AI Infra Interviews logo
LLM Inference & Serving / 01
easy★ EssentialNewOpenAIAnthropicBaseten

Why do prefill and decode behave so differently, and why does that matter for the hardware you serve on?

One forward pass reads every weight. Whether that read is the bottleneck depends on how many tokens ride along with it, and the answer is different for the two halves of a request.

Updated Sep 2026 · Grounded in real AI infrastructure interview loops and written to a senior-engineer editorial bar, with every number worked and every diagram hand-built.

TL;DR: Prefill processes the whole prompt in one pass, so thousands of tokens share each weight read and the GPU is compute-bound; it sets time to first token. Decode produces one token per sequence per step, so a small batch reads 141 GB of weights to do almost no math and the GPU is bandwidth-bound; it sets time per output token. The ridge point of the accelerator, about 295 FLOP per byte on an H100, is the line between them, and batch size is what moves decode toward it.

How to approach it

Open by naming the two phases and the metric each one owns: prefill produces the first token, decode produces every token after it. Ask which model and which card the interviewer has in mind, because the argument needs a weight size and a bandwidth figure; if they leave it open, pick Llama 3.1 70B on H100 and say so. Then say you will compute the arithmetic intensity of each phase and compare it against the card's ridge point, since that single comparison decides which resource is the bottleneck. Close by connecting each phase to the SLO it controls.

A strong answer

A typical situation: a fleet is sized on one throughput number and then misses its TTFT target on long prompts and its TPOT target on short ones. The two halves of a request want opposite hardware, and one number cannot describe both.

A transformer forward pass reads every weight once per step regardless of how many tokens are in the step. The useful work per weight read is what separates the phases. The Prefill vs Decode split is the first thing to draw:

inputs (Llama 3.1 70B, bf16, one H100 SXM)
  weights W = 70.6e9 params × 2 B = 141.2 GB
  FLOPs per token per pass = 2 × params = 2 × 70.6e9 = 1.41e11 FLOP
  H100: 989 TFLOPS dense bf16, 3.35 TB/s HBM

ridge point = peak FLOPS ÷ bandwidth
            = 989e12 ÷ 3.35e12 ≈ 295 FLOP per byte

arithmetic intensity of a step = FLOPs ÷ bytes read
  prefill, 2,000-token prompt: (2,000 × 1.41e11) ÷ 141.2e9 ≈ 2,000 FLOP/B   (above 295: compute-bound)
  decode, batch 1:             (1 × 1.41e11) ÷ 141.2e9 = 1 FLOP/B          (far below 295: bandwidth-bound)
  decode, batch 64:            64 FLOP/B                                  (still bandwidth-bound)
sanity: intensity for bf16 decode equals the batch size, so decode only reaches the ridge near batch 295

That table is the whole mechanism. During prefill every token in the prompt multiplies against the same weight tile while it sits in registers, so the tensor cores are the limit and the phase scales with prompt length. During decode there is one new token per sequence, so the step is a pass over 141 GB of HBM to compute a handful of matrix-vector products.

The two phases therefore have different time formulas:

TTFT ≈ prompt tokens × 2 × params ÷ (GPUs × peak × MFU)
     = 2,000 × 1.41e11 ÷ (8 × 989e12 × 0.4)         (8 H100s, MFU 0.4 for prefill)
     = 2.82e14 ÷ 3.16e15 ≈ 89 ms

TPOT at batch B ≈ (W + B × KV per sequence) ÷ aggregate bandwidth
  batch 1:  141.2 GB ÷ (8 × 3.35 TB/s = 26.8 TB/s) ≈ 5.3 ms per token
  batch 64, 4k context (KV per seq = 328 KB × 4,096 ≈ 1.34 GB):
            (141.2 + 64 × 1.34) GB ÷ 26.8 TB/s = 227 GB ÷ 26.8 TB/s ≈ 8.5 ms per token
sanity: 64 users each get a token every 8.5 ms, so the fleet emits about 7,500 tokens/s;
        at batch 1 it emits 190 tokens/s from the same eight cards

The consequence for hardware is that the two phases want different things. Prefill wants FLOPS, and an H100 and an H200 are the same die, so they prefill at the same speed. Decode wants bytes per second and capacity: the H200's 4.8 TB/s against the H100's 3.35 TB/s cuts the batch-1 step from 5.3 ms to 3.7 ms without changing the compute at all, and its 141 GB lets more sequences ride on each weight read. A shop whose traffic is short prompts and long generations buys bandwidth. A shop doing document summarization with 30k-token prompts and 200-token answers buys FLOPS. That is why Disaggregated Prefill and Decode exists as a design at all: the phases are cheapest on different pools.

TOKENS PER WEIGHT READ prefill, 2,000 tokens one read serves 2,000 compute-bound decode, batch 64 one read serves 64 in between decode, batch 1 one read serves 1 bandwidth-bound Bar length is tokens per weight read, which is arithmetic intensity under another name. The two phases want opposite machines, which is why every shared-pool flag is a compromise.

The decision: serve on the higher-bandwidth part when decode dominates the token count. The reversal condition: when the prompt-to-output ratio climbs past roughly 20 to 1, because at that point prefill compute is most of the GPU-seconds.

What interviewers probe next

  • "Why does adding batch help decode but not prefill?" Because decode intensity equals the batch size in bf16, so every added sequence is free until the step reaches the ridge, while prefill is already above the ridge at a few hundred tokens and extra tokens cost proportional compute.
  • "What happens to decode at 32k context?" The KV read joins the weight read: 32,768 × 328 KB ≈ 10.7 GB per sequence, so a batch of 16 reads 172 GB of KV on top of 141 GB of weights, and the step time more than doubles.
  • "Does fp8 change which phase is bound?" It halves the bytes per weight, so decode intensity doubles per unit of batch and the ridge in batch terms stays near 295 on an H100 because fp8 peak also doubles; it mostly buys capacity and a faster step, not a change in regime.

Common mistakes

  • Saying "inference is memory-bound" without splitting the phases; a 20k-token prefill is as compute-bound as training.
  • Quoting sparse tensor-core peaks (1,979 bf16 TFLOPS "with sparsity") so the ridge point comes out at 590 and the batch math is wrong by two.
  • Treating TTFT as a queueing number and forgetting the prefill compute term, which is most of it for long prompts.
  • Assuming the H200 speeds up prefill.

Key takeaways

  • Intensity of bf16 decode equals batch size; the H100 ridge is about 295 FLOP/B, so decode is bandwidth-bound until the batch is in the hundreds.
  • Batch-1 decode of a 70B model on 8 H100s is about 5.3 ms per token, set by 141 GB over 26.8 TB/s.
  • TTFT scales with prompt tokens times 2 × params over available FLOPS; TPOT scales with bytes per step over bandwidth.
  • Bandwidth and capacity buy decode; FLOPS buy prefill; the prompt-to-output ratio decides which you are buying.
That one was free — and so are 10 answers per topic without an account. Signing in doubles that to 20, opens the Plus lessons in the courses, and remembers which topics you keep getting wrong.no card · Google sign-in · nothing to cancel
HOW DID IT GO?
0
READING SIGNED OUT

Signing in doubles your free answers, from 10 to 20 per topic, and the site starts remembering you: mastery per topic, bookmarks, and a next-focus recommendation. Free, no card.

Sign in free

The concepts behind this question

Ranked by how closely each one overlaps this question's topic, so the first card is the thing to read if the answer above moved too fast.

Foundational
🚀 Inference & Serving
Prefill vs DecodeAn LLM request runs in two phases with opposite hardware profiles: prefill reads the whole prompt in one compute-bound pass and decides time to first token, decode emits one token per forward pass and is bound by memory bandwidth. Every serving decision, from batch size to which GPU to buy to whether to split the two phases across machines, follows from that split.
Advanced
🚀 Inference & Serving🔒 Premium
Disaggregated Prefill and DecodePrefill is compute-bound and decode is memory-bound, so running both on the same GPUs means each phase interferes with the other and neither runs on the hardware it wants. Disaggregation puts them on separate pools and ships the KV cache from prefill nodes to decode nodes over the fabric. It lets TTFT and TPOT scale independently and puts high-bandwidth parts where they pay, at the price of a KV transfer per request and a control plane. It pays at scale with long prompts; it does not pay for a small fleet.
Advanced
🧩 GPU & Accelerator Architecture🔒 Premium
Memory-Bound vs Compute-Bound KernelsEvery kernel is limited by one of two walls: how fast bytes arrive from HBM, or how fast the tensor cores can multiply. Which wall applies is decided by arithmetic intensity against the ridge point, and the two regimes need opposite fixes. Decode, LayerNorm and softmax are memory-bound; prefill GEMMs are compute-bound; the interview question is which one you are looking at and what you would do about it.
Core
🧮 Napkin Math & CapacitySign in
Arithmetic Intensity by OperationThe roofline says a kernel's ceiling is set by its FLOPs per byte against the hardware's ridge point. This page does the FLOPs-per-byte arithmetic for the operations an LLM actually runs (decode at several batch sizes, prefill, the attention score matmul with and without FlashAttention, LayerNorm, an embedding lookup) so the reader can place any of them on the roofline from first principles and say which lever moves it. The numbers explain why a serving fleet's GPUs report 30% utilization while fully loaded.
UP NEXT ON YOUR JOURNEY
FEDITOR'S NOTE

The interviewer is scoring whether you can place both phases on a roofline with numbers, and whether you know which latency metric each phase owns.

DISCUSSION · 0

No comments yet — be the first to share your approach.