[AMD][DSV4] perf: retune decode split-K heuristic for MI355X - #36094
Open
karverma-amd wants to merge 4 commits into
Open
[AMD][DSV4] perf: retune decode split-K heuristic for MI355X#36094karverma-amd wants to merge 4 commits into
karverma-amd wants to merge 4 commits into
Conversation
_kv_splits_heuristic over-split by exactly one power of two across the
decode range. At H=128/block_h=64 it chose 8/4/2 splits for T=32/64/128
where 4/2/1 measure faster: split-K only pays while the base grid
underfills the device, and each extra split adds a partial-buffer write
plus reduce-kernel work that the shrinking per-split K cannot amortize.
target_wg_per_cu 2.0 -> 1.5 and the max_kv_splits cap 64 -> 16. Measured
over T in {1..256} x kv_len in {128,512,1024} at H=128 on MI355X, scoring
each candidate by distance from the per-shape optimum: (2.0, 64) leaves
33.5% geomean regret (119% worst case), (1.5, 16) leaves 3.7% (36% worst).
Decode attention kernel at the production shape (T=32, top-k 1024):
55.7 -> 44.1 us, a 20.8% improvement. Selection is unchanged, so results
are identical modulo bf16 reassociation of the split reduction.
The heuristic had no test. Adds one covering the invariants the split-K
reduction depends on (positive power of two within the cap, monotonically
non-increasing in token count, no split once the grid saturates) and the
CUDAGraph-safety contract that it reads only capture-time scalars.
Co-authored-by: Cursor <cursoragent@cursor.com>
karverma-amd
requested review from
BBuf,
DarkSharpness,
HaiShaw,
HydraQYH,
celve and
yuan-luo
as code owners
August 23, 2026 14:53
black 26.1.0 wants the assert conditions wrapped rather than the messages. Formatting only. Co-authored-by: Cursor <cursoragent@cursor.com>
Files under test/registered/ must carry a CI registry call or they are never dispatched; the pre-commit checker rejects them. The heuristic takes only capture-time scalars, so CPU is the right suite. Adds the pytest __main__ entry CI relies on, since registered files are run as `python3 file.py`. Co-authored-by: Cursor <cursoragent@cursor.com>
codespell reads it as a misspelling of "returned". Hyphenating splits the token and keeps the sentence. Co-authored-by: Cursor <cursoragent@cursor.com>
Collaborator
|
/tag-and-rerun-ci |
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
_kv_splits_heuristicpicks how many KV splits DSv4 decode attention launches.It over-split by exactly one power of two across the whole decode range: at
H=128/block_h=64it chose 8/4/2 splits forT=32/64/128where 4/2/1 measurefaster.
Split-K only pays while the base grid underfills the device. Each extra split
adds a partial-buffer write plus reduce-kernel work, and once per-split K gets
short that overhead is no longer amortized.
Modification
Two constants in one file:
target_wg_per_cu2.0 -> 1.5 and the_MAX_KV_SPLITScap 64 -> 16. No kernel changes, no new code paths.Swept
Tin {1..256} xkv_lenin {128, 512, 1024} atH=128on MI355X,scoring each candidate by distance from the per-shape optimum:
The per-shape optimum does depend on per-token K, which is not knowable at
CUDAGraph capture time, so the residual 3.7% is the price of capture-time
safety rather than a tuning gap.
Kernel level
Decode attention at the production shape (
T=32,top-k 1024,H=128):55.7 us -> 44.1 us, a 20.8% improvement. Selection is unchanged, so results
are identical modulo bf16 reassociation of the split reduction.
Performance
DeepSeek-V4-Pro, MI355X (gfx950),
rocm/sgl-dev:v0.5.18-rocm720-mi35x-20260822,8192 in / 1024 out, TP8 + DP8 attention + EP8/MoRI + EAGLE MTP. Both arms are the
same image and the same flags; the only difference is the two constants.
Throughput rises and TPOT falls at every concurrency, and the two move together
at each point, which is harder to explain as drift than either alone. The gain
grows with concurrency because more tokens per rank makes decode attention a
larger share of the step.
One run per cell. Note the effect is specific to DP attention: with plain TP8,
the 128 heads sharded to 16 per rank, the same build measures flat (all deltas
under 1%, signs alternating). DP attention keeps all 128 heads resident per rank,
which is the shape the constants were tuned on.
Commands
Note: under DP attention
--max-running-requestsis divided bydp_size, so avalue below the DP degree floors to 0 per rank and trips
assert max_running_request > 0. At$CONC4 it was raised to 8; the client's--max-concurrencyis what bounds the load either way.Accuracy
GSM8K, 1319 questions, parallel 1319: 0.958 and 0.946 across two runs,
invalid 0.000 both times.
Unit test
_kv_splits_heuristichad no test. This PR addstest/registered/unit/layers/test_dsv4_kv_splits_heuristic.py(38 cases),pinning the contract rather than the constants:
indexes partial buffers by pow2 stride, so a bad value corrupts results rather
than merely running slowly
One clearly-marked table pins the six tuned operating points, so retuning for a
future architecture touches that test and nothing else.
Checklist
CI States
Latest PR Test (Base): ❌ Run #32750870340
Latest PR Test (Extra): ❌ Run #32750870208
Latest PR Test (AMD ROCm 7.2): ⏳ Run #32750870441