Repository navigation
[AMD][Spec][PD] Enable the PD DSA fused-TopK seed remap on ROCm - #36714
Merged
kpham-sgl merged 1 commit intoAug 29, 2026
Merged
Conversation
PR sgl-project#31477 added a decode-local remap so a GLM-5.2 MTP IndexShare seed can enter the allocator-local fused TopK domain under PD disaggregation. The remap is gated on `is_cuda()`, so on ROCm the gate is False, `pd_index_share_seed` stays True, and `should_use_dsa_fused_topk()` returns False: the fix is inert on gfx942/gfx950 and PD decode runs unfused. The maintainer confirmed the intent was to exclude NPU rather than ROCm (sgl-project#31477, 2026-08-24). Widening the predicate to `is_cuda() or is_hip()` admits ROCm and still declines NPU, where both predicates are False. `should_remap_pd_dsa_seed_to_local_slots()` is the only change. The remap itself is untouched, and it reads `req_to_token`, which is page_size=1 token slots on every backend. The `dsa_drop_wide_page_table` optimisation already excludes HIP independently (`is_cuda() and not _is_hip`), so enabling fusion here cannot drop a page table the ROCm indexer still reads. Test: the existing seed-transfer case is parameterised over CUDA / ROCm / neither, asserting that the third still declines the seed and passes the wire positions through unremapped. It stays a CPU unit test under `register_cpu_ci`, since the platform predicates are patched. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tianxiaojiang4
marked this pull request as ready for review
August 27, 2026 16:54
tianxiaojiang4
requested review from
1am9trash,
Fridge003,
HaiShaw,
YAMY1234,
hubertlu-tw,
kkHuang-amd and
rainj-me
as code owners
August 27, 2026 16:54
Contributor
Author
|
@kpham-sgl could you take a look at this one when you get a chance? I do not have permissions to add you as a reviewer directly. |
Contributor
Author
|
Something good to know: further digging into the 3x performance, what the DSA-topk fusion helped most was not kernel launching elimination. It's the two index-transform kernels (transform_index_page_table_decode_kernel and transform_index_page_table_prefill_kernel)that translates index to kvcache address I believe got jit recompiled during runtime due to growing context length. |
4 of 5 tasks
Collaborator
|
/rerun-test test/registered/unit/disaggregation/test_disaggregation_wire.py |
Contributor
|
Results for 🚀 |
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
PR #31477 added a decode-local remap so a GLM-5.2 MTP IndexShare seed can enter the allocator-local fused TopK domain under PD disaggregation. The remap is gated on
is_cuda():On ROCm that gate is False, so the remap never applies,
pd_index_share_seedstays True, andshould_use_dsa_fused_topk()returns False. The #31477 fix is inert on gfx942/gfx950 and PD decode runs unfused.@kpham-sgl confirmed in #31477 that the intent was to exclude NPU, not ROCm:
This is that PR.
Modifications
One predicate, in
should_remap_pd_dsa_seed_to_local_slots():NPU still declines, since
is_cuda()andis_hip()are both False there. The remap itself is untouched.Happy to switch this to
is_cuda_alike(), which is the same predicate (lru_cachedis_cuda() or is_hip()) and has ~24 existing call sites. I kept the expansion because it is the exact form the validation below ran, and because the unit test patches the two predicates individually.Two things I checked before proposing this, since "it compiles on ROCm" is not the same as "it is correct on ROCm":
req_to_token, which ispage_size=1token slots on every backend, so the slot domain is not platform-dependent.dsa_drop_wide_page_tablealready excludes HIP independently (is_cuda() and not _is_hip), so turning fusion on here cannot drop a page table the ROCm indexer still reads.Also note
SGLANG_OPT_USE_TOPK_V2is force-disabled on ROCm for DSA models, so the fused path exercised here isfast_topk_transform_fused, not_topk_transform_v2_paged.Tests
test_pd_decode_fused_topk_remaps_wire_positions_to_local_slotsis parameterised over CUDA / ROCm / neither, asserting the third still declines the seed and passes the wire positions through unremapped. It stays a CPU unit test underregister_cpu_ci— the platform predicates are patched, so no AMD hardware is needed in CI.Correctness on MI300X (gfx942, ROCm 7.2)
Ran against a real ROCm build, which is the arm NVIDIA CI cannot cover:
is_hipforced False (pre-patch behaviour) it declines.SGLANG_DSA_FUSE_TOPK=0, hisparse, and the prefill role each still veto.test_dsa_transform_index.py: 7 passed.test_dsa_indexer.pyandattention/unittests/dsa/test_dsa.pyfail on ROCm — byte-identically with the gate reverted, so not attributable to this change. I ran a stock-gate control arm specifically to attribute rather than assume; they are NVIDIA-only paths (flashinfer,sgl-kerneltopk-v2,flashmla_kv,fa3,tilelang).Accuracy
GLM-5.2-MXFP4, 8×MI355X (gfx950, ROCm 7.2.0), 1P1D at TP2, PD + EAGLE/MTP. Every comparison is paired on verified-identical sample sets (McNemar), with full coverage and zero router circuit-breaker events on both arms.
shortNeedle-in-a-haystack at ~188k prompt tokens: 3/3 depths retrieved on both arms.
No regression on either path; the nominal direction favours the patch on both. Stated honestly, this excludes regressions worse than ~1.1 pp dense and ~5.4 pp sparse. It does not prove exact equality — n=180 is the entire
shortsplit, and resolving a 5 pp sparse effect would need ~1500 per arm, which this benchmark cannot supply at any sampling.Two notes on why the two paths are reported separately rather than averaged:
index_topk = 2048dense-attention threshold, so DSA runs dense and the top-k shortlist is never consulted. GSM8K is a gross-breakage guard; it cannot validate a shortlist change.shortis ~24k tokens median, well above the threshold, so it is the sparse-path test — and it is the metric [Spec][PD] Enable fused TopK for GLM-5.2 MTP IndexShare #31477's own table reports.The LongBench absolute is not comparable to #31477's 60.94% → 62.50%: different hardware, prompt template and sample selection, and at n=64 the binomial SE alone is ~6 pp. The paired within-run delta is the comparable quantity.
Speed
Same topology, 300 s at concurrency 4, acceptance simulation off:
TTFT flat and acceptance unchanged are both expected: this is a decode-side change, and unchanged acceptance is the load-bearing correctness signal, since a wrong remap would hand the draft loop bad KV slots.
Per-worker evidence that the one line changed exactly the intended worker:
"Disabling fused DSA top-k"stock → patchedThe prefill warning persisting in both arms is correct by design — the gate requires
disaggregation_mode == "decode", so prefill draft-extend never fuses, on CUDA either. This signature reproduced across three independent job pairs.Decode step time is derived as
TPOT × accept_len(~72 ms → ~24.8 ms) rather than measured:step_time_dictis a mean overdecode_log_intervalsteps taken from the async scheduler loop's inter-log gap, so percentiles over it are percentiles of averages. Where it is usable it corroborates — 26.87 ms against 24.8 ms derived.Caveats
libionictargets a newerionic_rdmaABI than the deployed driver), so PD KV transfer falls back to XGMI. This is single-node 1P1D, where both workers share a host and KV never crosses the fabric, so it does not affect these numbers — but TTFT on this cluster is transfer-dominated in general.DISAGG_TRANSFER_BACKEND=mori; the speed pair used mooncake. Measured small where compared (unpatched c8: 33.85 vs 34.14 tok/s/user, 0.9%), unquantified with the patch active.CI States
Latest PR Test (Base): ❌ Run #33095503271
Latest PR Test (Extra): ❌ Run #33095502916
Latest PR Test (AMD ROCm 7.2): ❌ Run #33095503597