Two phases with opposite bottlenecks
Prefill computes the keys and values for the whole prompt at once, so it is a large matrix multiply and the hardware runs near its peak.
Decode produces one token per pass, so every weight in the model is read from memory to serve a single token.
That is the whole story of serving cost. Prefill is compute-bound, decode is memory-bound, and an optimisation that helps one usually does nothing for the other.
Why decoding is bandwidth, not maths
A 7-billion-parameter model in 16-bit weights reads about 14 GB per token. On an accelerator with 2 TB per second of bandwidth, that is roughly 7 ms, or 140 tokens per second.
The arithmetic in that step would take well under a millisecond. The chip spends most of its time waiting for weights.
Batching is therefore free throughput.
The weights are read once and serve every sequence in the batch, which is why a server's tokens per second rises almost linearly with batch size until the cache runs out of room.
The two numbers users feel
Time to first token is set by prefill, so it grows with prompt length. Time per output token is set by decode and is roughly flat.
A long prompt with a short answer is a prefill problem. A short prompt with a long answer is a decode problem, and they are fixed by different things.
Streaming exists because that first term can be hidden behind the rest, and a user reads more slowly than the model writes.
One request, in order
- Tokenise the prompt.
- Prefill: one forward pass over all prompt tokens, filling the KV cache.
- Sample the first token from the final position's logits.
- Decode: one pass per token, appending each new key and value to the cache.
- Stop at an end token, a stop sequence, or the length limit, then free the cache.
Where the memory goes
- : layers, : heads, : sequence length, : batch.
The cache grows with every token and every concurrent request, and it is usually what limits batch size rather than the weights.
Sharing keys and values across query heads cuts that memory several-fold, which is why nearly every recent model uses it.
Quantising the weights to 8 or 4 bits attacks the bandwidth term directly, and it speeds up decode roughly in proportion.
That is the clearest example of why the bottleneck is worth knowing before optimising.