Skip to content

[ROCm][MLA][Perf] Fuse decode QK-RoPE + Q-concat + KV-concat + KV-cache write for sparse MLA (backport #47757) - #19

Merged
hgquannn merged 1 commit into
moreh/v0.28.0from
moreh/v0.28.0-pr-47757
Sep 21, 2026
Merged

hgquannn merged 1 commit into
moreh/v0.28.0from
moreh/v0.28.0-pr-47757

Conversation

@hgquannn

Copy link
Copy Markdown

Context

Backport of upstream vllm-project#47757 (open, base main) to moreh/v0.28.0, for the GLM-5.2 DSA test images built from this fork. Upstream's six commits (756fe16dce .. 55fbb491c8) squashed into one.

On ROCm the sparse-MLA decode path runs RoPE on q_pe/k_pe, the Q concat, the KV concat and the fp8 KV-cache write as separate ops. This collapses them into the single AITER kernel fused_qk_rope_concat_and_cache_mla (present in aiter v0.1.19, so no aiter change is needed). Gated on ROCm + AITER + fp8 KV cache (not fp8_ds_mla); falls back to the split path otherwise.

Changes

  • vllm/_aiter_ops.py: register rocm_aiter_fused_qk_rope_concat_and_cache_mla and is_fused_mla_qkprep_enabled().
  • vllm/v1/attention/backends/mla/rocm_aiter_mla_sparse.py: use_fused_qk_rope_cache flag, do_kv_cache_update no-op when fusing, fused_qk_rope_concat_and_cache().
  • vllm/model_executor/layers/attention/mla_attention.py: rotary_emb ctor arg, positions threaded through forward / forward_impl / unified_mla_attention_with_output, fused branch after the W_UK bmm, _get_fused_rope_cos_sin().
  • vllm/model_executor/layers/mla.py: defer the main RoPE to the fused kernel and pass positions.
  • vllm/models/deepseek_v32/amd/rocm.py: mypy assert.
  • tests/kernels/core/test_fused_qk_rope_concat_and_cache_mla.py: upstream test, unchanged.

Backport differences: the two mypy-only assert self.rotary_emb is not None lines in vllm/models/deepseek_v32/attention.py are dropped (their surrounding code does not exist in v0.28.0); _get_fused_rope_cos_sin sits before MLAAttention.forward because v0.28.0 has no prepare_kv_cache_update to anchor on. GLM-5.2 (GlmMoeDsaForCausalLM in deepseek_v2.py) uses MultiHeadLatentAttentionWrapper, so it takes this path.

Test plan

Assisted by Claude Code; the backport conflict resolution was reviewed by hand.

…he write for sparse MLA

On ROCm, the sparse-MLA decode path runs the per-layer Q/KV preparation as
several back-to-back ops: main RoPE on q_pe/k_pe, the query concat (ql_nope +
RoPE'd q_pe), the KV concat, and the fp8 KV-cache write. Collapse them into the
single AITER kernel fused_qk_rope_concat_and_cache_mla.

Three decision sites, all keyed off ROCMAiterMLASparseImpl.use_fused_qk_rope_cache:
1. Wrapper (mla.py): when fusing, skip the in-place main RoPE and pass raw
   q_pe/k_pe down, threading `positions` as a real argument.
2. KV write (ROCMAiterMLASparseImpl.do_kv_cache_update): no-op when fusing.
3. Decode (MLAAttention.forward_impl): after the W_UK bmm, call the fused
   kernel to produce the pre-fused q and write the cache.

The fusion is gated (ROCm, AITER, fp8 KV cache, not fp8_ds_mla) and falls back
to the existing split-kernel path otherwise.

Backport of upstream vllm-project/vllm PR vllm-project#47757 to moreh/v0.28.0, squashed
from its six commits. Differences from upstream: the two `assert
self.rotary_emb is not None` lines in vllm/models/deepseek_v32/attention.py are
dropped (their surrounding code does not exist in v0.28.0; they only served
mypy), and _get_fused_rope_cos_sin is placed before MLAAttention.forward
because v0.28.0 has no prepare_kv_cache_update to anchor on. GLM-5.2
(GlmMoeDsaForCausalLM via deepseek_v2.py) uses MultiHeadLatentAttentionWrapper,
so it takes this path.

(cherry picked from commits 756fe16dce 3748e7775b 9b7165b13e bb42395d13 c2f9c18b57 55fbb491c8)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
hgquannn added a commit that referenced this pull request Sep 21, 2026
…se branch

Brings the changes tested on the tmp/v0.28.0 image series into moreh/v0.28.0.
Content is exactly that of the fork PRs #16 to #22 (all against this branch
or its tmp copy):

  #16  [ROCm][Perf] Fuse DSA indexer QK preprocessing with AITER (upstream vllm-project#53094)
  #17  [ROCm][Perf] Shard DSA prefill indexer rows across TP ranks (upstream vllm-project#56944)
  #18  [ROCm] Skip redundant sparse index remap on non-indexer layers
       (backport of upstream vllm-project/vllm vllm-project#51309)
  #19  [ROCm][MLA][Perf] Fuse decode QK-RoPE + Q-concat + KV-concat + KV-cache
       write for sparse MLA (backport of upstream vllm-project#47757)
  #20  [ROCm][Perf] Dispatch DSA prefill indexer logits to aiter's HIP kernel on gfx950
  #21  [ROCm][Perf] Use AITER tuned GEMM for the MoE router gate
       (backport of upstream vllm-project#50535)
  #22  [ROCm][Bugfix] Add `positions` to unified_mla_attention_with_output_fake

Verified as image vllm-forks:0.28.0-pr16-21-a4-9-260917 (this branch minus #22)
built with aiter moreh/v0.1.19 + PR #4 + PR #9 on MI355X.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@hgquannn
hgquannn merged commit 4ebcc08 into moreh/v0.28.0 Sep 21, 2026
@hgquannn
hgquannn deleted the moreh/v0.28.0-pr-47757 branch September 21, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants