howtospark

Concepts

docs/concepts.md

A running glossary of the ideas behind the benchmarks — what each number means, and the levers (format, method, engine, architecture) that move it.

The metrics

What a benchmark row measures.

TermMeaningBound by
Prefill (tok/s)How fast the prompt is ingested before any outputCompute (FLOPs)
Decode (tok/s)Generation speed once tokens are flowingMemory bandwidth
TTFTTime to first token ≈ promptTokens ÷ prefillTpsPrefill
ITLGap between streamed tokens = 1000 ÷ decodeTpsDecode
Total throughputSum of all streams' tok/s under concurrencyBatching efficiency

On the Spark: decode is your ceiling. With only 273 GB/s of memory bandwidth, generation speed — not compute — is what limits real single-user use. Prefill is comparatively cheap, so at batch = 1 you're almost always watching decode tok/s.

Quantization formats

How shrunk weights are stored — determines bytes/token and which compute path exists.

FormatWhat it isRuns on
Q4_K_M, Q8_0GGUF block formats; llama.cpp's native quantsllama.cpp family
GPTQ-Int4 / Int44-bit integers + group scales, safetensorsvLLM, SGLang
MXFP4Open-standard 4-bit float, blocks of 32, coarse scalesBoth (as plain data)
NVFP4NVIDIA 4-bit float, blocks of 16, FP8 scales — native Blackwell tensor-core typevLLM, TRT-LLM
FP88-bit float, native on Hopper/BlackwellvLLM, TRT-LLM
BF16Full training precision, no quantizationEverything

On the Spark: go 4-bit. Because decode speed is set by bytes moved over the bus, a 4-bit model generates roughly 4× faster than BF16 and frees memory for context. NVFP4 is Blackwell's native tensor-core format (the fastest path); MXFP4 is the portable fallback that runs anywhere.

Weight vs activation precision

Model names like NVFP4-W4A16 tell you two precisions — W is the stored weights, A is the activations (the data being multiplied).

SchemeWeightsActivationsWhat it buys
W4A164-bit16-bit (BF16/FP16)Less memory + less bandwidth; math still runs at 16-bit
W4A44-bit4-bitThe above plus faster compute (uses the FP4 tensor cores)
W8A88-bit8-bitMilder compression, high quality; common FP8 serving setup

On the Spark: W4A16 is the sweet spot. It quarters the bytes moved per token — the thing that actually caps decode — while keeping activations at 16-bit for quality. W4A4 additionally speeds up prefill (4-bit tensor-core matmul), but quantizing activations hurts accuracy and needs calibration, so it only pays off for long-prompt or serving workloads.

Quantization methods

How values are chosen — determines quality, not speed.

MethodEffortWho does it
Plain roundingMinutes, no dataAnyone (most GGUFs)
GPTQ / AWQ / imatrixHours + calibration text; compensates rounding errorAnyone (community repos)
QATContinued training with quantization simulatedVendors only (e.g. Google's Gemma QAT)

On the Spark: since you're running 4-bit to stay under the bandwidth ceiling, claw back the lost accuracy for free — a calibrated quant (GPTQ / AWQ / imatrix) or a QAT release costs the same tok/s as plain rounding but generates noticeably better output.

The two stacks

Format determines engine family.

GGUF worldsafetensors world
Enginesllama.cpp, ollama, LM StudiovLLM, SGLang, TensorRT-LLM
Wins atDecode (mature quant kernels)Prefill/TTFT (vendor GEMM kernels, batching)
AudienceLocal/enthusiastServer/production

On the Spark: for single-user work the GGUF stack (ollama / llama.cpp) is the pragmatic default — simplest setup and strong decode. Reach for vLLM / TensorRT-LLM when you want NVFP4's native Blackwell path or are serving several requests at once.

Architecture & hardware

TermMeaning
DenseEvery parameter used for every token (27B → reads all 27B)
MoE / A3BMixture-of-Experts; "A3B" = ~3B active per token — decode speed follows active, not total
MTPMulti-token prediction — extra head enabling speculative decoding (our next big experiment)
Unified memoryCPU+GPU share one 128 GB pool @ 273 GB/s — decode ceiling = 273 ÷ active-weight GB

On the Spark: this lever dominates the others. Decode ceiling = 273 GB/s ÷ active-weight GB, so a dense 27B (reads all 27B every token) crawls while an MoE like A3B moves only ~3B and flies. And the 128 GB unified pool fits models a consumer GPU can't — pick architecture first, everything else second.