[HIP] [CK] [FlyDSL] FlyDSL split-K preshuffle decode GEMM for small-M shapes (FP8 + MX, gfx950/gfx942) - #5148
johannes-graner wants to merge 9 commits into
Conversation
…fx942) + decode-fp8-latency GEMM rework Squashed for rebase onto current main. Primary focus: decode small-M split-K preshuffle path. decode-fp8-latency decode-GEMM rework rides along. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
PR title tags & labels: |
There was a problem hiding this comment.
Pull request overview
Adds new FlyDSL GEMM capabilities focused on decode/small‑M shapes: a two-pass fp32-workspace split‑K preshuffle GEMM (including blockscale + MX variants), plus a unified exact-shape BF16 decode GEMM family. The PR also wires these into tuning/AOT infrastructure, expands arch coverage (gfx942/gfx950 as described), and introduces new correctness tests.
Changes:
- Add split‑K preshuffle GEMM (workspace partials + fp32 reduce) and shared dispatch/tuner scaffolding for bpreshuffle families (a8w8 + a4w4/mxfp4).
- Add unified exact-shape BF16 decode GEMM kernels (Wave + BlockMFMA policies) and integrate decode candidates into the a16w16 tuner + AOT compilation.
- Add new FlyDSL correctness tests and update CI sharding scripts to include FlyDSL GEMM pytest-based tests (with one currently missing from the shard list).
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
op_tests/test_pretune.py |
Updates pretune expectations for the new blockscale bpreshuffle tuner script path. |
op_tests/flydsl_tests/test_flydsl_small_m_hgemm.py |
Adds runtime correctness tests (and optional perf sweep entrypoint) for small‑M BF16 HGEMM. |
op_tests/flydsl_tests/test_flydsl_preshuffle_gemm_splitk.py |
Adds correctness tests for split‑K preshuffle GEMM (epilogue + blockscale coverage). |
op_tests/flydsl_tests/test_flydsl_decode_gemm.py |
Adds correctness tests for unified BF16 decode GEMM + per-tensor FP8 decode path. |
csrc/gemm_a16w16/gemm_a16w16_tune.py |
Adds flydsl_decode tuner libtype, decode candidate policy, and optional vLLM wvSplitK comparison timing. |
csrc/ck_gemm_a8w8_bpreshuffle/gemm_a8w8_bpreshuffle_tune.py |
Adds split‑K pipeline runner support for the a8w8 bpreshuffle tuner. |
csrc/ck_gemm_a8w8_blockscale_bpreshuffle/gemm_a8w8_blockscale_bpreshuffle_tune.py |
New dedicated tuner driver for FlyDSL split‑K blockscale/mx128 bpreshuffle variants. |
csrc/ck_gemm_a4w4_blockscale/gemm_a4w4_blockscale_bpreshuffle_tune.py |
New dedicated tuner driver for FlyDSL a4w4 (mxfp4) split‑K bpreshuffle variants. |
aiter/utility/pretune.py |
Updates pretune script mapping/comments for the new blockscale bpreshuffle tuner. |
aiter/tuned_gemm.py |
Adds flydsl_decode dispatch path and strengthens FlyDSL HGEMM kernel identity checks. |
aiter/ops/shuffle.py |
Adds CDNA4 preshuffle helpers for mxfp4 weights/scales. |
aiter/ops/gemm_op_a8w8.py |
Wires FlyDSL split‑K bpreshuffle kernels into a8w8 dispatch via shared helper. |
aiter/ops/gemm_op_a4w4.py |
Adds FlyDSL split‑K dispatch branch for a4w4 (mxfp4), including inline operand preshuffle hook. |
aiter/ops/flydsl/splitk_bpreshuffle_common.py |
New shared dispatch helper for split‑K bpreshuffle kernels across a8w8/a4w4. |
aiter/ops/flydsl/kernels/tensor_shim.py |
Adds unused_tensor_arg helper and plumbs cache_modifier through buffer loads. |
aiter/ops/flydsl/kernels/splitk_hgemm.py |
Extends split‑K HGEMM kernel naming to include arch + exact N/K identity. |
aiter/ops/flydsl/kernels/preshuffle_gemm.py |
Updates preshuffle GEMM to support smaller tile_n by varying waves/threads. |
aiter/ops/flydsl/kernels/preshuffle_gemm_splitk_reduce.py |
New fp32 split‑K reduction kernel (downcast once at final store). |
aiter/ops/flydsl/kernels/preshuffle_gemm_splitk_op.py |
New driver API for the two-pass split‑K preshuffle GEMM (now used by dispatch). |
aiter/ops/flydsl/kernels/gemm_decode_wave.py |
New Wave-policy exact-shape decode GEMM implementation (BF16 + per-tensor FP8). |
aiter/ops/flydsl/kernels/gemm_decode_block_mfma.py |
New BlockMFMA-policy exact-shape BF16 decode GEMM implementation. |
aiter/ops/flydsl/gemm_tune/flydsl_splitk_bpreshuffle_tuner_common.py |
New shared tuner scaffolding for split‑K bpreshuffle tuners. |
aiter/ops/flydsl/gemm_tune/flydsl_gemm_a8w8_bpreshuffle_common.py |
Expands candidate space (adds split‑K pipeline + narrow decode tiles) and exposes split‑K blockscale/mx128 pipelines. |
aiter/ops/flydsl/gemm_tune/flydsl_gemm_a4w4_bpreshuffle_common.py |
New split‑K candidate space for a4w4/mxfp4 (gfx950-only). |
aiter/ops/flydsl/gemm_kernels.py |
Broadens GEMM APIs: adds decode GEMM entrypoints, small‑M HGEMM entrypoint, and refactors split‑K HGEMM metadata handling. |
aiter/ops/flydsl/__init__.py |
Exposes new decode GEMM/small‑M HGEMM symbols from the FlyDSL package surface. |
aiter/jit/optCompilerConfig.json |
Adds new tuner module entry for a4w4 blockscale bpreshuffle tune. |
aiter/jit/core.py |
Makes duplicate-row merge handling read-only (dedup in merged view without rewriting source CSVs). |
aiter/aot/flydsl/gemm.py |
Extends FlyDSL AOT precompile to include split‑K preshuffle GEMM, a4w4 split‑K, and decode GEMM jobs. |
.github/scripts/split_tests.sh |
Adds explicit FlyDSL GEMM pytest files to the sharded aiter test list (currently missing the split‑K preshuffle test). |
.github/scripts/aiter_test.sh |
Runs selected FlyDSL GEMM test files via pytest instead of python for correct collection. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…n CI. Wheel builds JIT-import module_aiter_core through that HIP op; parse a4w4 split-K names from the flydsl-free tuner module instead. Also require tile_n % 16 and run the split-K pytest in CI shards. Co-authored-by: Cursor <cursoragent@cursor.com>
… on N % 32. The FlyDSL mxfp4 tuner is Python-only; drop the nonexistent .cu module from optCompilerConfig. Require N divisible by 32 before shuffle_scale_w4_cdna4 in dispatch and tuning fit checks so odd-N shapes fall back to CK/asm instead of asserting. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 33 out of 34 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
csrc/ck_gemm_a8w8_blockscale_bpreshuffle/gemm_a8w8_blockscale_bpreshuffle_tune.py:86
- run_torch_blockscale() uses
view(m, k // block_k, block_k)but computesscale_kwith ceil-division and does not validate that K is a multiple of the block size. For an invalid shape this will fail with a low-signalviewerror (or silently mis-handle scale shapes). Add an explicit K%block_k check and compute scale_k from the exact divisor so failures are actionable.
block_n, block_k = BLOCK_SHAPE
m, k = x.shape
n = weight.shape[0]
scale_n = (n + block_n - 1) // block_n
scale_k = (k + block_k - 1) // block_k
That hunk came from samremes/gemm-decode, not this ticket. Restore main's duplicate-shape raise and source-CSV write-back. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Hi @johannes-graner — while validating this PR against current Several files introduced or changed by #5148 still import python3 -c "from aiter.ops.flydsl.utils import is_flydsl_available"
# ModuleNotFoundError: No module named 'aiter.ops.flydsl.utils'This also affects downstream capability checks and some of the new small-M/split-K paths. The PR head still contains When rebasing, could you either retain the helper or update all #5148-added imports to the post-#5116 |
|
Hi @andyluo7, |
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed issues in newly added FlyDSL test scripts (argparse defaults) and CI test runner timeout behavior that should be fixed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 34/35 changed files
- Comments generated: 3
- Review effort level: Lite
… decode dtype guard - aiter_test.sh: wrap FlyDSL pytest path in `timeout 60m` like other tests - flydsl decode/small-M tests: fix --dtype default (string -> list) so nargs="*" iterates dtypes - shuffle_scale_w4_cdna4: raise ValueError instead of assert (not stripped under -O) - flydsl_decode_gemm: also require BF16 input, not just output Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
It changes multiple GPU kernel families plus dispatch/tuning/AOT plumbing across many files, so it needs careful manual validation (and the review found at least one correctness guard to add).
Review details
- Files reviewed: 34/35 changed files
- Comments generated: 1
- Review effort level: Lite
| # tile_n < 64 needs fewer waves so num_acc_n stays >= 1; clamp at 4 to keep | ||
| # large tiles at the historical 256-thread block. | ||
| num_waves = 4 if tile_n >= 64 else tile_n // 16 | ||
| n_per_wave = tile_n // num_waves | ||
| num_acc_n = n_per_wave // 16 |
|
Hi @johannes-graner — one more downstream integration point from Hy4-preview FP8 TP8/C1 validation on gfx950. vLLM's correctness-preserving path splits the routed and shared experts because they use different activation/clamp semantics. That changes the small-M MXFP8 FMoE lookups from the existing combined MiniMax-M3 rows (
I tuned those six rows against the #5148 kernel family. The resulting CSV is SHA-256 Current #5148 head Would you be comfortable including the six tuned rows in that existing per-model table after I send the clean repeat/profile evidence, or do you prefer another AITER-owned configuration location? I will not hard-code these shapes in vLLM. I can provide the exact rows and per-kernel measurements once the uncontaminated rerun completes. |
|
Hi @andyluo7, Of course I can include the tuned rows. Either send them to me, or add them to the tuned csv and push directly to this branch, either is fine by me. |
# Conflicts: # aiter/aot/flydsl/gemm.py # aiter/ops/flydsl/gemm_kernels.py # aiter/ops/flydsl/kernels/small_m_hgemm.py # aiter/ops/flydsl/kernels/splitk_hgemm.py # aiter/tuned_gemm.py # csrc/gemm_a16w16/gemm_a16w16_tune.py Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new FlyDSL a4w4 split‑K dispatch path double-shuffles already-bpreshuffled weights when bpreshuffle=True, which can break existing callers and produce incorrect results.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 32/33 changed files
- Comments generated: 1
- Review effort level: Lite
| a_scale_padded[:m] = a_scale | ||
| a_scale = a_scale_padded | ||
| a_scale_shuf = shuffle_scale_w4_cdna4(a_scale).view(torch.int8) | ||
| b_shuf = shuffle_weight_w4_cdna4(WQ).view(torch.int8) |
Summary
Adds a FlyDSL split-K preshuffle GEMM tuned for decode (small-M) shapes, covering FP8 per-tensor and FP8 blockscale, plus a direct-output (split_k=1) epilogue for the whole scale-mode family. Adds MX datatype support (mxfp8, mxfp4) as correctness-validated, tunable dispatch candidates. Enables the blockscale and epilogue split-K kernel families on gfx942 in addition to gfx950. Rides along: a rework of the existing FP8 decode-GEMM dispatch/layout/AOT plumbing that this work shares infrastructure with.
What's included
gemm_decode-family split-K preshuffle GEMM kernel (aiter/ops/flydsl/kernels/preshuffle_gemm_splitk.py+ reduce/op helpers), wired into dispatch, the tuner, and AOT prebuild for both FP8 per-tensor and FP8 blockscale.split_k=1) epilogue, validated per scale mode against the FP32 oracle.op_tests/flydsl_testscoverage for the decode GEMM, split-K preshuffle GEMM, and small-M HGEMM kernels.Performance
Measured on gfx950, M in {1, 16}, N in {2048, 16384}, K=7168. "Best existing" is the best-tuned pre-existing CK/asm/FlyDSL incumbent for that shape, not a cold-dispatch heuristic fallback. Fuller benchmark data across more shapes is tracked separately.
FP8 per-tensor (this PR's split-K decode GEMM vs best-tuned existing kernel):
FP8 blockscale (best existing -> this PR):
Gains are largest at small N, the latency-bound decode regime; at large N both tables converge toward parity as the kernel approaches the HBM-bandwidth wall.
Correctness
Measured on gfx950, current
main+ FlyDSL 0.3.2. The tracked FlyDSL pytest suite passes (17/17, 0 skipped) against a torch FP32 reference. mxfp8 is exact across the tile/split sweep. mxfp4 is bit-exact on the identity case and reaches ~3e-3 max relative error on real data, with a negative control that correctly diverges.Notes