Repository navigation
[Perf] [AMD] gdn: Tune the ROCm decode Conv1D update and recurrent state streaming - #47157
Draft
vorapolsiloai wants to merge 1 commit into
Draft
vorapolsiloai wants to merge 1 commit into
vorapolsiloai wants to merge 1 commit into
Conversation
On ROCm: - the fused QKVZ/BA Conv1D decode update runs one feature per lane (4 wavefronts per 256-feature block instead of 8, which held every feature twice on 64-lane wavefronts) in a copy of the kernel that keeps the shifted state values from its first loads instead of reloading them; - the packed recurrent decode kernel loads and stores its fp32 state tile with streaming hints (evict_first / .cs), since each tile is touched once per step. Both produce bit-identical outputs and states (new kernel test). Setting SGLANG_DISABLE_ROCM_GDN_DECODE_TUNING=1 restores the stock launches; CUDA is unchanged.
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 ROCm, two of the GDN kernels that run in every decode step leave performance unused:
_fused_qkvzba_causal_conv1d_update_contiguous_kernellaunches 8 warps per 256-feature block. On 64-lane wavefronts that is 512 lanes for 256 features, so every feature is held twice. It also reloads two state values after the output store.fused_recurrent_gated_delta_rule_packed_decode_kernelstreams the whole fp32 recurrent state through the caches. At TP1 that is about 3 MB per request per GDN layer, so roughly 100-800 MB per layer per decode step at batch 32-256. Each tile is read and written exactly once per step, so caching it only evicts the weights the next GEMMs read.Modifications
kernels/ops/attention/triton_gdn_fused_proj.py: on ROCm, the launcher picks a new_fused_qkvzba_causal_conv1d_update_reuse_state_kernelat 4 warps, one feature per lane. It does the same operations in the same order as the contiguous kernel. The only difference is that it keeps the shifted state values from its first loads instead of reloading them; each lane is the only one touching those elements. The kernel is a separate copy so the CUDA path stays byte-for-byte unchanged.kernels/ops/attention/fla/fused_recurrent.py: a new constexprSTREAM_STATE(on for ROCm) loads the state tile withevict_firstand stores it with.cs. Tile shape, layout and op order are unchanged.srt/environ.py:SGLANG_DISABLE_ROCM_GDN_DECODE_TUNING=1(read at import, so set it before launch) restores both stock launches. CUDA is unaffected.Dependency: Qwen3.5/Qwen3.8 only reach the fused decode projection + Conv1D launcher on ROCm with #41677, which enables that path on HIP. On main alone, only the recurrent-state streaming change is active on ROCm. This PR is not stacked on #41677 and shares no files with it. It is a single commit on main.
Accuracy
Both changes are bit-exact: outputs and state pools are identical with the tuning on and off.
GSM8K (1319 questions), MI350X, TP2, Qwen3.8-27B: 0.917 (on) vs 0.917 (off).
Speed
MI350X, same image, tuning on vs off:
Serving, MI350X, median TPOT change (two runs):
MI355X, TP1, bs256, from traces (not an isolated A/B): the Conv1D update goes from 1,935 µs/step to 1,025 µs/step.
MI355X, TP1, the same build with the tuning on vs off (
SGLANG_DISABLE_ROCM_GDN_DECODE_TUNING=1), 8k input / 1k output tokens: median time per output token 8.14 → 8.00 ms (-1.7%) at 16 concurrent requests, 19.19 → 18.75 ms (-2.3%) at 64, 57.96 → 56.83 ms (-1.9%) at 256; output tokens/s +2.3% / +1.5% / +1.6%.Setup for the MI355X numbers:
amd/Qwen3.8-27B-Quark-AWQ-MXFP4).--attention-backend aiter, FP8 KV cache,--enable-amd-monokernel, chunked prefill 16384 (TP2 runs add INT4 quick reduce).SGLANG_DISABLE_ROCM_GDN_DECODE_TUNING=1), on the same GPU, averaged over 2 GPUs.Relation to #41879
#41879 adds opt-in AITER FlyDSL kernels for the prefill conv and the decode recurrence. Those need AITER's FlyDSL ops and are not bit-exact, because they split K across lanes. This PR keeps the Triton kernels, is bit-exact and on by default on ROCm, and also covers the decode Conv1D update, which #41879 does not touch. The two PRs share no files.
Tests
New:
test/registered/kernels/ops/attention/test_rocm_gdn_decode_tuning.py, registered for AMDjit-kernel-unit. It calls the public launchers with the tuning on and off and compares outputs and whole state pools bit for bit, including untouched slots. Coverage:Results:
Checklist
pre-commit run --all-files