Repository navigation
[ROCm] Extend the gfx950 extend-attention tile to head_dim <= 128: -43% kernel, -14% TTFT, bit-identical - #34461
Merged
alexnails merged 1 commit intoAug 24, 2026
Conversation
alexnails
requested review from
BBuf,
DarkSharpness,
HydraQYH,
celve and
yuan-luo
as code owners
August 11, 2026 23:14
This was referenced Aug 18, 2026
The gfx950 (CDNA4) branch in _get_block_sizes_for_extend_attention only covered 128 < head_dim <= 256, so head_dim 64 and 128 fell through to the generic (64, 64) / 4-warp default. Measured on MI350X, the same (128, 64) / 8-warp tile that won at head_dim 256 also wins at 64 and 128, so widen the condition to head_dim <= 256. gpt-oss-120b is the motivating case: it is forced onto the Triton backend (aiter's CK mha_batch_prefill has no kernel instance for attention-sinks + sliding-window), head_dim is 64, and _fwd_kernel is the single largest prefill cost. Measured at its TP4 shape (16 q / 2 kv heads, 8x8192-token prefill): -47% kernel time on full-attention layers, -51% on sliding-window layers. head_dim 128 (llama/qwen family) gains -32%. Output is bit-identical at every head dim: BLOCK_N is unchanged, so the online-softmax rescale sequence and the p@v reduction order are untouched; only the query tiling and warp count move. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
alexnails
force-pushed
the
perf/gfx950-extend-attn-headdim64
branch
from
August 24, 2026 06:19
70ff6d2 to
2101ed5
Compare
Collaborator
Author
|
/tag-and-rerun-ci |
This was referenced Aug 24, 2026
This was referenced Oct 19, 2026
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.
Summary
extend_attention.pyalready carries a gfx950-tuned tile —(BLOCK_M, BLOCK_N) = (128, 64)withnum_warps=8— but gates it behind128 < Lq <= 256, which excludes head_dim 64 and 128 for no stated reason. This changes the predicate toLq <= 256.One functional line. Output is bit-identical.
Before / after — isolated kernel
MI350X (gfx950, 256 CU), head_dim 64, measured per layer type because the model alternates full-attention and sliding-window layers:
(64,64)/4(default)(128,64)/8(this PR)head_dim 128 also gains −32%. head_dim 256 already took this path and is unchanged.
(128,64)/8is the only configuration that wins both layer types.(64,64)/8looks attractive on sliding-window layers (+126%) but loses 12% on full-attention layers, making it unusable for a model that alternates them.Before / after — in a served profile
gpt-oss-120b, TP4, ISL 8192, cc8,
SGLANG_USE_AITER=1 --attention-backend triton. Same-window A/B, four minutes apart on the same server script:_fwd_kernelµs/call_fwd_kernelshare of prefill GPUEvery other kernel's call count and per-call time is unchanged, so the reduction is attributable to the retile alone. Traces were checked for the roctracer corrupt-timestamp defect (4987 events, 1 outlier of 0.1 ms, sum/union 1.003).
Before / after — served
benchmark_serving.py, paired probes run in both A/B orders:Warm 1k is unchanged (105.1 vs 106.7 ms), matching the microbenchmark's prediction of a small short-prefill effect.
Numerics
Bit-identical: 14/14 shapes,
max_absexactly 0.0.This is structural rather than incidental.
BLOCK_Ngoverns the online-softmax rescale sequence and the extent of thep@vreduction, so changing it genuinely alters reduction order — butBLOCK_Mcannot. HoldingBLOCK_N = 64while raising onlyBLOCK_Mtherefore preserves the arithmetic exactly. The sweep confirms the rule in both directions: everyBLOCK_N=64configuration is bit-exact, and everyBLOCK_N ∈ {32, 128}configuration differs by ~1e-3.Also checked, no change made
The other HIP launch knobs on this path are already optimal and were left alone:
waves_per_eu=1,matrix_instr_nonkdim=16,num_stages=1.kpackis a literal no-op on gfx950 — the compiler forces 2→1 — so it was excluded from the search.Hardware: MI350X (gfx950), ROCm 7.2 userspace. Measured on MI350X only; an MI355X confirmation would be welcome.
🤖 Generated with Claude Code
CI States
Latest PR Test (Base): ❌ Run #32696876435
Latest PR Test (Extra): ⏳ Run #32698281924
Latest PR Test (AMD ROCm 7.2): ⏳ Run #32696876681