04.02 · Concept · Free
Static Batching
Describe request-level batching and name its two costs: padding to the longest sequence, and head-of-line blocking where every finished request waits for the slowest one.
Curated for this lesson
The Batch
Static Batching
The speaker says that "usually when a batch of requests came into the GPU I had to wait till the longest one finished and everybody had to sort of suffer for whoever asked the longest question," then contrasts this with iteration-level in-flight batching.
Static batching groups a fixed cohort of requests and advances them together, which improves regular GPU execution but couples every request to the largest shapes in the group. Its main costs are padded prefill work up to the longest prompt and decode head-of-line blocking until the slowest completion finishes.
What this lesson answers
- what is static batching in LLM serving
- why does static batching waste GPU work
- static batching head of line blocking explained
Notes
Static request-level batching means the server forms a fixed set of prompts, runs them through prefill together, and then advances the whole set through decode in lockstep until all requests in the set are complete. For a transformer using a dense attention kernel, the batched tensor is normally rectangular, so each prompt is padded to and the prefill attention work scales like rather than if masking does not avoid the padded rows efficiently; even when FlashAttention avoids materializing the full attention matrix, the rectangular batch still drives scheduling and memory traffic around the maximum sequence length. The useful-token fraction is , and the padding waste is . During decode, static batching also imposes a request-level barrier: if request finishes after generated tokens, its result is not returned or the batch slot not reused until , creating head-of-line blocking of decode steps across completed requests.
On an 80GB H100 with about TB/s HBM bandwidth, take a 70B FP16 model whose weights are roughly GB, so tensor parallel over two H100s leaves each GPU streaming about GB of weights per decode step. In the memory-bound decode regime, a crude roofline bound per GPU is batch-steps/s; with batch , that is at most token/s aggregate if KV reads and kernel overheads were free. Now suppose prompts have lengths . Static padding gives prompt token slots, while real tokens are , so and of the rectangular prefill slots are padding. If their output lengths are , static decode runs request-token steps but only are useful; slot-steps are pure head-of-line blocking.
The two costs show up differently in traces. Padding is paid mostly in prefill, where a short prompt beside a very long prompt inherits the launch geometry and masks of the long prompt; this is why production engines moved toward length bucketing even before full continuous batching. Head-of-line blocking is paid in decode, where generation is inherently one token at a time per live sequence: a request that emitted EOS at step can still occupy scheduler accounting, output buffering, and sometimes a KV-cache allocation until the request at step completes. Static batching was attractive in early GPT serving stacks because it maximized GEMM dimensions and made CUDA graph capture easy: the batch shape is known, the KV cache layout is simple, and there is no per-step admission control. But the mechanism is hostile to the actual distribution of chat traffic, where prompts and sampled completions are heavy-tailed and stop sequences, tool calls, and max-token limits produce highly variable .
This optimization stops working when variance in either or dominates the throughput gain from larger matrix multiplications. A concrete rule of thumb is that if the useful-token fraction falls below the speedup you obtained by moving from smaller to larger GEMMs, static prefill batching is already net negative. For example, if batching eight prompts makes prefill kernels faster than processing them separately but padding leaves , the effective speedup is only , a slowdown. In decode, the same logic applies to occupancy: if the mean completion is tokens but , a static batch keeps slots alive for the useful decode duration. Static batching is also poor for latency SLOs under bursty arrivals: a short request that joins a batch with one long completion sees its time-to-final-token coupled to the long request, even though the model could have freed the slot after EOS.
Modern LLM servers are largely reactions against these two static-batch costs. vLLM introduced PagedAttention in “Efficient Memory Management for Large Language Model Serving with PagedAttention” and implements continuous batching by admitting new requests into freed decode slots while representing KV cache as pageable blocks. SGLang’s runtime, described with RadixAttention and its serving system releases, combines continuous batching with prefix-cache-aware scheduling for agentic workloads. TensorRT-LLM added in-flight batching in NVIDIA’s release notes and examples, allowing requests to enter and leave an executing batch without waiting for a global batch boundary. NVIDIA Dynamo, announced as an inference serving framework for disaggregated and dynamic LLM serving, and llm-d, the Kubernetes-native LLM serving project, both assume dynamic admission rather than a static rectangular batch as the unit of work. FlashAttention, from Dao et al., reduces attention memory traffic but does not by itself remove request-level head-of-line blocking. EAGLE, the speculative decoding method, attacks decode-step count by proposing tokens, orthogonal to whether the serving scheduler is static or continuous.
The engineer’s mental model should therefore be precise: static batching is not “batching” in the abstract, but a fixed cohort contract. Its benefit is better accelerator utilization from larger, more regular kernels and fewer launches; its costs are exactly padding to the longest sequence in prefill and head-of-line blocking until the slowest request completes in decode. It is still defensible for homogeneous offline jobs, benchmark harnesses with equal prompt and output lengths, or embedding-style transformer passes where every item has the same shape. It is usually the wrong default for interactive LLM serving with mixed prompt lengths and stochastic generation. In that setting, the successor mechanisms preserve the useful part of batching, namely shared GPU execution, while breaking the fixed-cohort barrier that makes completed requests wait for the slowest sequence. Those mechanisms are vLLM’s PagedAttention scheduler, TensorRT-LLM in-flight batching, SGLang’s prefix-aware runtime, and related Dynamo or llm-d orchestration.
Common questions
- What is static batching in model serving?
- Static batching means the server forms a fixed group of requests and runs that group as one unit. The prompts are processed together, then generation proceeds in lockstep for every live request in the group. The batch membership does not change while it runs, so short requests remain tied to long ones.
- Why does padding hurt static batching?
- Transformer batches usually need a rectangular shape, so shorter prompts are padded to match the longest prompt in the group. Even with efficient attention kernels, the maximum sequence length still affects scheduling, memory traffic and kernel shape. If prompt lengths vary widely, much of prefill can be spent moving through padded slots rather than useful tokens.
- What is head-of-line blocking in static decode?
- Head-of-line blocking occurs when a request finishes generation but cannot fully leave the static batch until the slowest request is done. Its result, slot accounting, buffering or cache allocation may remain tied to the batch. This raises latency for short completions and wastes decode capacity that could have admitted new work.
Short definition: what is Static Batching?
