Repository navigation
Conversation
…3.2, GLM-5.x) Based on the merged MLA DCP path (sgl-project#14194 lineage): latent KV stays interleaved across DCP ranks (masked/divided write already inside set_mla_kv_buffer's kernel), while the DSA indexer K cache is kept replicated (global slots, sized *dcp) so every rank scores the full sequence and produces identical top-k. Owned selections are filtered and mapped to local rows inside the index transforms; sparse flashmla kernels return their LSE and outputs are combined across the DCP group (existing cp_lse_ag_out_rs_mla for the head-widened decode, new cp_lse_ag_out_ar all-reduce variant for extend). v1 scope: --dsa-{decode,prefill}-backend flashmla_sparse, bf16 KV cache, no hisparse, unfused top-k (fused variants bake in full-sequence index math). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… groups); contiguous LSE for the combine Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Under DCP decode the indexer (replicated, full-sequence paged scoring) is independent of the q-side pipeline, so fork it onto the existing alt stream and join after the cross-rank q all-gather is issued: comm hides behind indexer compute. GLM-5.2-NVFP4 tp4+dcp2 32k-ctx decode: +11% output throughput, -6% mean ITL; gsm8k parity unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ff by default), env knobs - Row-slice the head-padded flash_mla_sparse call under DCP (SGLANG_DSA_DCP_SPARSE_MAX_ROWS, default 8192, ~5% extend overhead) — fixes the OOM at large chunked-prefill sizes without lowering --mem-fraction-static. - Fused top-k v2 under DCP: correct via a non-mutating owner filter on the fused output (IndexShare-safe), but the v2 plan/persistent-pool is decode-shaped and ~2x slower on 32k-row extend chunks with no measured decode win — disabled by default, SGLANG_DSA_DCP_FUSED_TOPK=1 to experiment. Follow-up: extend-shaped plan (work-proportional routing + request-blocked tiling). - Speculative decoding stays rejected with DCP: EAGLE draft-graph capture crashes on current main with this flag set even without DCP (upstream Triton IMA), so there is no baseline to validate against. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
trtllm-gen already surfaces the base-2 LSE (ComputeLSEFromMD) through flashinfer's return_lse, so both decode and the decode-ized extend flow through the existing cross-rank combine. The owner-filtered top-k rows are compacted valid-first (attention is permutation-invariant over the selected set) with per-row local counts as seq_lens — the trtllm-gen sparse kernel scans a counted prefix, unlike flashmla's -1 skipping. Zero-count rows contribute exp2(-inf)=0. The LSE request needs a larger softmax-stats workspace (2x under DCP). This makes the resolved sm100 defaults (trtllm + fp8_e4m3 KV) the primary DCP configuration; flashmla_sparse + bf16 KV remains supported. GLM-5.2-NVFP4 tp4+dcp2, default flags: gsm8k 0.640 vs 0.610 baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lse_ag_out_ar SGLANG_DSA_DCP_SPARSE_MAX_ROWS and SGLANG_DSA_DCP_FUSED_TOPK move to envs.EnvInt/EnvBool (malformed values now warn and fall back instead of crashing at import). cp_lse_ag_out_ar was the combine for the abandoned same-query extend scheme (wrong across DCP head groups) — removed so nobody wires it back in; extend uses the gathered-q cp_lse_ag_out_rs_mla path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Coerce dsa_prefill_impl=flashmla_auto to flashmla_sparse under DCP instead of hard-failing before auto-select runs (non-sm100 defaults). - Gate the 2x LSE workspace on the trtllm impls actually being used (saves 384MB on flashmla_sparse+DCP runs). - Initialize lse=None in forward_absorb_core and assert in the DCP combine so a fusion path skipping the LSE fails loudly, not unbound. - Union return annotation on _forward_flashmla_sparse. - Unit tests for the DCP owner-filter branches of both index transforms (test_dsa_transform_index.py, 2 passed on B300). Remaining comments triaged as noise: negative-index guards (decode kernel's masked lanes never store computed values and C-remainder of -1 never matches a rank; prefill already guards via valid_topk_mask), backend-level spec assert (server_args already rejects spec+DCP at launch). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…P combos - Revert test_dsa_transform_index.py additions (keep the PR code-only). - Skip building the dense-MLA DCP extend gather metadata for DSA models (unused by the sparse local-shard extend path). - Reject --enable-mixed-chunk and --enable-dp-attention under DSA DCP: MIXED batches would walk the DCP extend path with mixed rows, and dp-attention currently overflows the trtllm softmax workspace besides being structurally unvalidated (both are follow-up work). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Mixed chunk needs no new machinery: decode and extend rows share the row-wise DCP recipe (gathered q -> local-shard sparse attention -> LSE combine). Validated under concurrent load (gsm8k 0.620, flashmla dcp2). - dp-attention composes when each DCP group nests inside one attention-DP shard (attn_tp_size % dcp_size == 0, asserted): ranks in a group then share requests and the replicated indexer keeps producing identical top-k. The trtllm LSE workspace now scales with the dcp-widened head count, and dp idle-companion batches skip the gather/combine. tp4 dp2 dcp2 on the default trtllm+fp8 stack: gsm8k 0.648 (500q) vs 0.635 dp-only baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…TOPK (opt-in ENABLE_ verb per env-var conventions) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ecipe The earlier 'blocked upstream' conclusion was wrong: the EAGLE draft-capture IMA was the sgl-project#30209-class flashinfer_trtllm bf16 draft-MoE instability, avoided by the production draft-MoE pins (--speculative-moe-runner-backend triton --speculative-moe-a2a-backend none). With those pins, spec works on this branch's stacks, so the CUDA spec x DCP rejection becomes an experimental warning and the three DSA DCP mode gates (q gather, attention branch, LSE combine) include DRAFT_EXTEND_V2 — draft rows use the same row-wise recipe; the dense-MLA draft path stays unimplemented. GLM-5.2-NVFP4 tp4 dcp2 + EAGLE 5-1-6 + triton draft-MoE: serves with accept length 4.4-4.6; gsm8k 0.590 (500q) vs no-spec dcp2 0.622-0.648 — functional, verify-path numerics validation outstanding. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ft-MoE pin The triton draft-MoE pin itself costs ~4.5 gsm8k points (0.592 vs 0.636 at 500q, no DCP, otherwise identical) — the earlier 0.590 spec x DCP reading was entirely that recipe, not DCP. On the default stack (trtllm attention, fp8 KV, flashinfer_trtllm draft MoE) with flashinfer >= 0.6.15 (contains the flashinfer#3238 draft-MoE fix): spec no-DCP 0.636, spec + dcp2 0.650 (500q), accept length 4.35-4.61. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same two dsa_backend.py conflicts as the earlier Helix-branch merge — upstream sgl-project#30514's Q8KV8 restructure vs the DCP init block and the extend flashmla_sparse call; resolved keep-both / concat-then-DCP. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The DCP extend recipe all-gathers q across the DCP group, which requires every rank in the group to hold identical extend rows. Prefill-CP splits rows across ranks, so DCP-group peers hold different tokens and the gathered q mixes unrelated rows. Short prompts previously bypassed CP engagement, which masked this; the batch-prep rework in the upstream window (post sgl-project#30514) routes short extends through CP and surfaced it as zero accuracy. Reject the combination at launch until the CP-split extend path gathers position-ordered KV across the DCP group instead (all_gather_kv_cache_for_mla_extend-style, RAGGED indexing). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… path The trtllm backends are the sm100 defaults and the only stack anyone should serve with; the flashmla_sparse DCP support existed only as a bring-up vehicle and carried real weight: an LSE tuple return + row chunking (with its SGLANG_DSA_DCP_SPARSE_MAX_ROWS env) to bound the 128-head padding transients, a flashmla_auto coercion, and dtype asserts. Remove all of it; DCP now requires trtllm decode+prefill at init. _forward_flashmla_sparse returns to its upstream shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rlap block, rename slot mapper - transform_index / dsa_backend / init: comments cut to one or two lines - delete the dangling flashmla row-slice comment - workspace multiplier computed in _dcp_workspace_multiplier instead of inline in the buffer lambda - _apply_dcp_owner_filter -> _dcp_global_slots_to_local_rows - forward_mla capture-overlap block: shared _indexer_topk closure instead of two duplicated arms - spec x DCP warning no longer talks about old flashinfer releases Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- init guards reordered (backend requirement first, then composition, then toggles) with assert messages cut to the point - slot mapper uses scalar torch.where - extend gather branch restructured as two positive arms, no-op elif/pass arms dropped (idle needs nothing; dense draft-extend simply has no gather) - comments in memory_pool/environ/kernels cut to one or two lines Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # python/sglang/srt/layers/attention/dsa_backend.py
…buffer for DCP The persistent multi-CTAS KV counter buffer (sgl-project#31607) is sized by head count; under DCP the trtllm decode runs with dcp-widened heads, so pre-size it by num_q_heads * dcp_size and let the grow check use the per-call head count. token_capacity in metrics and the load inquirer now reports logical tokens (physical * dcp_size), matching the allocator's accounting. Fix by @b8zhong, thanks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fixup kernel Route the trtllm decode LSE output through a pre-registered symmetric-memory buffer so cp_lse_ag_out_rs_mla's all-gather needs no separate cast/copy, and replace the zero_rows torch.where masking with the fixup_zero_kv_rows kernel (rows where this rank owns none of the selected tokens were producing NaN, not 0, so the prior masking was incomplete).
# Conflicts: # python/sglang/srt/layers/attention/dsa_backend.py
The init-time disable turned fusion off for decode too, which costs decode perf for no reason: the per-mode force_unfused gate already keeps extends on the unfused transform (the v2 plan is decode-shaped), and the fused decode table goes through the owner filter. The SGLANG_DSA_DCP_ENABLE_FUSED_TOPK escape hatch forced fusion onto extends, which produces wrong indices; with the per-mode gate there is no configuration that reaches a fused extend, so the env var is gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Re-enabling fused decode (c192ef9) drops gsm8k from 0.920 to 0.000 at dcp2 with everything else fixed, so the v2 fused transform no longer composes with the DCP owner filter after the recent upstream churn. Keep the unfused path until that is root-caused; the incorrect SGLANG_DSA_DCP_ENABLE_FUSED_TOPK escape hatch stays removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts: # python/sglang/srt/models/deepseek_common/attention_forward_methods/forward_mla.py # python/sglang/srt/server_args.py
15 of 41 tasks
foraxe
marked this pull request as ready for review
August 12, 2026 09:35
foraxe
requested review from
1am9trash,
BBuf,
DarkSharpness,
Edwardf0t1,
Fridge003,
HaiShaw,
HydraQYH,
Qiaolin-Yu,
YAMY1234,
Ying1123,
alphabetc1,
celve,
ch-wan,
fzyzcjy,
hanming-lu,
hebiao064,
hnyls2002,
hubertlu-tw,
hzh0425,
ispobock,
kkHuang-amd,
merrymercy,
rainj-me,
xiezhq-hermann,
yizhang2077 and
yuan-luo
as code owners
August 12, 2026 09:36
Contributor
|
Thanks @foraxe. Closing this because you have 11 PRs open and none updated in 7 days, over our soft cap of 5 for idle PRs. Reopen the two or three you most want reviewed - a short active set moves faster than a long idle one. Some directories moved recently, so an older branch may need retargeting: |
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.
Summary
Depends on #31821.
This draft adds the complete opt-in Shared-DCP optimization for the DSA/MLA
decode path:
and FP8 conversion;
candidate reads for bounded decode.
The producer-fanout Query research route is not included. Large or ragged
prefill rows retain packed candidate AllGather after a direct ragged transport
experiment was measured, found substantially slower, and reverted.
Why
#31821 context-shards DCP attention, but it still:
every DCP rank.
Shared-DCP makes these objects peer-addressable and aligns Indexer storage and
compute with logical-token ownership. The default remains the #31821 path.
Configuration
The selected routes require a same-host NVIDIA CUDA DCP group with peer access
and native peer atomics, and currently target the DeepSeek-V3.2/GLM-5.x DSA
MLA path.
Performance
Measured on four NVIDIA GB200 GPUs with GLM-5.2 NVFP4, FP8 KV cache, fixed
1800 MHz clocks, and the exact #31821 implementation as the same-lineage
control.
Three fresh server repetitions per DCP concurrency-1 cell:
All DCP TPOT CVs are below 0.18%.
Ordinary NCCL A2A was the fastest existing collective on this host. The full
stack still lowers TPOT by 2.15%/5.14% for DCP2 at 32K/128K and
3.28%/8.27% for DCP4. FlashInfer
fi_a2awas attempted at DCP2 and DCP4, butthis allocation rejected MNNVL fabric memory with
CUDA_ERROR_NOT_PERMITTED; no performance value is inferred.KV capacity
physical tokens/rankis measuredmax_total_num_tokens; logical KV tokensmultiply by DCP size.
Measured frontier:
Concurrency tradeoff
At 128K C4/C8, Shared-DCP improves output throughput by 0.49-2.30%, TPOT by
0.99-2.86%, and p99 ITL by 3.93-10.30%.
At 32K C16/C32 mixed prefill/decode, aggregate output throughput is
4.25-5.26% lower. Tail ITL improves by 1.11-11.97%, but TPOT is mixed. This
draft therefore claims long-context decode and KV capacity, not universal
throughput or prefill improvement.
Isolated mechanisms
Validation
changing-input CUDA-graph replay;
changing-input CUDA-graph replay;
F401,F821,UP037, py_compile, andgit diff --check;Accuracy
The final-current-main matrix is complete on the four-GPU allocation.
Pass zero is the warmup and is excluded from the counted result. AIME25 uses
30 problems x 4 stochastic repeats with a 64K reasoning cap. Every GSM8K pass
has zero invalid outputs and every AIME25 pass has a 0.00% error rate. Counted
AIME25 truncation rates at the cap are 0.83%/0%/0%/2.50%/0% for
TP4/DCP2-control/DCP2-Shared/DCP4-control/DCP4-Shared. The earlier interrupted
DCP2 counted AIME25 run is excluded; the table uses its fresh 120-sample
replacement restarted from sample zero.
Coverage limits
UNMEASURED; no eight-GPU allocation was available.AllGather.
Review structure
The branch keeps three explicit commit boundaries for independent review:
d16fd9994..2a2b156292a2b15629..5e8618eaf5e8618eaf..6f984f7a3CI States
Latest PR Test (Base): ❌ Missing
run-cilabel -- add it to run CI tests.Latest PR Test (Extra): ❌ Blocked --
run-ciis required first.