Prefill-Decode Scheduling and Disaggregation
Prefill and decode are two completely different workloads sharing one GPU. This page animates why they fight when co-located, how chunked prefill tames the interference, and how prefill-decode disaggregation splits them onto separate worker pools — shipping the KV cache between them.
Two phases, two bottlenecks
step-throughPrefill is compute-bound — one big parallel pass that saturates the math units. Decode is memory-bandwidth-bound — one token at a time, dominated by re-reading weights and the KV cache.
For a single request, prefill must finish before decode can begin. But across many requests a scheduler is free to choose the order. Prioritizing prefill or mixing prefill and decode in one batch raises throughput — at the cost of latency, because the in-flight decodes get slowed or stalled. The next figure shows that collision, and the fix.
The interference problem → chunked prefills
step-throughIn a shared continuous batch a long prefill hogs an iteration and stalls the running decodes, spiking inter-token latency (TBT). Chunked prefill (Sarathi) splits that prefill into smaller pieces interleaved with decode steps, bounding the delay.
Prefill-decode disaggregation: the KV handoff
step-throughDistServe goes further: run prefill and decode on separate worker pools. A prefill pool computes the prompt's KV cache, ships it over the interconnect to a decode pool, which streams out tokens. No more interference, and each pool can use its own hardware and parallelism.
Most systems co-locate the two phases so that one copy of the model weights and the KV cache can be reused in precious HBM. Disaggregation flips that: it replicates the weights across pools and moves the KV cache instead. That sounds expensive, but moving a request's KV — within a node or over a low-latency interconnect — is far faster than prefill or decode, so request latency barely moves (DistServe reports ~0.1% impact, p95 < 30 ms). DistServe pulls the KV from the prefill node's memory; Splitwise overlaps transfer with prefill by shipping each layer's KV as it's computed.
The tradeoff: isolation & scaling vs. KV bandwidth
auto-playEach pool scales independently to match demand, and can sit on the hardware best suited to it (decode = lots of memory, little compute). The cost is a steady stream of KV cache crossing the interconnect between them.
Disaggregation buys clean isolation, simpler scheduling (no prefill-vs-decode prioritization to balance), better tail latency, and the freedom to scale and place each pool independently — at the price of replicated weights and KV cache moving over the network. It is one of several promising disaggregation targets; even attention vs. the feed-forward network have different enough profiles to be split in future.