Repository navigation
Conversation
jiaryang
force-pushed
the
amd/gfx1250-mla-fused-rope-kv-cache
branch
from
October 20, 2026 15:55
68175b3 to
f142e83
Compare
jiaryang
marked this pull request as ready for review
October 20, 2026 15:58
jiaryang
requested review from
Fridge003,
ch-wan,
fzyzcjy,
ispobock and
merrymercy
as code owners
October 20, 2026 15:58
Contributor
Author
|
/rerun-failed-ci |
jiaryang
force-pushed
the
amd/gfx1250-mla-fused-rope-kv-cache
branch
from
October 22, 2026 16:26
217506b to
b377194
Compare
Contributor
Author
|
/rerun-failed-ci |
3 similar comments
Contributor
Author
|
/rerun-failed-ci |
Contributor
Author
|
/rerun-failed-ci |
Contributor
Author
|
/rerun-failed-ci |
Contributor
Author
|
@amd-bot ci-status |
Collaborator
5 tasks
Contributor
Author
|
/rerun-failed-ci |
With SGLANG_USE_AITER=1 on gfx1250, aiter or triton MLA decode skips the standalone RoPE and uses aiter fused_qk_rope_cat_and_cache_mla, the same fused branch aiter MLA takes on gfx95, with a bf16 Q. sglang's RotaryEmbedding keeps cos and sin in one cos_sin_cache, so the kernel gets its two halves as strided views. Limited to plain rope modules whose table covers the whole rope head, without DSA or DCP, and to bf16 or fp8 e4m3 KV caches. Requires aiter with ROCm/aiter#5501. The layer-static terms of the gate are computed once in __init__. A CPU unit test pins down each term of the gate and the cos/sin order of the tables. Co-authored-by: Cursor <cursoragent@cursor.com>
Address review feedback. - The gate is evaluated per call as on gfx95 instead of caching the layer-static terms in __init__, so init_mla_rocm_forward is removed. - The rope check is the exact type RotaryEmbedding or DeepseekScalingRotaryEmbedding; subclasses such as Bailing MoE v3's video mrope compute their rope differently. - The KV check reads the pool's logical dtype (bf16 or fp8) instead of the kv_cache_dtype server arg, so fp8-quantized checkpoints and draft runners whose server arg is "auto" are covered, and an fp16 pool stays unfused. - Q keeps q_nope_out's dtype on gfx1250, which is bf16 there. - Prepare's rope-skip condition moves into _applies_rope_in_prepare so the tests can check that prepare skips rope exactly when core fuses it. - The CPU cases join test_rocm_mla_absorb_fusion_gate.py, and test_rocm_mla_gfx1250_fused_rope_gate.py is removed. Co-authored-by: Cursor <cursoragent@cursor.com>
jiaryang
force-pushed
the
amd/gfx1250-mla-fused-rope-kv-cache
branch
from
November 3, 2026 06:51
e99dec6 to
59901a8
Compare
This comment has been minimized.
This comment has been minimized.
main moved ForwardMode into sglang.srt.model_executor.forward_mode and its check-indirect-imports hook rejects importing it through forward_batch_info. Co-authored-by: Cursor <cursoragent@cursor.com>
On gfx1250 with SGLANG_USE_AITER=1, _fused_rope_cat_and_cache takes the gfx1250 branch and reads rotary_emb.cos_sin_cache, which the test's stub lacks. That branch excludes DSA, so the test's DSA pools pin _use_gfx1250_fused_mla_rope to False.
4 of 5 tasks
Contributor
Author
|
/rerun-failed-ci |
Contributor
Author
|
/rerun-failed-ci |
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
On gfx950, aiter MLA decode runs RoPE, the q/k concat and the KV-cache write in one
fused_qk_rope_cat_and_cache_mlakernel. On gfx1250 these are still separate: native RoPE, twotorch.catandset_kv_buffer, more than a dozen elementwise kernels per layer. This PR extends the gfx950 fused branch to gfx1250.Modifications
With
SGLANG_USE_AITER=1on gfx1250, MLA decode with the aiter or triton backend skips the standalone RoPE and takes the fused branch, as aiter MLA does on gfx950. gfx950 is unchanged.RotaryEmbeddingorDeepseekScalingRotaryEmbedding, and a bf16 or FP8 KV pool. The pool check reads the pool's dtype, so an fp16 pool, which the kernel rejects, stays on the unfused path.cos_sin_cache; the kernel gets the two halves as strided views.q_nope_out's dtype, which is bf16 on gfx1250: MLA decode there takes an unquantized Q even over an FP8 KV cache._applies_rope_in_prepare, so the unit test can check that prepare skips RoPE exactly when core fuses it.test/registered/unit/models/test_rocm_mla_absorb_fusion_gate.py.Requires ROCm/aiter#5501, which both ROCm Docker pins in
docker/rocm.Dockerfilealready contain. On main, gfx1250 MLA decode runs the triton backend, which the gate covers, and the first set of numbers below is main with the triton decode backend. With #44458's aiter decode backend the same fused branch applies; the second table measures that.Validated on gfx1250 with Kimi-K2-Thinking-MXFP4 at TP8, with the triton decode backend on main and the aiter decode backend from #44458.
Accuracy Tests
The fused kernel matches the unfused path (q and the written KV rows) for bf16 and FP8 KV, batch 1 to 128.
GSM8K, 8-shot, 1319 questions, triton decode backend on main:
Unchanged main moves by 0.011 between server launches (0.950 and 0.939), so the single bf16 run is within that spread.
Speed Tests and Profiling
RoPE, concat and KV write per layer, Kimi-K2 TP8 shapes, CUDA graph replay:
bench_serving, 8k input / 1k output, FP8 KV, triton decode backend on main:In the decode profile (concurrency 4, 8k context), each layer's RoPE, concat and KV write go from about 14 PyTorch kernels taking about 82 us to the fused kernel taking about 3 us, and the decode step goes from 30.0 ms to 23.6 ms. The triton decode attention kernels are unchanged.
Concurrency 4 with #44458's aiter decode backend on both sides:
Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ciCI States
Latest PR Test (Base): ✅ Run #41622351290
Latest PR Test (Extra): ❌ Run #41622351313
Latest PR Test (AMD ROCm 10): ✅ Run #41622351159
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: