Repository navigation
[Perf] dsa: Capture DSA prefill attention and the NextN draft prefill in the prefill CUDA graph - #46887
Open
mattteochen wants to merge 2 commits into
Open
[Perf] dsa: Capture DSA prefill attention and the NextN draft prefill in the prefill CUDA graph#46887mattteochen wants to merge 2 commits into
mattteochen wants to merge 2 commits into
Conversation
Contributor
Preview approval requiredThis pull request comes from a fork, so Mintlify won't build a preview until someone with write access approves commit |
… in the prefill CUDA graph Under the breakable prefill CUDA graph, every DSA layer's attention and the whole indexer run as eager graph breaks, and the NextN draft extend after each target prefill chunk runs eagerly (DeepseekModelNextN has no `layers`). For short extends the host work of those breaks dominates the prefill. - DSA prefill attention (k_b bmm, RoPE + FP8, KV write, TRT-LLM sparse MLA) is recorded in the graph, reading per-row lengths from a static buffer that init_forward_metadata refreshes; padded rows attend to the dummy slot 0. Buckets below the smallest one whose real rows all exceed SMs / 2 keep the eager break, so every prefill stays bitwise equal to it. HiCache load-backs are waited for in full before the forward; per-layer loaders (FlexKV, the external cache linker, radix cache plug-ins, host-pool retraction backup) keep the eager break, as do DCP, DP attention, prefill CP, hisparse, k-pool, TBO and page-sharded KV caches. - With it, the indexer's Q/K prep and index-K store are captured too; only logits + top-k stay a break. - DeepseekModelNextN exposes its decoder as a one-layer `layers` view (no DP attention, PP or prefill CP), so the draft extend replays the prefill graph; the DSA index-share seed is published from a graph break at replay, and multimodal batches stay eager. Switches (default on): SGLANG_ENABLE_DSA_PREFILL_ATTN_IN_CUDA_GRAPH, SGLANG_ENABLE_DSA_PREFILL_INDEXER_PREP_IN_CUDA_GRAPH, SGLANG_ENABLE_NEXTN_DRAFT_PREFILL_CUDA_GRAPH. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mattteochen
force-pushed
the
dsa-prefill-attn-cuda-graph
branch
from
November 4, 2026 17:41
0b11a0e to
a10852b
Compare
mattteochen
marked this pull request as ready for review
November 4, 2026 22:20
mattteochen
requested review from
1am9trash,
Fridge003,
Ying1123,
ch-wan,
fzyzcjy,
hnyls2002,
hubertlu-tw,
ispobock,
kkHuang-amd and
merrymercy
as code owners
November 4, 2026 22:20
mattteochen
requested review from
HaiShaw,
JustinTong0323,
Qiaolin-Yu,
YAMY1234,
hebiao064,
rainj-me,
sogalin,
wisclmy0611 and
zijiexia
as code owners
November 4, 2026 22:20
nvpohanh
reviewed
Nov 5, 2026
nvpohanh
left a comment
Collaborator
There was a problem hiding this comment.
[by Claude Code] This review is done by agents. Please feel free to disagree if they do not make sense.
4 of 5 tasks
…tion Address review: - Wait for every layer's HiCache load before the forward only when the extend replays a bucket whose DSA attention is captured; smaller extends keep the eager break, which waits per layer and keeps the load/compute overlap. - Shorten the forward_prefill_in_graph docstring and the comments on _PREFILL_GRAPH_MIN_ROWS, _wait_for_layerwise_kv_load and _layerwise_kv_load_configured. - Drop the redundant layer-split pool check from the indexer prep gate (the layer-split pool requires prefill CP, which the gate already excludes). - Detect the text-only NextN layer model with isinstance instead of getattr. - Share the all-selected top-k fill between the indexer and the prefill graph top-k break (Indexer._fill_all_selected_topk). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Motivation
With the breakable prefill CUDA graph, every DSA layer's sparse attention and indexer still run as eager graph breaks, and the NextN (MTP) draft extend that follows each prefill chunk runs eagerly. Short prefills and prefix-cache hits are then bound by host launch work rather than GPU time. This records the DSA prefill attention, the indexer's Q/K prep and the NextN draft extend inside the prefill graph, which cuts TTFT on GLM-5.2 NVFP4 (GB300) by up to 44% for short fresh prompts and by up to 37% for cached-prefix prefill under concurrency, with outputs bitwise equal to the eager breaks.
Modifications
One commit,
[Perf] dsa: Capture DSA prefill attention and the NextN draft prefill in the prefill CUDA graph:init_forward_metadatarefreshes; padded rows attend to the dummy slot. Buckets below the smallest one whose rows all exceed SMs / 2 (96 on GB300) keep the eager break, so every prefill stays bitwise equal to it.DeepseekModelNextNexposes its decoder as a one-layerlayersview (no DP attention, PP or prefill CP), so the draft extend replays the prefill graph. The DSA index-share seed is published from a graph break at replay; multimodal batches stay eager.kv_layers.layer(id).store_mla,kv_layers.read(id).key(), [Refactor] attention: Use typed KV views and shared layer routing #46990), like_forward_trtllm.test/registered/unit/layers/attention/test_dsa_prefill_cuda_graph.py,test/registered/unit/models/test_deepseek_nextn_draft_prefill_graph.py); a GB300 nightly e2e test (test/registered/e2e/models/test_dsa_glm52_nvfp4_prefill_graph.py) comparing captured vs eager servers bitwise, with and without HiCache load-back. Env var docs updated.Kill switches (default on):
SGLANG_ENABLE_DSA_PREFILL_ATTN_IN_CUDA_GRAPH,SGLANG_ENABLE_DSA_PREFILL_INDEXER_PREP_IN_CUDA_GRAPH,SGLANG_ENABLE_NEXTN_DRAFT_PREFILL_CUDA_GRAPH.Accuracy Tests
GSM8K on GB300 with GLM-5.2 NVFP4: full test set (1319 questions), 5-shot, greedy, real acceptance. Same harness as #46630 (few-shot
/generate, prompts and answer extraction ofsglang.test.few_shot_gsm8k, one question sent first so both arms read the same 5-shot prefix KV). Runs per arm: 2 orderings x 2 server instances.The run-to-run range per arm is 0.3-1.3 pp.
Speed Tests and Profiling
Setup: GB300, GLM-5.2 NVFP4, HiCache on, chunked prefill 8192, default prefill graph capture size. The 2026-10-26 SGLang nightly image (
lmsysorg/sglang:nightly-dev-cu13-20261026-8252e3af, SGLang8252e3af63) is the main arm; the other arm is this branch on top of it. TP4 is one tray (EAGLE 4/1/5, max 8 running requests); TP8 is two trays in one NVL72 rack (EAGLE 5/1/6, max 16).Gains come from fewer host-bound graph breaks: at concurrency 1 they are largest where the extend is short (fresh 512-1k; at TP8 also 32k + 1k). Under concurrency, shorter prefill steps cut the queueing of the other lanes.
Steady decode (fresh 1000 in / 512 out, median TPOT ms, main → PR):
64-token answers. TPOT is not a per-step measure here, and two effects show up in it:
Graph memory (rank 0): target prefill graph 4.04 → 3.61 GB (TP4) and 3.79 → 3.37 GB (TP8), plus 0.25 GB for the draft prefill graph; the KV pool size is unchanged.
Nov-4 re-check on
lmsysorg/sglang:nightly-cu134-20261104-27aedf7(Nov-4 SGLang nightly image, current main), this branch rebased onto it. TP4, one server instance per arm, real acceptance; the e2e testTestGLM52NVFP4DsaPrefillCudaGraphpasses (4 tests). Median TTFT ms, main → PR:Main is faster at concurrency 1 than on the Oct-26 image, so the concurrency-1 gains are smaller. GSM8K (1319, 5-shot, parallel 4): main 94.69% (accept length 3.757), PR 94.47% (3.762).
Reproduce
Checklist
Tests on GB300:
test_deepseek_v41_bcg_multimodal.py) fails on main too.Related:
🤖 Generated with Claude Code
CI States
Latest PR Test (Base): ❌ Run #42039509434
Latest PR Test (Extra): ❌ Run #42039509462
Latest PR Test (AMD ROCm 10): ❌ Run #42039509342
Tip
Base CI only covers the core cases, and its workload may not exercise your change. Use
/rerun-testto run the tests your change touches, or copy this prompt for an agent: