Skip to content
nonconvexcard

KV Cache, Batching and Little's Law

The memory equation that decides how many sequences fit, and why static batching wastes a logarithmically growing fraction of the GPU.

LLM OpsAdvanced⏱ 1 hour13 min readkv cachebatchinglittle's lawgqapaged attention
4 problems →

The memory equation

PropositionKV cache size

For a model with LL layers, key/value width dkvd_{kv} and bb bytes per stored element, the cache holds

MKV=2 L dkv bbytes per token per sequence,M_{\mathrm{KV}} = 2\,L\,d_{kv}\,b \quad \text{bytes per token per sequence},

so a batch of BB sequences of length SS requires 2BSLdkvb2BSLd_{kv}b bytes.

Assumptions

  • One key vector and one value vector are stored per layer per token — hence the leading 2.
  • dkv=nkv⋅dhd_{kv} = n_{kv} \cdot d_h, where nkvn_{kv} is the number of key/value heads and dhd_h the head dimension. Multi-head attention has nkv=nheadsn_{kv} = n_{\text{heads}} and so dkv=dd_{kv} = d; grouped-query attention shrinks nkvn_{kv}; multi-query attention takes nkv=1n_{kv} = 1.
  • No cross-sequence sharing. Prefix sharing changes this and is discussed below.
CorollaryMaximum concurrent sequences

With total device memory MM, weights MWM_W and overhead MOM_O, the number of concurrent sequences at context length SS is bounded by

Bmax⁡=⌊M−MW−MO2SLdkvb⌋.B_{\max} = \left\lfloor \frac{M - M_W - M_O}{2SLd_{kv}b} \right\rfloor .

Throughput and concurrency

TheoremLittle's law

For a system in which requests arrive, spend time inside, and depart, let λ\lambda be the long-run arrival rate, WW the long-run mean time a request spends in the system, and Lˉ\bar L the long-run mean number of requests in the system. If these limits exist and are finite, then

Lˉ=λW.\bar L = \lambda W .

Assumptions

Stationarity and finiteness of the three limits. No assumption on the arrival process, the service-time distribution, the number of servers, or the scheduling discipline. This is what makes the law usable: it holds for a system as messy as an LLM server.

Key idea

For a server, read Little's law as

B⏟mean concurrency=λ⏟requests/s×W⏟mean latency.\underbrace{B}_{\text{mean concurrency}} = \underbrace{\lambda}_{\text{requests/s}} \times \underbrace{W}_{\text{mean latency}}.

Concurrency is not a free parameter you tune independently of latency and throughput — fixing any two fixes the third. Since BB is capped by memory, so is the product λW\lambda W: you may serve many slow requests or few fast ones, and the trade is arithmetic, not engineering skill.

Why static batching wastes the machine

Static batching groups BB requests, runs them together, and returns the batch when all have finished. Since sequences stop at different lengths, the short ones keep occupying a slot — and consuming decode steps — long after they are done.

PropositionStatic batching utilisation decays like 1/log B

Let output lengths S1,…,SBS_1,\dots,S_B be i.i.d. exponential with mean μ\mu. Define utilisation as the expected fraction of computed token-slots that carry useful work,

UB=E[∑iSi]B⋅E[max⁡iSi].U_B = \frac{\E\big[\sum_i S_i\big]}{B \cdot \E\big[\max_i S_i\big]} .

Then

UB=1HB,HB=∑k=1B1k∼ln⁡B.U_B = \frac{1}{H_B}, \qquad H_B = \sum_{k=1}^{B}\frac{1}{k} \sim \ln B .

At B=8B = 8 this is U≈0.37U \approx 0.37; at B=32B = 32, U≈0.25U \approx 0.25; at B=128B = 128, U≈0.19U \approx 0.19. Utilisation gets worse as you batch harder — the opposite of what batching is supposed to buy.

Key idea

Continuous (in-flight) batching removes this loss by construction: a finished sequence is evicted and a queued one admitted at the next step, so slots never idle. The gain is not an optimisation of a constant factor — it is the removal of an Θ(log⁡B)\Theta(\log B) penalty that grows precisely as you scale up.

What this does not say

The exponential assumption is doing real work. It is a reasonable first model for "stop tokens arrive at a roughly constant hazard rate", and empirical length distributions are heavier-tailed than exponential, which makes the gap worse, not better. But the exact constant 1/HB1/H_B is a property of the exponential model, not a measured quantity. The qualitative claim — utilisation decays with BB under any non-degenerate length distribution — follows from E[max⁡]>E[mean]\E[\max] > \E[\text{mean}] and needs no distributional assumption.

Paging the cache

Allocating a contiguous buffer sized for the maximum possible context wastes everything between the actual length and that maximum. Block allocation fixes this.

PropositionBlock paging bounds internal fragmentation

If the cache is allocated in blocks holding kk tokens each, then a sequence of length SS wastes

w(S)=k⌈Sk⌉−S < ktoken-slots,w(S) = k\left\lceil \frac{S}{k} \right\rceil - S \ <\ k \quad\text{token-slots},

independent of SS and of any maximum context length.

So total waste across BB sequences is under BkBk slots regardless of context length, versus ∑i(Smax⁡−Si)\sum_i (S_{\max} - S_i) for contiguous preallocation — a quantity that grows with the declared maximum rather than the used length. Choosing kk trades fragmentation (small kk) against per-block indirection overhead in the attention kernel (large kk); values in the tens are typical.

References

These works are cited as sources to read, not reproduced. All exposition, examples and problems on this site are written independently; where an argument is standard, the citation points to a canonical treatment.

Results stated on this page

  • PropositionKV cache sizeproof includedThe cache costs 2·L·d_kv·b bytes per token per sequence, linear in context length and independent of batch-wide sharing.
  • CorollaryMaximum concurrent sequencesproof includedAvailable memory after weights, divided by per-sequence cache, bounds the batch size — usually well below the batch needed to be compute-bound.
  • TheoremLittle's lawproof includedIn any stable queueing system the mean number in system equals arrival rate times mean time in system, with no distributional assumptions.
  • PropositionStatic batching utilisation decays like 1/log Bproof includedWith exponentially distributed output lengths, a static batch of size B wastes a fraction 1 − 1/H_B of its decode steps.
  • PropositionBlock paging bounds internal fragmentationproof includedAllocating the cache in blocks of k tokens wastes fewer than k tokens per sequence, independent of context length.

Problems (4)

All problems