Runbooks/ LLM Inference Runbook Track E · Running it in production Deep readQuick learn
  1. 00 Start
  2. /
  3. 01 Tokens
  4. 02 Anatomy
  5. 03 Journey
  6. /
  7. 04 Hardware
  8. 05 Phases
  9. 06 KV cache
  10. /
  11. 07 Attention
  12. 08 Position
  13. 09 Precision
  14. 10 Cache ops
  15. /
  16. 11 Many GPUs
  17. 12 Engines
  18. 13 Decode loop
  19. /
  20. 14 Planning
  21. 15 Production
Document 14 · Quick learn Little’s Law · Two paths · Name the binding constraint

From a forecastto a purchase order

From a traffic forecast to a number you can put in a purchase order — with the binding constraint named, the headroom justified, and the cost compared honestly.

“How many chefs? Nobody can say until somebody says how many covers, and how long a diner will wait.”
600 in flight
40 req/s × 15 s, by Little’s Law
4 + 1 GPUs
the load, then redundancy
$0.11 / M tokens
at 40% utilisation, all kinds
2.5×
20% → 50% utilisation, on cost
The question, reframedand why it is not the one you were asked

“How many GPUs do we need?” has no answer until two other numbers exist. The same traffic needs one GPU or ten depending on what you promised; the same promise needs one or ten depending on the traffic shape. The first move is not arithmetic.

The reframing, said once, at the start

“I can give you a number today. To make it a number you can hold me to, I need two things: the peak request rate with the prompt and output length distributions, and what we are promising for time-to-first-token and streaming speed at p95. Give me a forecast and I will give you a fleet size, the binding constraint, and what would change it.”

Three things at once: it gets the inputs, it makes clear the answer is derived rather than asserted, and it puts ownership of the forecast where it belongs — so when traffic turns out different, it is a forecast conversation rather than an engineering one
The analogy — sizing a restaurant kitchen

“How many chefs?” is unanswerable until somebody says how many covers at the busiest hour and how long a diner will tolerate waiting. Promise food in ten minutes and you need far more staff than if twenty-five is acceptable — because a slower promise means each table is occupied longer, which means more tables occupied at once, which means more of everything.

That last chain is Little’s Law, and it is the step people skip
The seven stepstwo paths, computed separately, so you can say which binds
1
The forecastpeak requests/second and the distribution of prompt and output lengths — p50, p95, p99, never the mean
40 req/s
2
The promiseTTFT and inter-token targets at a stated percentile. Without these the question has no answer
<1 s / <50 ms
3
ConcurrencyLittle’s Law: in flight = arrival rate × time in system
600
4
The memory path600 × 0.281 GiB = 168.5 GiB ÷ 53.73 GiB per GPU
4 GPUs
5
The compute path(prefill 1,369 + decode 193) TFLOP/s ÷ 396 per GPU at 40% MFU
4 GPUs
6
Take the larger, add headroomround to something buyable: 4 for the load, +1 for N+1
5 GPUs
7
The billand an honest comparison against the managed-API price for the same traffic
$11k / mo
Worked40 req/s × 15.0 s = 600 in flight · 600 × 0.281 = 168.5 GiB · 168.5 ÷ 53.73 = 4 · +1 = 5 · buy a node of 8and both constraints bind about equally here — say so
The counter-intuitive consequence of Little’s Law

Time in system is dominated by output length divided by the inter-token target. So a looser latency promise makes the fleet bigger: at 20 tokens/second a 300-token answer occupies a slot for 15 seconds; at 10 tokens/second it occupies one for 30. Double the time in system, double the concurrency, double the cache.

This surprises people. It is cheaper in compute — you can batch harder — and more expensive in memory. A relaxed SLO moves the binding constraint rather than uniformly reducing cost
Two mistakes that make a plan wrong by a factor of two

Using the mean prompt length instead of the distribution. Prefill cost is superlinear in length, so a workload with p50 2,000 and p99 50,000 costs substantially more than its mean suggests.

Sizing memory against worst-case and compute against average, or vice versa.

Pick a convention and state it. This runbook sizes memory against the paged figure — typical conversation length — and covers the worst case with the redundancy headroom
Which constraint bindsthe fixes do not overlap, which is why it matters

Memory binds

Cache utilisation pinned near 100%, requests queueing for blocks. Preemption count rising confirms it.

  • Happens with: long outputs, high concurrency, long context
  • fp8 cache · lower context limit · quantised weights · fewer KV heads
  • More compute does nothing at all
Compute both.
Compare.
Then confirm
with two gauges.

Compute binds

The GPU is genuinely saturated while cache utilisation is comfortable.

  • Happens with: long prompts, short answers — RAG and classification shapes
  • Prefix reuse · shorter prompts · pruning tool schemas · a smaller model
  • An fp8 cache does nothing — you were not short of memory
Why naming it matters more than the GPU count

It tells you what to do next, and what not to bother doing. A capacity plan that does not name the binding constraint cannot be acted on.

And when both bind about equally — as they do on the reference stack — say that too: it means either could move first if the traffic shape shifts, and it tells you which measurements to watch
The billand the honest comparison
5 GPUs at $3/hr

× 730 hours.

~$11,000 / month, fixed
At 40% average load

Roughly 95 billion tokens a month.

~$0.11 per million tokens of all kinds
The same traffic on an API

At typical managed prices.

~$30,000 / month
At 10% average load

The same fixed cost, a quarter of the tokens.

The advantage disappears entirely
Why utilisation is usually the biggest lever

Every technique in this runbook raises tokens per hour against a fixed hourly cost. But a half-idle GPU costs exactly the same as a busy one, so raising average utilisation from 20% to 50% is a 2.5× improvement in cost per token — larger than quantisation, larger than prefix caching, larger than almost anything else.

Which means the highest-value capacity work is often not optimisation at all: consolidating traffic onto fewer fuller machines, scheduling batch work into the overnight trough, and being willing to queue rather than over-provision
The build-versus-buy answer that does not sound defensive

“At our current volume the API is cheaper once you count engineering time. Self-hosting starts winning at roughly X tokens a month at 40% utilisation, and here is the calculation. What it also buys is control over latency, data residency and model version pinning — and what it costs is an on-call rotation and a re-benchmarking exercise on every upgrade.”

“My recommendation is to stay on the API until we cross that volume or until one of those three controls becomes a hard requirement, and to revisit quarterly with the measured number.” A recommendation with a trigger gets acted on; one without gets re-argued every quarter
The capacity notesix sections, one page, one hour

The deliverable is not a number in a message. It is a one-page document that someone can disagree with precisely.

1 · The inputs, attributed

Peak rate, length distributions, latency targets — and who owns each one.

So a wrong forecast is a forecast problem rather than an engineering one
2 · The model and precision

Parameter count derived from the config, weight footprint, cache per token.

Three lines of arithmetic anyone can check
3 · The two constraints

Memory path and compute path, computed separately.

With which one binds stated explicitly
4 · The fleet

Load, plus redundancy, rounded to the purchasing unit.

As three separate numbers, not one
5 · The cost

Monthly infrastructure, dollars per million tokens, and the managed-API comparison.

For the same traffic, with its caveats named
6 · What would change it

The two or three sensitivities that matter, quantified.

“If p95 prompts reach 8k, compute binds and the fleet goes to 7”
Section 6 is the one that earns trust

Anyone can produce a number. Producing the number and the two conditions under which it is wrong is what makes it a plan rather than an estimate — and it is what stops the conversation being reopened from scratch every month.

It also protects you. When traffic turns out to be 8,000-token prompts rather than 2,000, the document already said what happens — so the discussion is “the forecast moved, here is the pre-agreed consequence” rather than “the capacity plan was wrong”
Answer it out loudthe ninety-second version, then five questions
“I cannot size a fleet without a traffic forecast and a latency promise, so I would get those first. Given them, it is two calculations done separately. Little’s Law gives concurrency — arrival rate times time in system, and time in system is output length over the inter-token target — so forty requests a second with fifteen-second responses is six hundred in flight. Multiply by cache per conversation and divide by the KV budget per card for the memory path. Separately, prefill plus decode demand divided by peak times MFU for the compute path. Take the larger, add N+1, round to the purchasing unit: four for the load, five with redundancy, and buy a node of eight. And I would say which constraint binds, because that is what tells you what to do next.”

Five questions, and the spine of each answer

Architect

We expect 40 requests a second. How many GPUs?

  • Two things first: length distributions and the latency promise. They change the answer by an order of magnitude
  • Say 2,000 in, 300 out, 20 tok/s: time in system 15 s → 600 in flight
  • Memory: 600 × 0.28 GiB = 168 GiB ÷ 53.7 = 4
  • Compute: 1,370 + 190 TFLOP/s ÷ 396 = 4
Four for the load, five with N+1, and buy a node of eight because that is the purchasing unit. Both constraints bind about equally — say that explicitly, because either could move first.
Architect

What is Little’s Law and why does it matter here?

  • In flight = arrival rate × time in system
  • The bridge between a forecast (a rate) and a memory requirement (how many are resident)
  • Time in system is dominated by output length ÷ the inter-token target — both product decisions
So fleet size is downstream of an SLO conversation, not a hardware one. And the counter-intuitive bit: a looser promise makes the memory fleet bigger. People expect a relaxed SLO to be uniformly cheaper; it is not.
Eng manager

Finance wants to know: self-host or API?

  • Give them the arithmetic and a trigger, not a preference
  • Five GPUs at $3/hr is ~$11k a month, fixed. At 40% load that is ~$0.11 per million tokens
  • The same traffic on a managed API is ~$30k — so on infrastructure alone, 2–3× cheaper
  • Name what that leaves out: engineering time, on-call, upgrades, idle overnight, cold-start risk
And it is extremely sensitive to utilisation — at 10% average load the advantage disappears entirely. So: a trigger, not a verdict, revisited quarterly with the measured number.
Architect

Which constraint binds, and how would you know?

  • Compute both, compare, then confirm in production with two gauges
  • Memory: cache utilisation pinned near 100%, requests queueing for blocks, preemption rising
  • Compute: the GPU genuinely saturated while cache utilisation is comfortable
  • The fixes do not overlap
Which is why you say which binds rather than just giving a count: it tells you what to do next and what not to bother doing. A plan that does not name it cannot be acted on.
Eng manager

How do you cut our inference bill by 30%?

  • Utilisation first, because it is usually the biggest lever and needs no model change — 20% → 50% is 2.5× on cost per token
  • Then the free levers: prefix caching, chunked prefill, a context limit set from measured p99
  • Then the cheap ones: an fp8 cache (2×), fp8 weights (+14% users)
  • Then the expensive ones: a smaller model, different hardware
And I would want the binding constraint named first, because half of that list does nothing if the other resource is the one that is short.
Fast answersthe seven that come up most

QDoes a looser SLO really make the fleet bigger?

In memory terms, yes. Time in system is output length over the inter-token target, so halving the target doubles the time each request occupies a slot, which doubles concurrency and the cache. It does buy compute headroom — so it moves the binding constraint rather than uniformly reducing cost.

QWhy not just autoscale?

Because cold start is minutes, not seconds — tens of gigabytes of weights have to be read and loaded. By the time new capacity is ready, the spike is over. You can autoscale slowly against sustained trends, but you cannot scale into a burst — which is why headroom is a design input rather than a failure of planning.

QShould the capacity plan assume prefix caching?

Only if you have measured the reusable fraction on real traffic. It is transformational on chat and agents and near-worthless on RAG, so assuming it is either a large saving or a large error. If you have not measured it, size without it and treat any hit rate as headroom.

QWhat utilisation should I plan for?

Whatever your traffic profile actually gives — for an interactive product usually 30–50% averaged over a month. That number goes directly into cost per token, and improving it is frequently a bigger lever than any optimisation in this runbook.

QHow often should capacity be reviewed?

Monthly against measurement, and immediately when any input changes — a new model, a prompt-length shift, a new SLO. The sensitivities section should make most reviews a two-minute check rather than a re-derivation.

QDo I size for peak or for average?

Peak for the fleet, because that is what must not breach the SLO. Average for the cost model, because that is what you actually serve. Using peak for cost overstates the bill and average for the fleet under-provisions — both are common, because people carry one number for two jobs.

QWhat is the single most common error in a capacity plan?

Stopping the memory ladder at the weights line. “A 70B in fp8 is 70 GB so it fits on an 80 GB card” is true and useless — it leaves about 3 GiB of cache, which is one user. Always finish to a concurrency number, and always say whether it is worst-case or paged.

“How many GPUs?” is not a question until a forecast and a promise exist. Then it is two calculations done separately — the memory path through Little’s Law, and the compute path through prefill and decode demand — and the answer is three numbers, not one: the load, the redundancy, and the purchasing unit. Name the binding constraint, because that is what tells the team what to do next. And remember the biggest lever is not in this runbook at all: a half-idle GPU costs exactly what a busy one does.

20% utilisation
50% — 2.5× cheaper per token
Where this goes next

Questions to ask them

What is the peak request rate, and what is the length distribution?

What are the TTFT and inter-token targets, at what percentile, and who set them?

Which constraint binds today — memory or compute? Does anyone know?

What is average utilisation over a month, not at peak?

What is the cost per million tokens, and has it been compared against an API?

Is there a written capacity note, and does it say what would change the answer?

← 13 · Decode loop Read the full chapter → 15 · Production →