Skip to content

[ROCm][Bugfix] Fix Triton paged decode leaving output heads unwritten on gfx942 - #63268

Merged
AndreasKaratzas merged 4 commits into
vllm-project:mainfrom
AndreasKaratzas:akaratza_rocm_paged_decode_buffer_store
Oct 23, 2026
Merged

AndreasKaratzas merged 4 commits into
vllm-project:mainfrom
AndreasKaratzas:akaratza_rocm_paged_decode_buffer_store

Conversation

@AndreasKaratzas

@AndreasKaratzas AndreasKaratzas commented Oct 23, 2026 •

Copy link
Copy Markdown
Member
  • chunked_prefill_paged_decode.py: offset the output pointer to the token's row as a 64-bit scalar and keep the per-head store offsets 32-bit.
  • test_prefix_prefill.py: fill the output with NaN, so a row the kernel skips fails every time instead of passing on leftover memory.

test_qwen3_nonstandard_block_size[True-chunked_prefill_paged_decode-...-8-4-256-1056], added with the interleaved V cache in #42755, fails on MI300 intermittently (build 96693). Locally it fails 6 of 20 runs on main. The Triton decode kernel only writes 263 of the decode token's 2048 output values, so the result depends on whatever memory the output buffer reuses. The kernel's logic is correct: under TRITON_INTERPRET=1, or with AMDGCN_USE_BUFFER_OPS=0, every value is written. The LLVM IR computes the 64-bit head offset correctly, but in the gfx942 ISA the output_stride_1 argument is never read and the head index is multiplied by an unrelated spilled SGPR instead (the block-table row offset, in the variant traced). Rows land at the wrong offsets, so most values are left unwritten and some heads overwrite others. This only happens in variants with hundreds of SGPR spills; computing the per-head offset in 32 bits avoids it, so the change is a workaround for a backend miscompile. The interleaved V path is not the only one affected: the normal layout loses outputs too, on the Triton fallback with 128 and 256 token pages at head size 128 and 256, which hybrid models with large pages can hit. On a decode-only sweep of 60 head-size, GQA, page-size and layout combinations, 18 dropped stores before this change and none after; kernel time changes by -0.4% to +1.4%.

Tests: pytest kernels/attention/test_prefix_prefill.py 10/10 (205 passed each; the updated test fails 3/3 without the kernel change), and pytest v1/attention/test_attention_backends.py v1/attention/test_rocm_attention_backends_selection.py (201 passed).

AI assistance (Claude Code) was used to draft this change. Every line was reviewed by the submitter.

… on gfx942

With 64-bit store offsets, Triton's AMD buffer_store lowering drops the
head stride for the dot-result layout of kernel_paged_attention_2d, so a
decode row's heads land on top of each other and most stay unwritten.
Offset the output pointer to the token row as a 64-bit scalar and keep the
per-head offsets 32-bit. Fill the test output with NaN so an unwritten row
fails deterministically.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andreas Karatzas <akaratza@amd.com>

@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.

@mergify mergify Bot added rocm Related to AMD ROCm bug Something isn't working labels Oct 23, 2026
@github-project-automation github-project-automation Bot moved this to Todo in AMD Oct 23, 2026
@AndreasKaratzas

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #96825 for commit 92d7790dba57.

ℹ️ This PR is 14 commits behind upstream main. Merged upstream main into this branch as 92d7790dba57 before starting CI. Pull the branch before pushing more changes.

cur_batch_in_all_start_index * output_stride_0
+ query_head_idx * output_stride_1
)
# The row base stays a 64-bit scalar and the per-head offsets 32-bit: with

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.

Could this also be an issue in triton_unified_attention.py?

@AndreasKaratzas AndreasKaratzas Oct 23, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I checked triton_unified_attention.py on MI300X with our pinned Triton (3.8.0+git669b31ac), and it doesn't hit this. I pre-filled the output with NaN and swept head size 64/128/256, GQA 1/4/8, page size 16 to 256, decode and mixed batches, 2D and 3D (so reduce_segments too), fp8 out, TD on/off, forced tiles, and softcap/sinks/sliding window/ALiBi. Every output value was written, and the results match AMDGCN_USE_BUFFER_OPS=0 bit for bit. The same harness reproduces the drops in paged decode on main.

AndreasKaratzas and others added 2 commits October 23, 2026 18:59
The LLVM IR for the i64 head offset is correct; the gfx942 ISA ignores
output_stride_1 and multiplies the head index by an unrelated spilled
SGPR in high-spill variants. The 32-bit per-head offset avoids it.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Andreas Karatzas <akaratza@amd.com>
@AndreasKaratzas

Copy link
Copy Markdown
Member Author

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #96953 for commit 988488d024b3.

@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.

LGTM

I think generally in the future when we review triton code we have to be careful about proper handling of 32bit offsets and lowering to buffer load/stores, seems a bit brittle

@AndreasKaratzas
AndreasKaratzas merged commit 18df4cd into vllm-project:main Oct 23, 2026
118 checks passed
@AndreasKaratzas
AndreasKaratzas deleted the akaratza_rocm_paged_decode_buffer_store branch October 23, 2026 21:26
@github-project-automation github-project-automation Bot moved this from Todo to Done in AMD Oct 23, 2026
zhentaocc pushed a commit to zhentaocc/vllm that referenced this pull request Oct 27, 2026
Both accuracy bugs in ROCM_ATTN's Triton fallback that this avoided are
fixed on main: the sliding-window NaN (vllm-project#62828) no longer occurs since
vllm-project#60767 nulls below-window block-table entries, and the gfx942 unwritten
output heads were fixed by vllm-project#63268. What remains is a performance change,
which belongs in vllm-project#61433. Keep only the gfx950 rule for vllm-project#62606.

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Chen, Todd <zhenchen@amd.com>
bantianyue pushed a commit to bantianyue/vllm that referenced this pull request Oct 28, 2026
… on gfx942 (vllm-project#63268)

Signed-off-by: Andreas Karatzas <akaratza@amd.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: vllm-agent <claw@inferact.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working rocm Related to AMD ROCm

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants