Repository navigation
Conversation
Add the call form StreamKKernel uses (one A and one B window, hot-loop flag, tail number) to comp_tdm and comp_tdm_v2. It forwards to the tuple form, so Stream-K runs the same pipeline entry as universal GEMM. V2 restates it because its operator() overloads hide V1's. comp_tdm now exposes UsePersistentKernel (non-MX problems only, as in comp_async), which StreamKKernel requires to match its partitioner. comp_tdm_v2 inherits it. StreamKKernel: - wait for the last TDM prefetch after a partial tile, which runs no epilogue, before the next tile refills the same LDS; - reject TdmEpilogue with atomic reduction (it overwrites C), the plain-GEMM-only pipelines and TDM cluster launch at compile time; - require CShuffleEpilogue or TdmEpilogue and row-major C for comp_tdm and comp_tdm_v2; - check for a gfx125 device, and with a non-TDM epilogue reject a C whose contiguous dimension is not a multiple of the block tile (the CShuffle store does not clip). Existing Stream-K, universal, grouped and multi-D kernels compile to the same device code.
TestGfx1250StreamKTdm covers 36 configs: both pipelines x atomic, linear and tree reduction x CShuffle and TDM epilogue (TDM with linear/tree only) x persistent and non-persistent, plus fp16, a 64x64 tile, the other A/B layouts and comp_tdm on eight waves. Each config runs data-parallel-only, split-K segments of 1-5 iterations, segments that cross tiles, mixed data-parallel and Stream-K, ragged K, ragged M/N, a full-device grid and a misaligned-pointer rejection. The suite is built into the gfx1250 Stream-K full and smoke targets. The smoke build keeps three atomic configs, because the emulator runs one workgroup at a time and a linear or tree tile owner would wait forever there. The legacy buffer-addressing target does not build it: that mode has no LDS transpose load for the TDM pipelines.
codegen_common.streamk_trait_reject_reason holds the Stream-K trait rules: atomic reduction needs the cshuffle epilogue, linear and tree take cshuffle or tdm, and TDM pipelines keep the no-pad rule. The codegen, expand_sweep and arch_filter all use it together with gfx1250_pipeline_reject_reason(streamk=True), which accepts only STREAMK_GFX1250_PIPELINES (comp_tdm, comp_tdm_v2) and skips the universal "epilogue=tdm" and "no persistent kernel" rules. comp_tdm_pc and comp_async stay rejected with the same reasons as before. The Stream-K codegen now emits the TDM epilogue for linear and tree reduction. Vector-width pairing (_tile_fits) follows the kernel's new C-tail check for a TDM pipeline with a CShuffle epilogue. Add test_streamk_tdm_gfx1250.py: the trait matrix against an independent oracle, the reject reasons, and agreement between codegen, expand_sweep and arch_filter, plus checks on the generated headers.
… pipelines Since #15005, UniversalGemmKernel::IsSupportedArgument runs IsCTensorSupported for a TDM pipeline with a non-TDM epilogue: a ragged contiguous C dimension needs kPadN (kPadM), and that dimension must be a multiple of the C vector size. StreamKKernel::IsSupportedArgument calls it after its TDM block, so the Stream-K copy of the C-tail check is redundant for the unpadded TDM configs (the gtest and the dispatcher never pad a TDM pipeline), and its comment, which says the universal kernel skips that check, no longer holds. Drop the copy and keep the gfx125 device check. A padded C goes through the same padded C window as the other Stream-K pipelines.
✅ All Checks Passed — Ready for Review
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🎉 All checks passed! This PR is ready for review. |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The TDM Stream-K gate still admits unsupported column-major layouts and CShuffle wave tuples that can cause compilation failures or output corruption.
4 open issues
What changed in this PR
Enables gfx1250 CK Tile Stream-K GEMM on comp_tdm and comp_tdm_v2, extending existing native Stream-K support to TDM pipelines for workloads with few output tiles and large K dimensions.
Changes:
- Adds pipeline call adapters, persistent-kernel support, synchronization, and kernel compatibility checks.
- Shares dispatcher acceptance rules and enables TDM epilogues for linear/tree reduction.
- Adds GPU regression and emulator-smoke coverage, CPU dispatcher tests, and a release note.
| File | Description |
|---|---|
projects/composablekernel/tile_engine/ops/gemm/gemm_vector_fallback.py |
Adds the contiguous-C tile check for TDM with non-TDM epilogues. |
projects/composablekernel/test/ck_tile/gemm_streamk/test_gemm_streamk_tdm_gfx1250_wmma.cpp |
Adds TDM Stream-K GPU coverage across pipelines, reductions, persistence, and tails. |
projects/composablekernel/test/ck_tile/gemm_streamk/CMakeLists.txt |
Includes the new suite in builtin and smoke targets, excluding legacy addressing. |
projects/composablekernel/include/ck_tile/ops/gemm/pipeline/gemm_pipeline_ag_bg_cr_comp_tdm_v2.hpp |
Adds V2’s runtime Stream-K call adapter. |
projects/composablekernel/include/ck_tile/ops/gemm/pipeline/gemm_pipeline_ag_bg_cr_comp_tdm_v1.hpp |
Adds the persistent trait and runtime Stream-K call adapter. |
projects/composablekernel/include/ck_tile/ops/gemm/kernel/streamk_gemm/streamk_gemm_kernel.hpp |
Adds TDM compatibility checks, device validation, and prefetch draining. |
projects/composablekernel/include/ck_tile/ops/gemm/kernel/grouped_gemm_kernel.hpp |
Removes an outdated comment about TDM persistent traits; no functional change. |
projects/composablekernel/dispatcher/tests/test_streamk_tdm_gfx1250.py |
Adds CPU rule-matrix, codegen-equivalence, pairing, and generated-header tests. |
projects/composablekernel/dispatcher/tests/test_gfx1250_tdm_pipelines.py |
Updates expected Stream-K pipeline coverage. |
projects/composablekernel/dispatcher/tests/CMakeLists.txt |
Registers the new CPU regression suite with CTest. |
projects/composablekernel/dispatcher/python/gemm_utils.py |
Applies shared Stream-K rules during sweep expansion. |
projects/composablekernel/dispatcher/codegen/unified_gemm_codegen.py |
Expands supported reduction/epilogue combinations and emits TDM epilogues. |
projects/composablekernel/dispatcher/codegen/codegen_common.py |
Centralizes Stream-K trait rules and the gfx1250 pipeline allowlist. |
projects/composablekernel/dispatcher/codegen/arch_filter.py |
Applies the shared gfx1250 gate to Stream-K configurations. |
projects/composablekernel/CHANGELOG.md |
Documents the new TDM Stream-K support and restrictions. |
Review effort: Max
Comment on lines
+1596
to
+1597
| if streamk and pipeline not in STREAMK_GFX1250_PIPELINES: | ||
| return f"pipeline={pipeline} is not supported for stream_k" |
| if epilogue != "tdm": | ||
| # StreamKKernel takes a TDM pipeline with either epilogue and persistent or not; | ||
| # streamk_trait_reject_reason decides the epilogue per reduction strategy. | ||
| if not streamk and epilogue != "tdm": |
| # comp_tdm and comp_tdm_v2 are the gfx1250-only pipelines StreamKKernel has been | ||
| # validated with. | ||
| STREAMK_REDUCTION_STRATEGIES = ("atomic", "linear", "tree") | ||
| STREAMK_GFX1250_PIPELINES = ("comp_tdm", "comp_tdm_v2") |
| if cfg.epilogue == "tdm": | ||
| return True | ||
| if cfg.layout[2] == "r": | ||
| return dims["n"] % cfg.tile_n == 0 |
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.


JIRA ID: AICK-2558
Builds on #12340 (native gfx1250 Stream-K) and #13975 (comp_tdm_pc bridge), both in
develop. Independent of #14962 (Stream-K for comp_tdm_pc): either PR can merge first, see "Relation to other PRs". The remaining pipelines are in the follow-up TODO list at the end.Motivation
On gfx1250, Stream-K only runs the mem/compv3/compv4 pipelines. The TDM pipelines are the fastest universal GEMM pipelines there, but
StreamKKernelcould not host them:StreamKKernelcalls a pipeline.UsePersistentKernel, andStreamKKernelrequires it to match the tile partitioner.stream_kand only builds the cshuffle epilogue.The shapes Stream-K is meant for (small M x N, very large K) gain the most. On H (crr 192x448x393216) and M (crr 118x102x368640) the best existing Stream-K kernels reach 228.9 and 36.8 TFLOPS, and the best universal kernels 30.1 and 3.27 TFLOPS. Stream-K on comp_tdm_v2 reaches 297.2 and 64.3 TFLOPS.
Changes
Pipelines (comp_tdm, comp_tdm_v2)
operator()(a_window, b_window, num_loop, has_hot_loop, tail_number, p_smem), enabled only for non-tuple windows. It wraps the windows in tuples and forwards to the existing tuple form, so Stream-K runs the same pipeline entry as universal GEMM (hot loop and tail are derived fromnum_loopthe same way). comp_tdm_v2 restates it because itsoperator()overloads hide comp_tdm's.UsePersistentKernel = Traits::UsePersistentKernel && !MX, as in comp_async. comp_tdm_v2 inherits it.Kernel (
StreamKKernel)s_wait_tensorcnt<0>()) before the next tile refills the same LDS. A workgroup that only stores a partial tile runs no epilogue, so nothing else waits for it there. comp_tdm_pc (wavelet) is not affected.IsSupportedArgument, for TDM pipelines: check for a gfx125 device (the TDM instructions are no-ops elsewhere). With a non-TDM epilogue, also reject a C whose contiguous dimension is not a multiple of the block tile.UniversalGemmKernelskips its tile checks for TDM pipelines because the TDM loads clip, but the CShuffle store does not. Without this check my prototype gave wrong results on N=448 and crashed on N=102.grouped_gemm_kernel.hpp: removed a comment that said the TDM pipelines do not defineUsePersistentKernel.Dispatcher
codegen_common.streamk_trait_reject_reason(pipeline, epilogue, reduction, pads): the one Stream-K trait rule set. Atomic needscshuffle; linear and tree takecshuffleortdm; TDM pipelines keep the no-pad rule; gfx1250-only pipelines outsideSTREAMK_GFX1250_PIPELINES = ("comp_tdm", "comp_tdm_v2")are rejected.gfx1250_pipeline_reject_reason(..., streamk=True): accepts onlySTREAMK_GFX1250_PIPELINESand skips the universal "requires epilogue=tdm" and "no persistent kernel" rules. The intrawave, exact-gfx1250, pad and comp_tdm_v2 4-wave rules stay.unified_gemm_codegen.py(STREAM_K branch),gemm_utils.expand_sweepandarch_filter(GEMM_STREAMK) all use these two functions, so codegen, sweep expansion and arch filtering agree. The Stream-K codegen now emits the TDM epilogue for linear and tree.tile_engine/ops/gemm/gemm_vector_fallback._tile_fits: a TDM pipeline with a non-TDM epilogue needs the contiguous C extent to be a tile multiple, the same as the kernel check above.stream_k, with the same reason text as before. Other variants and the compv3/compv4/mem Stream-K kernel set are unchanged.I copied the gate design from #14962's dispatcher change, so the two PRs differ only in the pipeline tuple.
Tests
test/ck_tile/gemm_streamk/test_gemm_streamk_tdm_gfx1250_wmma.cpp(TestGfx1250StreamKTdm), 36 configs. The core is bf16 row/col/row with a 128x128x64 tile: comp_tdm and comp_tdm_v2 x {atomic + CShuffle, linear + CShuffle/TDM, tree + CShuffle/TDM} x persistent and non-persistent. On top: fp16, a 64x64x64 tile, col/row, row/row and col/col A/B, and comp_tdm on eight waves (4x2x1, 2x4x1).test_ck_tile_streamk_gfx1250_wmma(REGRESSION_TESTS, 288 new tests) and_smoketargets. The smoke build keeps 3 atomic-only configs (21 tests), because the emulator runs one workgroup at a time and a linear or tree tile owner would wait forever there (feat(ck-tile): enable gfx1250 GEMM Stream-K reductions #12340's split). The_legacytarget does not build it: legacy buffer addressing has no LDS transpose load for the TDM pipelines, which is already the case ondevelop.dispatcher/tests/test_streamk_tdm_gfx1250.py(11 tests, 951 subtests), registered indispatcher/tests/CMakeLists.txt. It checks the full pipeline x epilogue x reduction x pads x persistent x waves matrix against an independent oracle and the reject reasons. It runs the real codegen and checks it againstexpand_sweepandarch_filter, then checks the generated headers.test_gfx1250_tdm_pipelines.py: the Stream-K golden test now expects comp_tdm and comp_tdm_v2. It also passes whenSTREAMK_GFX1250_PIPELINESalso contains comp_tdm_pc (after feat(ck_tile): Enable Stream-K for Producer Consumer pipeline #14962).Validation
The main runs were on a gfx1250 A0 board (asicRevision 0, ROCm 10.2, clang bdc35841c97) and the gtests were repeated on a B0 board (asicRevision 1, 96-CU compute partition, ROCm 10.2, clang c7ceccf9a57), building with the Jenkins flags:
BUILD_DEV=On,-Werror,-O3,GPU_TARGETS=gfx1250. All builds finished with 0 warnings.gtests (A0 board):
test_ck_tile_streamk_gfx1250_wmma: 379/379 (288 new + 91 existing)._smoke: 34/34 (21 new)._legacy: 91/91.--gtest_repeat=5: 5 x 288 passed, 0 failed.develop.gtests (B0 board, asicRevision 1, 96-CU compute partition, ROCm 10.2 clang c7ceccf9a57):
test_ck_tile_streamk_gfx1250_wmma: 379/379;--gtest_repeat=3: 1137/1137._smoke: 34/34; repeat 3: 102/102._legacy: 91/91; repeat 3: 273/273.-persistent=0/1for comp_tdm and comp_tdm_v2, fp16 and bf16, plus 1000^3. All runs report "GPU verification result is: correct".Emulator (Jenkins gfx1250 smoke path):
HSA_MODEL_LIB=/libhsakmtmodel.so,HSA_MODEL_TOPOLOGY=/topology/mi450,ctest -L SMOKE_TEST -R streamk: 1/1 passed in 66 s, with no deadlock. The 21 new atomic tests take about 28 s.SMOKE_TESTholds only the_smoketarget. The linear/tree suites areREGRESSION_TEST.No existing kernel changed. I compared device-only gfx1250 assembly between
developand this branch:Dispatcher on the GPU, with #10919 applied (23bf4ae):
streamk_gemm_full_benchmark.pyend to end on the control shape: 20/20 verified.Performance: bf16, 5 interleaved A/B rounds, warmup 50, repeat 100. The table compares the best new kernel with the best existing Stream-K kernel and the best universal kernel. "Rounds" counts the rounds where the new kernel was faster. The timing comes from the bridge build before the last review fixes; those fixes added only compile-time asserts, host-side checks and comments.
comp_tdm (V1) matches V2 on H, A and control, but reaches only 0.74x of V2 on G and 0.83x on J.
CPU Python: I ran every
test_*.pyunderdispatcher/testsandtile_engine. Ondevelop: 2831 passed, 0 failed, 139 skipped. On this branch: 2842 passed, 0 failed, 139 skipped. The 11 extra are the new file. No shared file changed its result.All C++ changes pass clang-format 18.1.4, and all added text is ASCII.
Limitations
UsePersistentKernelflag: a universal or grouped kernel built with persistent traits now takes the persistent entry with these pipelines. All current universal, grouped, MX, multi-D and quant TDM users are non-persistent. Their device code is unchanged and their tests pass. Grouped GEMM still rejects a persistent TDM pipeline with its existing static_assert.developas well, and its device code is identical, so it is unrelated to this PR.Relation to other PRs
feat(ck_tile): Enable Stream-K for Producer Consumer pipeline #14962 (draft, Stream-K for comp_tdm_pc): independent. I left alone the call sites it rewrites (
RunGemm, the linear/tree call, the waveletRunGemmPipeline) and the Stream-K test util. A trial merge against its head (ab8ab43) gives 4 small textual conflicts:streamk_gemm_kernel.hpp: both PRs add a block at the top ofIsSupportedArgument. Keep both (ours first) and drop our duplicate device check.codegen_common.py: makeSTREAMK_GFX1250_PIPELINESthe union("comp_tdm", "comp_tdm_v2", "comp_tdm_pc")and merge the comment.test_gfx1250_tdm_pipelines.py, Stream-K golden test: combine both bodies, keeping feat(ck_tile): Enable Stream-K for Producer Consumer pipeline #14962's comp_tdm_pc persistent check.gemm_vector_fallback.py: one docstring line; either side works.With the union resolved our tests pass. Two feat(ck_tile): Enable Stream-K for Producer Consumer pipeline #14962 tests (
test_only_comp_tdm_pc_among_gfx1250_pipelines,test_gfx1250_gate_for_stream_k) assert that comp_tdm and comp_tdm_v2 are rejected and need updating.feat(ck-tile): enable gfx1250 Stream-K Dispatcher-Bridge #10919 (gfx1250 Stream-K dispatcher bridge): no conflicts. I ran the bridge validation above with it applied.
fix(ck-tile): run misaligned Stream-K problems through the vector-width fallback (gfx1250) #14163 (misaligned Stream-K through the vector-width fallback): one conflict in the
unified_gemm_codegen.pySTREAM_K loop. Keep our per-strategy loop and add fix(ck-tile): run misaligned Stream-K problems through the vector-width fallback (gfx1250) #14163'sstreamk_atomic_c_reject_reasoncheck afterstreamk_trait_reject_reason. Its other conflicts already exist againstdevelop.Follow-up TODO
Remaining pipelines:
STREAMK_GFX1250_PIPELINESthe union and updates the tests that assert the other pipelines are rejected.kPlainGemmOnly), whichStreamKKernelnow rejects at compile time. Needs the same Stream-K call form, a Stream-K exception to the plain-GEMM-only rule, tests, and the dispatcher bridge.Other follow-ups from this work:
UniversalGemmKernelcheck;epilogue_can_accumulate_vassert;RunTilePipeline;test_gemm_streamk_util.hppfixture.Checklist