Skip to content

[ROCm][Bugfix] Pass per-sequence context lengths to the AITER paged MQA-logits kernels - #59420

Merged
AndreasKaratzas merged 8 commits into
vllm-project:mainfrom
amd-sriram:rocm/paged-mqa-per-seq-context-lens
Oct 9, 2026
Merged

AndreasKaratzas merged 8 commits into
vllm-project:mainfrom
amd-sriram:rocm/paged-mqa-per-seq-context-lens

Conversation

@amd-sriram

@amd-sriram amd-sriram commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Error

MTP with native DSA-indexer decode above next_n=2 crashes during warm-up on MI355X (seen at next_n=3 and next_n=6). GLM-5.2-MXFP4, TP4, num_speculative_tokens=5 (next_n=6), Gluon paged MQA logits:

Memory access fault by GPU node-4 (Agent handle: 0x20465ea0) on address 0x792dc0bf1000. Reason: Unknown.

Where it does not crash, the indexer silently uses wrong causal bounds: in a direct call at next_n=3, the 8192-token sequence loses its last 2 valid positions in every row (9/12 rows correct).

Cause

With native decode (next_n > 1), rocm_fp8_paged_mqa_logits receives a (B, next_n) table of per-row context lengths, [b, j] = L_b - next_n + j + 1, built in indexer.py#L1136-L1152. The AITER Gluon deepgemm_fp8_paged_mqa_logits and deepgemm_fp8_paged_mqa_logits_stage1 kernels read the table as a flat [B] array and some sequences get another row's length.

Example: 4 requests, next_n=3, context lengths 8192 / 1500 / 3000 / 700:

b j=0 j=1 j=2 L_b
0 8190 8191 8192 8192
1 1498 1499 1500 1500
2 2998 2999 3000 3000
3 698 699 700 700

The kernel expects [8192, 1500, 3000, 700] and computes each row's bound itself. Reading the (4, 3) table as [4], it gets the first four values in memory, [8190, 8191, 8192, 1498]: request 0 loses its last 2 positions in every row, and requests 1 to 3 get lengths past their own KV pages, the likely source of the fault. Column j = next_n - 1 equals L_b, which is what the kernel needs.

Fix

Pass the kernels the last column, which is the per-sequence length. [B] and (B, 1) inputs, the C4A Triton path and the torch fallback are unchanged.

On ROCm native decode is used for next_n 1 and 2 today, so MTP with one speculative token goes through this path. #59421 raises that cap, which needs this fix.

Test Plan

  • pytest tests/v1/attention/test_rocm_paged_mqa_context_lens.py (new): the helper returns the per-sequence lengths for a (B, next_n) table and passes [B] / (B, 1) through unchanged.
  • Direct call of rocm_fp8_paged_mqa_logits on one MI355X against a torch reference: B=4, next_n=3, contexts 8192/1500/3000/700, block size 64.

Test Result

Gluon Rows correct Notes
This PR 12/12 max rel diff 2.4e-7
Before 9/12 the 8192-token sequence loses its last 2 valid positions in every row

With this fix, GLM-5.3 MTP at next_n=3 and next_n=5 completes the full throughput sweep, GPQA (0.889 / 0.904) and RULER niah_single_2 (1.0 / 1.0).

next_n (spec tokens) GPQA NIAH Geomean tok/s/GPU
no MTP 0.879 1.00 2435.5
3 (2) 0.889 1.00 3309.1
5 (4) 0.904 1.00 3607.8

Throughput per GPU:

Conc 8k/1k no MTP 8k/1k n=3 8k/1k n=5 60k/600 no MTP 60k/600 n=3 60k/600 n=5
4 544.4 1105.3 1337.0 2925.1 4067.3 4422.3
8 897.5 1650.6 2015.3 3889.2 4658.8 4408.6
16 1415.4 2177.6 2648.5 4550.6 4948.6 5050.4
32 2058.7 3061.8 3638.4 4938.2 5175.0 5303.4
64 2853.3 4013.9 4447.8
128 3741.3 4715.5 4291.3
256 4603.2 4663.6 5208.6

The no-MTP run is the same setup without speculative decoding (decode paged MQA logits on the FlyDSL kernel instead of Gluon).

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@AndreasKaratzas

Copy link
Copy Markdown
Member

Did you do any perf tests after this? Looks like this might introduce perf regression. Also do you think that the best place to fix it is here or in aiter?

@simondanielsson simondanielsson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this makes sense, as I understand it AITER expects 1d context lens (in contrast to Nv deepgemm expecting 2d) and then reconstructs the full one here https://github.com/ROCm/aiter/blob/4ee387457385e9e18c50c4c808b9b4d0300514d6/aiter/ops/triton/_triton_kernels/attention/pa_mqa_logits.py#L513.

But I agree with Andreas, can we check that we don't hit this new contiguous call unless expected? e2e perf numbers with both mtp on and off would be good.

Thanks!

@amd-sriram

amd-sriram commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Did you do any perf tests after this? Looks like this might introduce perf regression. Also do you think that the best place to fix it is here or in aiter?

If we introduce the fix in aiter to accept a 2D context length array, then we might have to change other frameworks and other models that use this method. E.g. ATOM Deepseek v2/v32 passes the per batch context length - https://github.com/ROCm/ATOM/blob/868cb029cc154038fb748c24397afb35e7c2bc57/atom/model_ops/attentions/aiter_mla.py#L3031.

Similar to ATOM, I could compute this in indexer metadata builder so that it removes that copy per step and instead turns it into a persistent buffer, and the AITER calls read it. @AndreasKaratzas which method do you recommend?

I think this makes sense, as I understand it AITER expects 1d context lens (in contrast to Nv deepgemm expecting 2d) and then reconstructs the full one here https://github.com/ROCm/aiter/blob/4ee387457385e9e18c50c4c808b9b4d0300514d6/aiter/ops/triton/_triton_kernels/attention/pa_mqa_logits.py#L513.

But I agree with Andreas, can we check that we don't hit this new contiguous call unless expected? e2e perf numbers with both mtp on and off would be good.

Thanks!

Currently there is no native decode for next_n > 2 - #59421.

@simondanielsson I have now added the Performance number and accuracy numbers in the PR description.

@AndreasKaratzas

Copy link
Copy Markdown
Member

I still think this belongs in aiter. Preferably vllm should be mostly a frontend. Imagine that aiter is bumped later and this becomes a NOP and we don't even know about it

@simondanielsson

Copy link
Copy Markdown
Contributor

If we introduce the fix in aiter to accept a 2D context length array, then we might have to change other frameworks and other models that use this method. E.g. ATOM Deepseek v2/v32 passes the per batch context length - https://github.com/ROCm/ATOM/blob/868cb029cc154038fb748c24397afb35e7c2bc57/atom/model_ops/attentions/aiter_mla.py#L3031.

For this, couldn't we make the aiter impl backwards compatible so you can pass either 1d or 2d?

@amd-sriram
amd-sriram force-pushed the rocm/paged-mqa-per-seq-context-lens branch from 33a8124 to 464cc22 Compare October 5, 2026 14:38
@tjtanaa

tjtanaa commented Oct 5, 2026

Copy link
Copy Markdown
Member

We should ship this as an accuracy and functionality fix, before we land the fixes in AITER.

Comment thread tests/v1/attention/test_rocm_paged_mqa_context_lens.py
@amd-sriram

Copy link
Copy Markdown
Contributor Author

I still think this belongs in aiter. Preferably vllm should be mostly a frontend. Imagine that aiter is bumped later and this becomes a NOP and we don't even know about it

If we introduce the fix in aiter to accept a 2D context length array, then we might have to change other frameworks and other models that use this method. E.g. ATOM Deepseek v2/v32 passes the per batch context length - https://github.com/ROCm/ATOM/blob/868cb029cc154038fb748c24397afb35e7c2bc57/atom/model_ops/attentions/aiter_mla.py#L3031.

For this, couldn't we make the aiter impl backwards compatible so you can pass either 1d or 2d?

@AndreasKaratzas @simondanielsson Thanks for the comments. I have drafted an AITER PR that supports both 1D and 2D context_lens for MTP so that it is backward compatible for other frameworks.

@simondanielsson simondanielsson added the verified Run pre-commit for new contributors without triggering other tests label Oct 6, 2026
…s kernels

Signed-off-by: Sriram Kumar <sriramkumar.kishorekumar@amd.com>
Signed-off-by: Sriram Kumar <sriramkumar.kishorekumar@amd.com>
@amd-sriram
amd-sriram force-pushed the rocm/paged-mqa-per-seq-context-lens branch from 464cc22 to 0ac615a Compare October 7, 2026 13:23
Comment thread vllm/v1/attention/ops/rocm_aiter_mla_sparse.py

@dllehr-amd dllehr-amd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Thanks for catching this @amd-sriram

@AndreasKaratzas

Copy link
Copy Markdown
Member

/ci run

@AndreasKaratzas
AndreasKaratzas enabled auto-merge (squash) October 7, 2026 18:21
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #93383 for commit ea02b2b60a1a.

@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Oct 7, 2026
@vllm-agent

Copy link
Copy Markdown
Collaborator

CI selector (shadow): 4 test steps (7 jobs) instead of 69 (93 jobs)

Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works.

Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.

steps (jobs) Today's rules Selector Would skip Would add
NVIDIA, CPU and others 69 (93) 4 (7) 66 (88) 1 (2)
AMD mirrors 62 (83) 12 (22) 54 (65) 4 (4)
Selector would run (4)
  • cpu-kernel-tests ×2
  • v1-attention-b200 ×2
  • v1-attention-h100-mi300 ×2
  • v1-others-cpu
Would skip (today's rules run them) (66)
  • ascend-npu-test
  • async-engine-inputs-utils-worker
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-test-other-cpu
  • basic-models-tests-initialization
  • basic-models-tests-other
  • batch-invariance-b200
  • batch-invariance-h100
  • benchmarks-cli-test
  • cpu-language-generation-and-pooling-model-tests ×3
  • cpu-multimodal-config
  • cpu-params-env-tokenizers-parser
  • cpu-reasoning-renderers
  • cpu-tool-parsers
  • e2e-core-1-gpu
  • e2e-core-large-memory
  • e2e-scheduling-1-gpu
  • e2e-scheduling-accuracy-1-gpu
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-integration-responses-api
  • entrypoints-integration-speech_to_text
  • fusion-e2e-quick-h100
  • fusion-e2e-tp2-ar-rms-dynamo-partition-amd
  • fusion-e2e-tp2-ar-rms-inductor-partition-amd
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • kernels-attention-test ×7
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • metrics-tracing-2-gpus
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • multi-modal-models-standard-4-other-whisper
  • multi-modal-processor ×4
  • multi-modal-processor-cpu ×4
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-compilation-unit-tests-h100
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • rl-entrypoints-tests
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-sample
  • v1-spec-decode
Would add (today's rules do not run them) (1)
  • cpu-kernel-tests ×2 (code map)
AMD mirrors: would skip (54)
  • async-engine-inputs-utils-worker
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-tests-initialization
  • benchmarks-cli-test
  • e2e-core-1-gpu
  • e2e-core-large-memory
  • e2e-scheduling-1-gpu
  • e2e-scheduling-accuracy-1-gpu
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-integration-responses-api
  • entrypoints-integration-speech_to_text
  • fusion-and-compile-unit-tests-2xb200
  • fusion-e2e-quick-h100
  • fusion-e2e-tp2-ar-rms-config-sweep-h100
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • metrics-tracing-2-gpus
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • multi-modal-models-standard-4-other-whisper
  • multi-modal-processor ×4
  • platform-tests
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-compilation-unit-tests-h100
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • quantized-moe-test-b200
  • regression
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-metrics-lmeval
  • v1-sample
  • v1-spec-decode
AMD mirrors: would add (4)
  • engine-1-gpu (code map)
  • pytorch-nightly-dependency-override-check (code map)
  • ray-dependency-compatibility-check (code map)
  • torch-stable-abi-audit (code map)

2 changed files · base 32fbfa15e8 · head ea02b2b60a · Python record: build 93039 at 1e5d0ea888 · kernel record: table 43b4aae (build 93244), map 43b4aae · not counted: 10 build steps, 5 A100 steps the generator no longer emits, 11 optional steps the selector would also run

@dllehr-amd

Copy link
Copy Markdown
Contributor

/ci run

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

❌ This PR is 19 commits behind upstream main. Your branch must contain every commit currently on upstream main. No new CI build was started. Merge or rebase onto the latest main, then rerun /ci run. To test this branch at your own risk, use /ci run --allow-stale.

@dllehr-amd

Copy link
Copy Markdown
Contributor

/amd-ci retry

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

✅ No failed, timed-out, or expired jobs need retrying: https://buildkite.com/vllm/amd-ci/builds/14210

@simondanielsson

Copy link
Copy Markdown
Contributor

/ci run

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #93626 for commit 41c64175e79a.

@AndreasKaratzas

Copy link
Copy Markdown
Member

/ci retry

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #93784 for commit 1f8f488eb38d, running 19 failed step(s) from Buildkite CI #93626.

@AndreasKaratzas
AndreasKaratzas merged commit 560fae6 into vllm-project:main Oct 9, 2026
42 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in AMD Oct 9, 2026
amd-sriram pushed a commit to amd-sriram/vllm that referenced this pull request Oct 14, 2026
aiter.paged_mqa_logits takes one length per sequence, like the deepgemm
kernels vllm-project#59420 fixed. Route the (B, next_n) table through
_per_sequence_context_lens on this path too.

Signed-off-by: build <build@local>
@amd-sriram

Copy link
Copy Markdown
Contributor Author

I will revert this After ROCm/aiter#6451 (Triton/Gluon) and ROCm/aiter#6450 (FlyDSL). gets merged and lands in Vllm pin

ROCm/aiter#6153 got split in to 2 PRs and is being closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ready ONLY add when PR is ready to merge/full CI is needed rocm Related to AMD ROCm verified Run pre-commit for new contributors without triggering other tests

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants