Repository navigation
[Perf][DSv4.1] Run decoder replay layers in CUDA graphs and trim in PIECEWISE graphs - #59532
Merged
ivanium merged 10 commits intoOct 6, 2026
Merged
Conversation
…IECEWISE graphs Run the decoder-side SWA bounded replay layers on the replay batch in breakable PIECEWISE graphs of their own, captured by a CudaGraphManager owned by DeepseekV41ModelState. PIECEWISE model graphs above VLLM_DSV41_DECODER_REPLAY_TRIM_THRESHOLD tokens (1024 by default) break out to those layers, so they trim too instead of only eager steps. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
Juntian777
force-pushed
the
feat/dsv41-replay-cudagraph
branch
from
October 1, 2026 04:19
1fa8c15 to
c834870
Compare
Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
…tokens The replay batch builds attention metadata only for the groups the replay layers read, skipping the kv sources' compressor and their other compressed-KV and indexer groups (about 0.55 ms of CPU per trimming step). PIECEWISE graphs of at least 768 padded tokens now trim: the 384 and 576 graphs lost ~3 ms per mixed decode step to the replay overhead, while 768 and 1020 gained 18-25%. Trim the tests to the regression checks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
Juntian777
force-pushed
the
feat/dsv41-replay-cudagraph
branch
from
October 1, 2026 07:57
556b658 to
c7220f0
Compare
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
This was referenced Oct 2, 2026
… bound; clarify replay batch naming Add compilation_config.cudagraph_decoder_replay (default on) to turn the replay graphs and PIECEWISE trimming off, and reject a decoder_replay_trim_threshold at or below the replay window, where no graph has anything to trim. Keep the threshold in the model state only: the replay layers break out of a PIECEWISE graph whenever a replay batch is set, which the model state does at the threshold or above. Build the replay batch's DP metadata once, after its padding is known. Rename replays/trims to force_replay_batch/needs_replay_batch, replay_graphs to replay_cudagraphs, and tighten the comments. Trim the tests to the regression checks. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
Juntian777
marked this pull request as ready for review
October 2, 2026 22:33
Juntian777
requested review from
AndreasKaratzas,
DarkLight1337,
WoosukKwon,
mgoin,
njhill,
robertgshaw2-redhat,
yewentao256,
youkaichao and
ywang96
as code owners
October 2, 2026 22:33
A replay batch that dispatches a replay graph holds at least `window` rows: eager steps replay only when a prefill trims to its last `window` rows, and PIECEWISE steps at the trim threshold hold more than `window` tokens. Sizes below the window were never replayed, so start there and step by the window, widening to 1/8 of the power-of-two interval past 16 * window. With the GB200 default bound of 1024 this captures 8 replay graphs instead of 64. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Juntian Liu <Juntianl777@gmail.com>
Contributor
Author
|
/ci run |
|
✅ Triggered Buildkite CI #92990 for commit |
Contributor
Author
|
/ci retry |
|
✅ Queued 1 failed job(s) for retry in Buildkite CI #92990. |
gcanlin
added a commit
to gcanlin/vllm
that referenced
this pull request
Oct 7, 2026
prepare_inputs_to_capture handed CUDAGraphMode.NONE to ModelState.prepare_attn for every capture, while PIECEWISE steps at runtime hand PIECEWISE. A model state that prepares what the graph runs by its mode then captured something else: DeepSeek-V4.1 builds the decoder replay batch for PIECEWISE graphs at the trim threshold or above (vllm-project#59532), so its graphs were captured without the replay break and ran the replay layers on the whole batch, though every step still prepared a replay batch. PIECEWISE captures now pass PIECEWISE. The other model states branch on FULL only, so they build the same metadata as before. DSV4.1-Flash DEP4 on B200, CUDA graphs up to 8192 tokens: 8k-token prefills 142.7k -> 236.9k total tok/s, 32k in / 256 out 772 -> 1,281 output tok/s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Canlin <canlinguosdu@gmail.com>
6 tasks
This was referenced Oct 10, 2026
This was referenced Oct 13, 2026
wangyicong52
pushed a commit
to bytedance-iaas/vllm
that referenced
this pull request
Oct 15, 2026
…IECEWISE graphs (vllm-project#59532) Signed-off-by: Juntian Liu <Juntianl777@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> (cherry picked from commit eb2901b)
michael-gpu
pushed a commit
to practical-inference/vllm-ampere-extended
that referenced
this pull request
Oct 20, 2026
…IECEWISE graphs (vllm-project#59532) Signed-off-by: Juntian Liu <Juntianl777@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
4 of 5 tasks
reputationly
added a commit
to reputationly/vllm-backport
that referenced
this pull request
Oct 21, 2026
上游来源:vllm-project/vllm#59532 (eb2901b735),适配点: - DecoderReplayLayers 换 ReplayBatch 语义,新增 graph break 与 trim_threshold; - 新增 decoder_replay_cudagraph.py(按 replay batch padded size 的可断图); - CompilationConfig 增加 cudagraph_decoder_replay / decoder_replay_cudagraph_capture_sizes / decoder_replay_trim_threshold; - 补 forward_context.in_piecewise_cudagraph(本仓缺失); - ModelState 新增 capture_inner_cudagraphs 钩子,model_runner 在 capture 后调用; - model_state 按上游整文件合入,保留本仓 InputBatch 无 fast_prefill、 以及 model_config.enable_return_routed_experts 的适配; - 上游两个测试文件同步更新(12 passed)。 Co-authored-by: DSH Agent <dsh-agent@local> Signed-off-by: DSH Agent <dsh-agent@local> Signed-off-by: reputationly <197039020@qq.com>
reputationly
added a commit
to reputationly/vllm-backport
that referenced
this pull request
Oct 21, 2026
上游来源:vllm-project/vllm#59532 (eb2901b735) 的配套测试改动。 Co-authored-by: DSH Agent <dsh-agent@local> Signed-off-by: DSH Agent <dsh-agent@local> Signed-off-by: reputationly <197039020@qq.com>
6 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Run the decoder-side SWA bounded replay layers (#58132) in CUDA graphs of their own, and trim them in PIECEWISE graph steps too. #58132 trims layers 21-39 to each prefill's last 128 tokens only on eager steps (above the model graph's capture range) and runs them eagerly there; those steps are often launch-bound (#58132 measured ~175 ms of kernel launches with the GPU waiting on a single 4K-8K prefill), and with a large
max_cudagraph_capture_sizenothing trims at all.DecoderReplayCudaGraphManager(nvidia/decoder_replay_cudagraph.py), aCudaGraphManagerowned byDeepseekV41ModelState, captures breakable PIECEWISE graphs of the replay layers, keyed by the replay batch's padded token count and reading the layer inputs from static buffers. Attention runs in their eager breaks: the replay batch mixes prefill tails and decodes, and the SWA and sparse MLA builders support uniform batches only.compilation_config.decoder_replay_trim_thresholdpadded tokens (768 by default) break out to the replay layers, which run on a replay batch (trimmed, or whole when nothing trims) and write their outputs to fixed buffers the graph's next segment reads. FULL graphs and smaller PIECEWISE ones keep the layers on the whole batch, as before._prepare_replay_batchpads the replay batch to the smallest graph that fits the largest DP rank's replay batch and sets it onDecoderReplayLayersas oneReplayBatch(rows, forward context, graph runner). A replay batch abovemax_cudagraph_capture_size, possible only in eager steps, stays eager.ModelState.capture_inner_cudagraphsis a new hook the runner calls after the model's capture; it is a no-op by default.compilation_config.cudagraph_decoder_replay=falseturns it off. Also off under LoRA, prompt embeddings or on a non-first PP rank. Off keeps [Model] Decoder-side SWA bounded replay for DeepSeek-V4.1 #58132's behavior.No open PR runs the replay layers in graphs. #56752 (closed) captured them nested inside the model graph's capture; this captures them on their own and has the model graph break out to them.
Benchmark
Prefill-only TTFT of DeepSeek-V4.1-Flash on GB200 at
f21ea3c947(the last commit only adds the switch and renames), default CUDA graph settings,max_num_batched_tokens=16384, prefix caching off,max_tokens=1. With the default capture range every 1K-128K prefill step is eager, so this measures the eager path, not PIECEWISE trimming. Median of 3 runs in ms; c1 is one request at a time, c8 is 8 concurrent. Off is--no-swa-bounded-replay; parent is df8fd42 (main with #58132) with bounded replay on. Each topology ran all three on one node.TP4 (repeats within ±2%; this PR's 1K c1 runs were 102/103/131 ms):
DEP2 (one fixed prompt per length; each ratio compares runs on the same GPU pair, since the two pairs of a node differ by 3-10%; c1 repeats within ±3%; c8 below 128K is omitted, it varies ±10-30% with how the two API servers split the 8 requests across DP ranks):
Why TP4 gains at long prompts and DEP2 does not
A profile of one 128K prefill shows the trimmed layers need only a few ms of GPU per chunk, but on TP4 their eager launches take several times longer and layers 0-20 do not hide them, so the GPU sits idle through most of layers 21-39; in graphs that idle time is gone. A DEP2 rank runs layers 0-20 on the whole chunk without TP splitting, so the CPU is far ahead of the GPU and the eager launches were already hidden; this PR only helps DEP2 where the step is short (1K-4K).
🤖 Generated with Claude Code