Repository navigation
[Triton/Gluon] Add gfx942 FP8 head-dim-256 MHA config - #7516
phambinhfin wants to merge 3 commits into
Conversation
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
One backend per PR: PR title tags & labels: |
READY FOR HUMAN REVIEWPR Self-ReviewRevision Author self-review accepted. Readiness report: Author answers
Show the author's self-review answersBehavior and intentValidation and unverified scopePR-specific questionChanged op testsPR state
Copilot findings
Code and op-test hygiene
Required CI
Shadow mode reports what would block but keeps the status successful. Set |
akii96
left a comment
There was a problem hiding this comment.
Thanks for the good work! I took a swing at checking a few things in the hopes that once the needed changes are in before other reviewers/maintainers take a look.
cc24cd8 to
11ee970
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The new test duplicates input setup, quantization, and reference checks from an existing test, leaving shared logic to be extracted into mha_test_utils.py while keeping backend-specific calls separate.
1 open issue
What changed in this PR
This PR adds a targeted gfx942 configuration for Triton MHA forward with FP8 inputs and a value head dimension of 256, without changing the general default.
Changes:
- Adds
fp8_large_headwith eight warps and two pipeline stages. - Selects it only for FP8 at
head_dim_v == 256, preserving existing dispatch precedence. - Adds selection-boundary tests and causal/non-causal variable-length correctness tests.
| File | Description |
|---|---|
op_tests/triton_tests/attention/test_mha.py |
Adds config-selection and FP8 d256 correctness tests. |
aiter/ops/triton/configs/gfx942/triton/attention/mha/DEFAULT.json |
Defines the gfx942 fp8_large_head tuning entry. |
aiter/ops/triton/_triton_kernels/attention/mha.py |
Adds guarded selection of the new FP8 configuration. |
Review effort: Balanced
7ecb718 to
1ca189a
Compare
|
@akii96 @Boss2002n Could u take a look again? |
|
@Boss2002n this ticket prevent vllm-project/vllm#62913 move on. Could you take alook if you have time? |
akii96
left a comment
There was a problem hiding this comment.
Thanks for working through the first round 🙏
You might want to look at two main-side PRs are worth a look, since the branch predates both:
- #7232 added
test_mha_forward_out_dtype(covers FP8 causal varlen d256) and moved_flash_attn_forward/get_archto the top-level imports. So the "only test reaching d256" line in the description is out of date, and the in-function imports can go. Your test is still worth keeping: it checks againstattention_refand also covers non-causal. - #6502 changed
_flash_attn_forwardto also returnrng_state, so the 5-value unpack in the new test will fail after the rebase (inline).
Happy to take a second look once it's rebased!
| "fp8_large_head": { | ||
| "BLOCK_M": 128, | ||
| "BLOCK_N": 64, | ||
| "PRELOAD_V": true, | ||
| "waves_per_eu": 2, | ||
| "num_warps": 8, | ||
| "num_ctas": 1, | ||
| "num_stages": 2, | ||
| "matrix_instr_nonkdim": 16, | ||
| "kpack": 1 | ||
| }, |
There was a problem hiding this comment.
Nit (PR description only): compared to default, this changes num_warps (4→8), num_stages (1→2) and PRELOAD_V (false→true), and adds matrix_instr_nonkdim=16 and kpack=1. The description only mentions the first two and credits the gain to num_stages=2. Could you list all of them, and only credit num_stages if you have a sweep that shows it?
There was a problem hiding this comment.
Updated the description. Versus default this entry changes num_warps 4→8, num_stages 1→2, PRELOAD_V false→true, and adds matrix_instr_nonkdim=16 and kpack=1.
The reported speedup is the whole entry versus default. The 108-config sweep varies BLOCK_M, BLOCK_N, num_warps, num_stages, and PRELOAD_V together, so it does not isolate num_stages. num_stages=2 stays in the description only as the LDS reason for head_dim_v == 256: above that, BLOCK_DMODEL_POW2 pads to 512 and the double-buffered K tile needs 65568 B against a 65536 B limit.
| from aiter.ops.triton.attention.mha import _flash_attn_forward | ||
| from aiter.ops.triton.utils._triton.arch_info import get_arch |
There was a problem hiding this comment.
Minor nit: after rebasing, main already imports _flash_attn_forward and get_arch at the top of this file, so these can go maybe please check
There was a problem hiding this comment.
Dropped the in-function imports. After the rebase, _flash_attn_forward and get_arch are already imported at the top of the file.
|
|
||
| HEAD_SZ = 256 | ||
| x = make_varlen_fp8_inputs(2, 512, 1024, 8, 2, HEAD_SZ, dtype) | ||
| triton_out, _, _, _, _ = _flash_attn_forward( |
There was a problem hiding this comment.
Needs a fix after rebase: #6502 made _flash_attn_forward return 6 values (it added rng_state), so this unpack will fail. _flash_attn_forward(...)[0] avoids depending on the length.
There was a problem hiding this comment.
Rebased onto main and switched to _flash_attn_forward(...)[0], so the test no longer depends on the return length after #6502. -k fp8_large_head: 9 passed on MI325X after the rebase.
fwd["default"] pairs BLOCK_M=128, BLOCK_N=64 with num_warps=4, which is 3.2-3.8x slower than fp8_large_head for FP8 at head_dim_v == 256 on gfx942. Add the entry and a _get_config branch, bounded to d256 because above it the head dim pads to 512 and num_stages=2 exceeds the 64 KB LDS limit. Signed-off-by: Pham Binh <194774975+phambinhfin@users.noreply.github.com>
Move the varlen FP8 input setup and reference shared by test_mha_varlen_fp8_gluon and test_mha_varlen_fp8_large_head into mha_test_utils. head_dim_v == 256 already excludes None. Signed-off-by: Pham Binh <194774975+phambinhfin@users.noreply.github.com>
ROCm#6502 made _flash_attn_forward return rng_state, so the 5-value unpack fails. Index the output, and drop imports main already has at the top. Signed-off-by: Pham Binh <194774975+phambinhfin@users.noreply.github.com>
1ca189a to
a41ecd1
Compare
|
Rebased onto main.
|

Summary
Add an
fp8_large_headentry to the gfx942 Triton MHA forward config and selectit for FP8 at
head_dim_v == 256, wherefwd["default"]is 3.2-3.8x slower.Claims
4096q x 4096k causal on MI325X, vs today's
defaultat the same shapes.two MI325X hosts.
head_dim_v == 256and FP8 only: d255, d320, d512, bf16/fp16 atd256, and fp32/dropout all keep their current config. Above d256 the head dim
pads to 512 and this entry exceeds LDS, so it cannot widen.
_get_configis unchanged thereby construction.
Validation
Setup: 1x MI325X (gfx942),
vllm/vllm-openai-rocm:nightly-5d35ce3934a7,torch 2.13.0+rocm10.0.0, aiter at this branch via
PYTHONPATH. Before isfwd["default"], after isfwd["fp8_large_head"], same process, same GPU.Kernel
Head dim 256, 24 query heads, 4 KV heads, FP8 Q/K/V, varlen. Median of 10 after
3 warmups.
vs CK bf16 at the first shape: 58.699 -> 38.837 ms, relative error 0.0530,
matching the pre-existing FP8 path. Launch parameters change, not the math.
Grid sweep
108 configs over
BLOCK_M, BLOCK_N, num_warps, num_stages, PRELOAD_V, twoMI325X hosts, each checked against CK bf16. 72 compiled; the rest hit
OutOfResourcesatBLOCK_M=256, BLOCK_N=128.Small shapes
Same heads and dtype, varlen with equal lengths per sequence,
defaultvsfp8_large_headwith an A/Adefaultcontrol, 5 alternating rounds, medians.22 shapes, batch 1-64, seqlen 128-4096, causal and non-causal: 1.87-3.79x,
no shape slower. A/A within 0.5% except two rows (8-12%) on a shared node.
Tests
-k fp8_large_head: 9 passed on MI325X after the rebase onto main.test_mha_fwd_fp8_large_head_selectionpins the bound. Catches a widened orreordered branch.
test_mha_varlen_fp8_large_headruns d256 FP8 varlen againstattention_refand covers causal and non-causal. It catches this entry exceeding LDS.
[Triton/Gluon] [Feature] MHA: add out_dtype to the Triton forward entry point #7232's
test_mha_forward_out_dtypealready covers FP8 causal varlen d256.-k mid_head_selection: 14 skipped, unchanged (gfx950 only).Not run: the sweep on MI300X; every reachable host was busy, had a profiler
interposition inflating timings ~6x, or a full disk. A narrower A/B there gave
157.645 -> 43.193 ms at 30720q x 32768k non-causal. Re-sweep before this entry
is ever proposed as gfx942's general default.
Details
Compared with
default(BLOCK_M=128,BLOCK_N=64,num_warps=4,num_stages=1,PRELOAD_V=false),fp8_large_headkeeps the tile and changesnum_warps4→8,num_stages1→2,PRELOAD_Vfalse→true, and addsmatrix_instr_nonkdim=16andkpack=1. The speedup above is the whole entryversus
default. The 108-config sweep variesBLOCK_M,BLOCK_N,num_warps,num_stages, andPRELOAD_Vtogether; it does not isolatenum_stages.num_stages=2is the LDS bound, not a claim that it is the sole source of thegain: it double-buffers the K tile, and since
BLOCK_DMODEL_POW2 = next_power_of_2(v_head_dim), any head dim above 256pads to 512 and the two buffers need 65568 B against a 65536 B LDS limit. Hence
== 256, not>= 256— an earlier revision used>= 256and turnedd320/d384/d512 FP8 from working-but-slow into
OutOfResources.The branch sits after
dropout_or_fp32and beforesmall_head/mid_head(
head_dim_v <= 128, no overlap), following #4414 and #5858: a targeted entryrather than changing
default.Testing
Documentation
The config space has no prose docs; the JSON and the
_get_configbranch arethe only places it is described, both updated here.
Dependencies
Breaking Changes
None. The branch is additive and gated on
"fp8_large_head" in fwd_cfg, trueonly for gfx942 after this change.
PR Self-Review
Reviewed revision
a41ecd1584060b9a2de7c1ee02615df232112536Behavior and intent
On gfx942, FP8 Triton MHA forward at
head_dim_v == 256now usesfwd["fp8_large_head"]instead offwd["default"]. Versusdefaultthe entry changesnum_warps4→8,num_stages1→2,PRELOAD_Vfalse→true, and addsmatrix_instr_nonkdim=16andkpack=1. The measured speedup is for that whole entry. Every other dtype, head dim, dropout/fp32, PE path and architecture keeps its current config.Validation and unverified scope
On MI325X (gfx942), after rebasing onto main,
python3 -m pytest op_tests/triton_tests/attention/test_mha.py -k "fp8_large_head or mid_head_selection"gave 9 passed, 14 skipped. Kernel timings are in Validation above. Not run: the 108-config sweep on MI300X, a single-knob ablation ofnum_stages, and FP8 e5m2 inputs (only e4m3 was timed).PR-specific question
The only key that consumes
fp8_large_headis gfx942_get_configwith no dropout, no fp32, no PE, an FP8 dtype fromget_fp8_dtypes()andhead_dim_v == 256.test_mha_fwd_fp8_large_head_selectionpins that d255, d320, d512, d128, bf16 at d256 and dropout at d256 keep their previous config. On other architectures the test asserts the JSON has nofp8_large_headkey, so their selection is unchanged.Changed op tests
op_tests/triton_tests/attention/test_mha.py:test_mha_fwd_fp8_large_head_selectionpins the dispatch bounds above.test_mha_varlen_fp8_large_headruns d256 FP8 varlen againstattention_ref, causal and non-causal. #7232'stest_mha_forward_out_dtypealready covers FP8 causal varlen d256.op_tests/triton_tests/attention/mha_test_utils.py: shared varlen FP8 setup used by this test andtest_mha_varlen_fp8_gluon; no new cases.