Skip to content

feat(ck-tile): add dispatcher correctness and performance CI lanes for gfx942/gfx950 - #10897

Merged
ThruptiRajLakshmanaGowda merged 58 commits into
developfrom
users/tlakshma/ck/dispatcher_ci
Sep 18, 2026
Merged

ThruptiRajLakshmanaGowda merged 58 commits into
developfrom
users/tlakshma/ck/dispatcher_ci

Conversation

@ThruptiRajLakshmanaGowda

@ThruptiRajLakshmanaGowda ThruptiRajLakshmanaGowda commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

ISSUE ID : AICK-2170

A change to the CK-Tile dispatcher bridge or codegen can break numeric correctness,
kernel build, or kernel launch for any of the 13 bridged GEMM operators, and today
nothing catches it until someone runs the tests by hand. Three operators
(stream-K, aquant, abquant) had no GPU correctness test at all, and four more were
registered in ctest but never invoked from CI.

This adds two opt-in Jenkins lanes that fan out across gfx942 and gfx950 and cover
every operator with a bridge on develop, plus the missing tests. Both parameters
default to OFF, so no existing CI run gets slower.

Dependencies

Depends on #11591 — fix(ck-tile): guard the gfx1250 unscaled WMMA builtin behind __gfx1250__.

ck_tile/ops/gemm.hpp does not compile on any non-gfx1250 target on current
develop (19 errors, in both the host and the device pass), which breaks four of the
dispatcher GPU correctness tests this PR adds. That fix is unrelated to this change and
is split out into its own PR. Default CI here is unaffected — both lanes are
defaultValue: false — but Test Plan steps 1, 2 and 4 will not pass until #11591 merges.

Technical Details

1. RUN_DISPATCHER_CORRECTNESS_TESTS — JIT-compiled kernels vs. host reference

Covers all 13 operators rather than a representative sample: a developer touching
the bridge needs signal on all of them, and a lane covering four cannot give that.
Cost is held down by the search budget instead — --budget 64 for the standard
sweep, --budget 16 per variant sweep.

gfx942 gfx950
shared gemm_universal sweep + parity, grouped, multi_d (4 layouts), multi_abd, batched_gemm, batched_contraction (fp16+bf16+fp32), stream_k, rowcolquant, tensorquant, aquant, abquant same
arch-only — mx_gemm, bquant C4 (fp8/bf8), C (fp8i4/bf8i4), H3 (mx_*)

Only two things stay gfx950-only, both for ISA reasons rather than policy. mx_gemm
needs the scale-MFMA builtins; it also cannot join the --variant sweep at all,
because mx_gemm_utils exposes only default_fp8_config() / default_fp4_config()
and never plugs into expand_sweep. The bquant H3 (mx_*) configs need the same
builtins. bquant's C4/C paths are held to gfx950 for a softer reason: its config
builders are arch-aware now, so the gate is pending one validating gfx942 run rather
than a known defect. Everything else — including
stream-K and all three quant operators — was widened to run on gfx942 as well over
the course of this branch. Both rationales are recorded inline in ck.groovy.

There is deliberately no gfx1201 stage: gemm_utils._SUPPORTED_ARCHES excludes
it, and widening that guard does not help, because every warp tile in
default_ci_config.json is 64 wide while RDNA4 is warp_size 32, so all 16 strata
enumerate 0 configs and the runner exits 1 on "no configs to run".

One narrowed surface is documented rather than closed: grouped_gemm_{a,ab,b}quant
run only on rcr, because all three config builders hardcode layout="rcr" and the
ctypes libs assert packed rcr strides.

2. RUN_DISPATCHER_PERF_TESTS — ahead-of-time tile_engine instances

Smoke-tier benchmark covering the same 13 operators as the correctness lane, so
the AOT instance path gets the same operator coverage the JIT path gets. The two are
gated separately and neither substitutes for the other: correctness JIT-builds each
config with hipcc and checks it against a host reference, while this lane exercises
tile_engine's codegen, instance builder and benchmark harness.

One dtype, one layout, one problem size, and a fixed 64 AOT instances per operator.

gfx942 gfx950
fp16 / rcr gemm_universal, batched_gemm, batched_contraction, gemm_streamk, grouped_gemm gemm_streamk
fp16 / rcrr gemm_multi_d, gemm_multi_abd —
fp8 / rcr grouped_gemm_rowcolquant, grouped_gemm_tensorquant gemm_aquant, gemm_bquant, gemm_abquant, mx_gemm

Three details that are load-bearing rather than incidental:

  • The per-op cap is explicit, not derived. TILE_ENGINE_SAMPLING_TIER is a
    total budget split evenly across every op with a non-empty <OP>_DATATYPE
    (ops/gemm/CMakeLists.txt:16-23), so adding operators silently shrinks the coverage
    of the ones already there — gfx942 alone would have gone from 125 to 55 instances
    per op. Pinning <OP>_MAX_INSTANCES uses the first-class override path (same file,
    :50-59) and keeps lane cost fixed and independent of how many ops the lane builds.
    The tier is still passed, because each op also forwards it to the sampler as
    --tier to select the sampling strategy.
  • One dtype and one layout per op is not just smoke sizing. The per-op budget is
    divided again across (dtype × layout) combos with integer truncation, so a
    multi-combo op can floor a combo to zero instances and build nothing.
  • gemm_multi_d and gemm_multi_abd take 4-character layouts (A, B, D, E).
    Passing the rcr the other ops use is a parse error in the instance builder, not a
    narrower selection.

mx_gemm cannot leave the gfx950 branch: its CMakeLists filters targets with a
literal regex, target MATCHES "^gfx950", so on any other arch
benchmark_mx_gemm_all is never created and ninja fails on an unknown target rather
than skipping. It also has no fp16 path.

gemm_streamk builds on both arches. DESIRED_TARGETS was widened to include gfx950
earlier on this branch, but that CMake change is the one part that could not be
exercised locally; this lane is its first real confirmation, and it matches the
correctness lane, which already runs stream-K on both. If the gfx950 AOT build turns
out to be broken, that DESIRED_TARGETS line is revertible on its own without
touching the lane.

3. New search-space runner — dispatcher/tests/test_gemm_search_space.py

One runner covering every variant expand_sweep understands (standard, grouped,
multi_d, multi_abd, stream_k), selected with --variant — they share the same
enumerate/sample/build/report machinery and differ only in which Gpu*Runner to
drive and how the numpy reference is computed.

It enumerates the GemmKernelConfig space against tile_engine's
default_ci_config.json, samples a budget-limited subset with a daily rotating seed
per (dtype, layout) stratum — so even budget 64 spreads ~4 configs across all 16
combinations rather than testing one deeply — compiles via the bridge, runs on GPU,
and reports correctness + TFLOPS as JSON.

This is the dispatcher equivalent of tile_engine's per-op benchmark scripts, with one
deliberate difference: those never verify numerics and always exit 0. This one
validates every kernel against a numpy reference and exits 1 on any mismatch or
build failure
.

4. New GPU correctness tests

  • test_streamk_gpu_correctness.py — all three reduction strategies. The shared
    sweep only ever builds atomic (default_ci_config.json carries no streamk_config,
    so expand_sweep falls back to ["atomic"]), leaving linear/tree unverified
    through the ctypes bridge. Two shapes: an occupancy-bound 4096³ case, and a
    Stream-K-heavy M=N=128, K=8192 case that only linear/tree can assert tightly,
    since estimate_num_wgs_per_tile is gated on Atomic and returns 1 otherwise.
    Tolerance is CK's own split-K-aware element-wise bound, ported from
    streamk_driver_common.hpp + check_err.hpp.
  • test_aquant_gpu_correctness.py — A-side per-(m,k)-group scales; fp8, bf8, and a
    tiled shape spanning a 4×4 output-tile grid that the 1×1-tile cases cannot catch.
  • test_abquant_gpu_correctness.py — scales on both operands, completing the quant
    trio; fp8 + bf8 on compv3, plus the gfx950-native eightwaves pipeline (192×256
    tiles, TransposeC=True, bquant_group_n=128), a different MFMA path and B-scale
    granularity than compv3.

All four quant/stream-K bridge tests are now registered in ctest with
SKIP_RETURN_CODE 77. They intentionally take no --gfx from CMake: each
hipcc-compiles with --offload-arch and then runs, so the arch must match the
physical GPU, and the configured GPU_TARGETS may legitimately differ from the card
in the box.

5. Skip semantics — exit 77 instead of exit 0

The script-style tests previously returned 0 when no GPU was present, so a CPU-only
runner reported a green PASS for a test that never touched the GPU. They now return 77,
which ctest maps to skipped via SKIP_RETURN_CODE and the Jenkins lane maps via a
run_ok shell helper. Only 77 is swallowed — any other non-zero still fails the lane.
This matters because execute_cmd is one &&-joined string: without it, a single
unsupported arch would abort the lane and every later operator would silently never run.

--gfx also loses its hardcoded gfx950 default in the quant tests, so "user asked for
gfx950" stays distinguishable from "we are on an unrelated box" and the skip can fire.

6. Fixes and coverage extensions found while wiring this up

  • gemm_utils.expand_sweep: skip non-cshuffle epilogues for stream_k — the codegen
    emits only cshuffle for that variant, so those configs surfaced as spurious build
    failures.
  • grouped_gemm_aquant_utils._compile_aquant_kernel: add the arch defines
    (CK_USE_OCP_FP8, CK_TILE_USE_OCP_FP8, CK_USE_NATIVE_MX_SUPPORT,
    CK_GFX950_SUPPORT) that CMake normally injects but the standalone hipcc path omitted,
    matching the bquant path. gfx942 is FNUZ, gfx950 is OCP; without this the encoded
    inputs and the compiled kernel disagree and the device returns NaN.
  • tile_engine/ops/gemm_streamk/CMakeLists.txt: widen AOT DESIRED_TARGETS to include
    gfx950, and correct the skip warning, which still listed only (gfx90a, gfx942)
    afterwards.
  • streamk_gemm_ctypes_lib.cpp: correct a stale comment claiming the lib is Atomic-only.
    The strategy is a codegen-time template constant and GetWorkSpaceSize returns 0 for
    Atomic / non-zero for Linear/Tree, so the one allocate-and-launch path serves all three.
  • Widened two existing GPU tests that were narrower than the operator they cover:
    batched-contraction now exercises bf16 and fp32 alongside fp16, and the Multi-D GEMM
    test exercises all four layouts rather than one.
  • Dockerfile: add ml_dtypes, required for host-side fp8/bf8 encoding.

Both lanes archive their per-kernel JSON from a finally block — a red lane is exactly
when that artifact is worth having, and buildAndTest throws on failure.

Test Plan

  1. gfx942 correctness lane — RUN_DISPATCHER_CORRECTNESS_TESTS=true: the
    gemm_universal sweep at budget 64 across all 16 dtype × layout strata, the parity
    test, the grouped/multi_d/multi_abd/batched_gemm/batched_contraction/rowcolquant/
    tensorquant/aquant/abquant/bquant bridge tests, the grouped/multi_d/multi_abd/
    stream_k variant sweeps at budget 16, and the stream-K registry + bridge tests.
  2. gfx950 correctness lane — the same set, plus mx_gemm and the bquant H3
    (mx_*) configs.
  3. Both perf lanes — RUN_DISPATCHER_PERF_TESTS=true on gfx942 and gfx950; confirm
    all 9 gfx942 and all 5 gfx950 benchmark_*_all targets build, every script runs, and
    each *_results.json lands as an archived artifact. The gfx950 gemm_streamk result
    is the specific new signal — it is the first exercise of the DESIRED_TARGETS
    widening.
  4. Skip path — run the ctest suite on a non-gfx942/gfx950 box and confirm the
    arch-gated tests report Skipped, not Passed and not Failed.
  5. Artifact archiving — confirm dispatcher_*_results.json and *_results.json
    appear as build artifacts, including on a deliberately failed run.

Test Result

  • Will be run on CI

Submission Checklist

@therock-pr-bot

therock-pr-bot Bot commented Aug 17, 2026 •

Copy link
Copy Markdown

✅ All Policy Checks Passed

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

🎉 All policy checks passed!

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

therock-pr-bot Bot commented Aug 17, 2026 •

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

@ThruptiRajLakshmanaGowda ThruptiRajLakshmanaGowda changed the title Users/tlakshma/ck/dispatcher ci feat(ck-tile): add dispatcher CI stage for universal GEMM correctness and performance Aug 18, 2026
@ThruptiRajLakshmanaGowda
ThruptiRajLakshmanaGowda marked this pull request as ready for review August 19, 2026 04:38
@ThruptiRajLakshmanaGowda
ThruptiRajLakshmanaGowda requested a review from a team as a code owner August 19, 2026 04:38
@ThruptiRajLakshmanaGowda
ThruptiRajLakshmanaGowda requested review from brockhargreaves-amd and a lite review from Copilot August 19, 2026 04:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds CI coverage for the CK-Tile universal GEMM dispatcher by introducing new Jenkins pipeline stages and a Python-based, budget-limited search-space runner that builds and validates sampled dispatcher GEMM configurations.

Changes:

  • Extend projects/composablekernel/Jenkinsfile with new boolean parameters and parallel stages to run dispatcher-focused tests.
  • Add dispatcher CI entrypoints in groovy/vars/ck.groovy to configure/build dispatcher artifacts and invoke the new runner and correctness tests.
  • Introduce dispatcher/tests/test_gemm_search_space.py to enumerate, sample, build, run, and emit JSON results for dispatcher GEMM configs.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
projects/composablekernel/Jenkinsfile Adds CI parameters and stages for running dispatcher GEMM and universal dispatcher tests on specific GPUs.
projects/composablekernel/groovy/vars/ck.groovy Adds Jenkins shared-library helpers to build dispatcher components and run/archive dispatcher test outputs.
projects/composablekernel/dispatcher/tests/test_gemm_search_space.py New Python runner for stratified sampling of universal GEMM configs with correctness/perf reporting to JSON.
Suppressed comments (1)

projects/composablekernel/dispatcher/tests/test_gemm_search_space.py:74

  • _emulate() currently rounds fp8/bf8 inputs as fp16, which makes the CPU reference diverge from what the GPU kernel actually multiplies. That can hide correctness issues for fp8/bf8. Use the same fp8/bf8 encode/decode path as the existing dispatcher parity tests so the reference matches the kernel’s storage dtype.
def _emulate(x: np.ndarray, dtype: str) -> np.ndarray:
    if dtype == "bf16":
        u32 = np.ascontiguousarray(x, dtype=np.float32).view(np.uint32)
        rounded = (u32 + ((u32 >> 16) & 1) + np.uint32(0x7FFF)) >> 16
        return (rounded.astype(np.uint32) << 16).view(np.float32)
    return x.astype(np.float16).astype(np.float32)

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread projects/composablekernel/Jenkinsfile Resolved
@ozturkosu
ozturkosu self-requested a review August 19, 2026 07:44
@ThruptiRajLakshmanaGowda ThruptiRajLakshmanaGowda changed the title feat(ck-tile): add dispatcher CI stage for universal GEMM correctness and performance feat(ck-tile): add dispatcher CI stage for GEMM correctness and performance Aug 19, 2026
ThruptiRajLakshmanaGowda and others added 12 commits August 19, 2026 15:23
Adds a new 'Run DISPATCHER Tests' Jenkins stage parallel to the existing
tile engine stages, targeting gfx942 with dispatcher_gemm_lib build and
the tile_engine_dispatcher_bridge.py sweep runner.

- Jenkinsfile: add RUN_DISPATCHER_TESTS bool param (default OFF)
- Jenkinsfile: wire RUN_DISPATCHER_TESTS into the daily 22:00 cron
- Jenkinsfile: add 'Run DISPATCHER Tests' stage on gfx942
- ck.groovy: add runDispatcherTests(arch, compiler) with DISPATCHER_RULE_SET=tests

Co-Authored-By: Claude <noreply@anthropic.com>
Replaces the 4-algo hardcoded sweep with a budget-limited stratified
search over the full (dtype × layout × tile × trait) space, matching
tile_engine's daily-tier coverage for universal GEMM.

New files:
- dispatcher/codegen/gemm_search_space.py: enumerate_configs wraps
  expand_sweep across all (dtype, layout) strata; sample_configs does
  stratified budget-limited sampling with daily rotating seed.
- dispatcher/tests/run_gemm_search_space.py: CLI runner -- enumerate,
  sample, parallel JIT build, GPU run, correctness check, JSON results.

Updated:
- dispatcher/CMakeLists.txt: add DISPATCHER_GEMM_BUDGET cache var (500).
- groovy/vars/ck.groovy: runDispatcherTests now calls
  run_gemm_search_space.py with --budget 500, all dtypes and layouts,
  writing dispatcher_gemm_results.json as an artifact.

Coverage after this change: ~500 stratified configs across
fp16/bf16/fp8/bf8 × rcr/rrr/crr/ccr (vs 4 hardcoded before).

Co-Authored-By: Claude <noreply@anthropic.com>
…a file

gemm_search_space.py was an unnecessary indirection -- tile engine has no
equivalent; sampling lives inside the instance builder itself. Move the
_daily_seed and _sample helpers directly into run_gemm_search_space.py
and call expand_sweep from gemm_utils directly, matching the tile engine
pattern more closely.

Co-Authored-By: Claude <noreply@anthropic.com>
Budget is passed directly as --budget CLI arg to run_gemm_search_space.py
from the groovy script; CMake is not in the loop for sampling, so the
cache variable was dead code.

Co-Authored-By: Claude <noreply@anthropic.com>
Three fixes:
1. Remove spurious 'cd build &&' -- cmake_build already cds into build/
   before running execute_cmd; the extra cd would fail (build/build/).
2. Add archiveArtifacts for dispatcher_gemm_results.json to match
   tile_engine's JSON artifact pattern.
3. Add --warmup/--repeat args to run_gemm_search_space.py (default 5/5)
   and wire them in from the groovy call, matching tile_engine convention.

Co-Authored-By: Claude <noreply@anthropic.com>
Prefer the values already computed by GpuGemmRunner over recomputing them
manually. Fall back to manual computation only when result.max_rel is None
(GpuGemmRunner does not populate it; GpuMultiABDRunner does).

Co-Authored-By: Claude <noreply@anthropic.com>
CI requires changed code files to have an accompanying test file named
test_<name>.py. Rename the runner to match the convention.

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix script name: run_gemm_search_space.py -> test_gemm_search_space.py
- Build ck_tile_dispatcher (static lib) alongside dispatcher_gemm_lib so
  runtime-compiled tests can link against it
- Add test_gemm_parity.py, test_batched_gemm_gpu_correctness.py, and
  test_batched_contraction_gpu_correctness.py to the gfx942 dispatcher stage
- Add new runDispatcherTestsGfx950 groovy function and a parallel Jenkinsfile
  stage that runs test_bquant_gpu_correctness.py on gfx950

Co-Authored-By: Claude <noreply@anthropic.com>
Adds RUN_DISPATCHER_GEMM_UNIVERSAL_TESTS parameter and a new
"Run DISPATCHER_GEMM_UNIVERSAL Tests on gfx942" stage that builds and
runs only the gemm_universal benchmark (fp8/fp16/bf8/bf16, rcr/rrr/crr/ccr
layouts) via the new ck.runDispatcherGemmUniversalTests() groovy function.

Co-Authored-By: Claude <noreply@anthropic.com>
…CHER_GEMM_TESTS

Renames the parameter and stage to RUN_DISPATCHER_GEMM_TESTS /
runDispatcherGemmTests to allow future expansion beyond gemm_universal.

Co-Authored-By: Claude <noreply@anthropic.com>
…batched_contraction

Adds batched_gemm and batched_contraction to the RUN_DISPATCHER_GEMM_TESTS
stage on gfx942: builds the tile engine benchmarks alongside dispatcher
bindings, runs the benchmark scripts, and runs the GPU correctness tests for
both operators. bquant is intentionally excluded (gfx950-only).

Co-Authored-By: Claude <noreply@anthropic.com>
…eam_k, mx_gemm

Before this, the dispatcher CI covered gemm_universal, batched_gemm,
batched_contraction and bquant. Everything else in the dispatcher shipped with
only CPU-side/mocked unit tests, so a numeric regression in those bridges could
reach develop undetected.

Rather than fork five near-identical runners, generalize the existing
test_gemm_search_space.py with --variant {standard,grouped,multi_d,multi_abd,
stream_k}: expand_sweep, _ctypes_source_name and setup_multiple_gemm_dispatchers
already route every variant, so only the Gpu*Runner choice and the numpy
reference differ per variant. This keeps one sampling/reporting/JSON path
instead of five that drift.

The CI mirrors the shape of the tile_engine benchmark stages (per-op runner,
--warmup/--repeat/--json, per-arch stages, archived JSON) but deliberately not
their failure semantics: the tile_engine *_benchmark.py scripts never pass
--verify and return 0 unconditionally, so copying them literally would give
five permanently-green lanes. These lanes validate and exit 1 on mismatch.

multi_d runs the PassThrough epilogue. default_ci_config.json carries no
multi_d_config, so expand_sweep would otherwise fall back to MultiDAdd; the new
--elementwise-op flag pins it, and _verify reads cfg.elementwise_op so kernel
and reference always agree on the op. Note the similarly named
cde_elementwise_op is the multi_abd field, not this one.

mx_gemm has no expand_sweep -- mx_gemm_utils exposes only default_fp8_config()
/default_fp4_config() -- so it cannot join the sweep and instead runs the
two-config smoke test merged in #10132 on gfx950.

Also fixed along the way:

- expand_sweep emitted stream_k configs with non-cshuffle epilogues, which the
  codegen then skips, surfacing later as a spurious build failure. Gate them.
- test_batched_{gemm,contraction}_gpu_correctness.py returned exit 0 with no
  GPU while their add_test entries carried no SKIP_RETURN_CODE, so a CPU-only
  runner reported a green PASS for a test that never ran. They now exit 77 and
  the ctest properties record it as a skip. test_bquant gets the same 77 path
  plus a real arch gate.
- ml_dtypes was in no CI dependency manifest, yet every dispatcher lane sweeps
  bf16/fp8/bf8, which raises "requires the 'ml_dtypes' package" and counts as a
  failure. Add it to the Docker image.

Arch matrix is bounded by the tile_engine CMake guards: stream_k is gfx942-only
(TODO: add gfx950 in the stream-K CMakeLists), mx_gemm is gfx950-only. gfx1201
is excluded -- expand_sweep yields zero configs for it in all 16 dtype x layout
strata because RDNA4 is warp_size 32 and the config's warp tiles are all 64
wide, so such a lane could only run red.

Verified on gfx90a: all five variants pass (20/20 kernels, exit 0), each lane
confirmed able to go red (_RTOL 1e-12 -> exit 1) and to skip (exit 77).
mx_gemm is unverified on hardware -- it needs a gfx950 node.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ThruptiRajLakshmanaGowda
ThruptiRajLakshmanaGowda force-pushed the users/tlakshma/ck/dispatcher_ci branch from dfdfb43 to 4c0f0a3 Compare August 19, 2026 19:42
…tifact path

Three defects found reviewing the dispatcher CI before merge.

1. fp8/bf8 numerics were verified against a wrong reference. _emulate() fell
   through to float16 for fp8/bf8, so the reference rounded operands to fp16
   while the kernel consumed real float8_e4m3fnuz / float8_e5m2fnuz. That left
   the reference strictly more precise than the kernel, failing every fp8/bf8
   config by construction. A 4-dtype x 4-layout sweep (budget 64, size 512)
   went 32 pass / 32 fail, with all 32 failures fp8/bf8 at max_rel
   0.033-0.065 against an _RTOL of 0.02. This predates the new variant lanes:
   the gemm_universal lane already sweeps all four dtypes, so it would have
   gone red on the first nightly.

   Quantize operands at the input dtype and the result at cfg.dtype_c -- they
   differ, and conflating them was the bug. The same sweep is now 64 pass / 0
   fail, worst max_rel 0.0064 (bf16). _emulate had no other call site and is
   removed in favour of _quantize, which the grouped/multi_d branches already
   used correctly.

2. Build failures produced a green lane. The exit status ignored n_build_fail,
   so a total codegen or compile breakage -- every kernel failing to build,
   nothing verified -- still exited 0, and build failures were filtered out of
   the printed listing so the log gave no hint either. Verified by stubbing
   setup_multiple_gemm_dispatchers to return None: 0 pass / 0 fail / 4
   build-fail now exits 1 and names all four.

3. The result JSONs were never archived. cmake_build runs execute_cmd from
   projects/composablekernel/build, but archiveArtifacts resolves against the
   workspace root, so the bare "dispatcher_*_results.json" glob matched
   nothing -- silently, because allowEmptyArchive is set. Qualify the path, and
   move the call into a finally block so a red lane keeps the JSON that
   explains why it went red.

Re-ran grouped, multi_d, multi_abd and stream_k after the reference change:
4 pass / 0 fail each, exit 0.
Wrap runDispatcherGemmTests in try/finally so its gemm_universal /
batched_gemm / batched_contraction result JSON is archived on a red lane
too, matching runDispatcherTests. Remove the single-use
runDispatcherTestsGfx950 wrapper and call runDispatcherTests("gfx950", ...)
directly, consistent with the two-arg convention used everywhere else.

Co-Authored-By: Claude <noreply@anthropic.com>
…ne lanes

runDispatcherTests called rocmnode() directly, but rocmnode is defined in the
Jenkinsfile and a vars/ script does not inherit Jenkinsfile-local methods. All
four call sites would have thrown MissingMethodException before reaching
runOnHealthyNode. Both params default to false so PR builds never hit it, but
the 22:00 develop cron sets both true. Now passed as the first parameter, the
same convention runDownstreamTestsStages / runFMHATestsStages / runBuildCKStages
already use.

Delete runTileEngineBasicTests and runTileEngineGemmTests. Their parameters and
stages were removed earlier on this branch, leaving both helpers with no callers.
Retiring them on purpose: the operators they covered (preshuffle, the
block_scale_gemm quant variants, batched contraction multiple ABD) are the
next-phase set and mostly have no dispatcher bridge on develop yet, so a lane
for them can only run red. The coverage delta belongs in the PR description.

Fix the perf lane archive glob. That lane drives tile_engine's own benchmark
drivers, so every file it writes is a tile_engine JSON -- gemm_universal_results
.json and friends. Nothing there carries a dispatcher_ prefix; only the
correctness lane writes those. The narrower glob matched zero files and
allowEmptyArchive turned that into a silent success.

allowEmptyArchive stays true because the call is in a finally block: on a
cmake/ninja failure no JSON exists yet and a throwing archive step would mask
the real exception. The signal that the run produced results moves into the
drivers instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every driver returned 0 unconditionally. A run where the build directory held
no kernels, or where every launch failed at runtime, exited clean and the CI
lane went green with an empty or absent results JSON. Fixing this in the Jenkins
lane alone would only paper over it for one caller, so the accounting moves into
the drivers themselves.

GemmBenchmark now counts launch_attempted and launch_failed around run_kernel;
the seven standalone drivers that carry their own run_kernel loop count the same
way. export_json takes an optional launch_counts and adds
launches_attempted/succeeded/failed to the metadata when given, so the trend is
recoverable from an archived artifact.

Exit codes:

  no launches attempted  -> 1  (no kernels discovered; the build never produced
                                anything to run)
  no results collected   -> 1  (everything that was attempted failed)
  some launches failed   -> 0, with a WARNING line

The partial-failure case is deliberately a warning. This sweep runs every
generated config and individual ones legitimately fail to launch -- a tile shape
the arch does not support, a workspace too large for the problem size. Making
any single failure red trades a permanently-green lane for a permanently-red
one, which is no more informative. Total failure is already caught by the
empty-result check, and the per-run counts are in the JSON for anyone tracking
the trend.

The three out-of-scope positional callers of export_json (gemm_rowcolquant,
gemm_tensor_quant, gemm_preshuffle) are unaffected: launch_counts is the last
parameter and defaults to None.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…op false-green ctests

Four related test-side defects, all of which made a lane report success without
having exercised what it claims to cover.

_sample handed out the divmod remainder in sorted stratum order. With
budget < n_strata every per-stratum share is 0, so the entire budget was
remainder and always landed on the first four keys -- bf16/{ccr,crr,rcr,rrr}.
The ctest registration used --budget 4 against 16 strata, so no run in CI ever
compiled an fp8 or bf8 config, and the daily rotating seed changed only which
config was drawn inside those four fixed strata. Shuffle the stratum order
before the remainder loop, and raise the ctest budget to 16 so every stratum is
represented at least once.

The skip path called detect_gpu_arch() bare. That helper defaults to
fallback="gfx942" and so never returns falsy, making the `if not arch: return
_SKIP` branch dead -- a CPU-only runner walked past it and compiled gfx942
kernels for hardware it does not have. Ask for fallback="" so the branch is
reachable.

The three unittest.TestCase suites (grouped_gemm / multi_abd / mx_gemm GPU
correctness) were registered as bare `unittest discover`, which exits 0 when
every test skips. mx_gemm is gfx950-only, so on gfx942 that is a green tick
backed by zero assertions. They now run through run_unittest_77.py, which maps
all-skipped onto 77 and pairs with SKIP_RETURN_CODE. A driver rather than
converting the suites, so the skip decision stays in each test's own setUp.
Discovery collecting nothing returns 1, not 77, so a renamed file cannot report
Skipped forever.

Add test_search_space_sampling.py pinning both the sampler and the skip path.
CPU-only -- no GPU, hipcc or built kernels -- and both key tests were mutation
checked against the old implementations to confirm they fail there. The sampler
test asserts on stratum keys rather than whole samples because the buggy version
did vary the configs within its four fixed strata; the skip test stubs
detect_gpu_arch to honour the fallback it is handed, so it only passes if the
caller actually asks for fallback="".

Rename the quant helper functions from test_* to case_*. They take non-fixture
positional args, so pytest collected them as tests and errored at fixture
resolution -- 12 collection errors across the repo, now 0 with 1075 tests
collected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The gfx950 perf lane previously ran only gemm_aquant, gemm_bquant,
gemm_abquant, mx_gemm, and gemm_streamk. Every other operator --
gemm_universal, batched_gemm, batched_contraction, grouped_gemm,
gemm_multi_d, gemm_multi_abd, grouped_gemm_rowcolquant,
grouped_gemm_tensorquant -- was CMake-legal on gfx950 (all list gfx950
in DESIRED_TARGETS) but absent from the gfx950 command because
_dispatcherPerfCmd used a hard arch branch that built a completely
different operator set on each side.

Collapse the branch into a shared base (all arch-agnostic ops) with a
gfx950-only appendix (gemm_aquant/bquant/abquant/mx_gemm). GPU_TARGETS
is now passed through from the caller rather than hardcoded.

Remaining gfx950-only set and why:
  gemm_aquant/bquant/abquant  SUPPORTED_ARCHS = ("gfx950",) in their
                               Python layers; gfx942 has fp8 FNUZ and
                               is in DESIRED_TARGETS, but the guards have
                               not been lifted yet.
  mx_gemm                     CMakeLists filters with target MATCHES
                               "^gfx950", so benchmark_mx_gemm_all is
                               never created for gfx942; also has no fp16
                               path, hence quantDatatype.

Deferred (next PR, same list as the correctness lane):
  gemm_preshuffle             no dispatcher bridge on develop
  contraction_multi_abd       no Python benchmark driver yet

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Jenkins ignores the dynamic library("ck@branch") load when ck is already
registered as a global shared library, causing the call to fail with
'No such DSL method'. Inline the parallel block directly in the Jenkinsfile
and drop the groovy wrapper.

Co-Authored-By: Claude <noreply@anthropic.com>
Same fix as runDownstreamTestsStages: Jenkins ignores the dynamic
library load when ck is already registered globally, so any function
that exists only on this branch is invisible at call time.

Co-Authored-By: Claude <noreply@anthropic.com>
ThruptiRajLakshmanaGowda added a commit that referenced this pull request Sep 9, 2026
Part 2 of the dispatcher CI work started in #10897, which wired 13
operators and deferred these seven on the grounds that they had no
dispatcher bridge on develop:

  gemm_aquant, gemm_abquant, gemm_bquant, gemm_rowcolquant,
  gemm_tensorquant (block_scale_gemm), preshuffled GEMM,
  batched contraction multi-ABD

That premise was wrong. The bridges landed on develop as squash-merge
#10439; `git merge-base --is-ancestor` reported the feature branches as
unmerged because squash rewrites history. `git ls-tree -r origin/develop`
confirms every bridge file is present. Preshuffle never needed its own
bridge -- it rides gemm_utils.py via variant="preshuffle".

Correctness lane (ck.groovy):
  - Wire the four already-registered tests: test_gemm_rowcolquant,
    test_tensor_quant, test_preshuffle, test_contraction_multi_abd.
  - Add three new single-GEMM GPU correctness tests. The existing
    test_{a,ab,b}quant_gpu_correctness.py files import grouped_gemm_*_utils
    and cover the GROUPED ops; the single-GEMM bridges export identical
    class names, so the import line is the only distinguishing token.
    The single-GEMM problem descriptors also differ (no QM_A / no
    aquant_group_m), so the grouped reference math would produce a
    plausible but wrong answer.
  - Each new test checks for all-zero output explicitly: that is the
    failure mode of a wrong warp_tile_k, and it is silent -- no build
    error, and a relative-tolerance gate alone will not catch it.
  - fp8 encoding goes through dispatcher_common.fp8_uses_ocp rather than
    a local copy, so the gfx942 FNUZ / gfx950 OCP split follows the
    compiled arch.

Perf lane (ck.groovy):
  - Wire gemm_rowcolquant, gemm_tensor_quant, gemm_preshuffle,
    contraction_multi_abd; move gemm_aquant/gemm_abquant off the
    gfx950-only branch (their bridges and DESIRED_TARGETS both include
    gfx942). gemm_bquant and mx_gemm stay gfx950-only.
  - Every new op carries an explicit <OP>_MAX_INSTANCES.
    TILE_ENGINE_SAMPLING_TIER is a TOTAL budget split across active ops,
    so omitting it on even one op silently shrinks coverage for every
    operator already in the lane -- a green run with less testing.

New driver: contraction_multi_abd_benchmark.py. Modelled on
batched_contraction_benchmark.py, with the same exit-code contract
(empty run returns 1, partial launch failure warns and returns 0).
Two forced divergences: the executable has no -json_output flag, so
results are parsed from its stdout perf line; and it has no split_k /
flush_cache / rotating_count arguments.

contraction_multi_abd also gets its own multiAbdConfigs rather than
sharing problemConfigs. Its kernels compile with NUM_DIM_M/N = 2, and the
executable rejects a dim list whose LENGTH differs from the compiled
count -- "m=1024" is one M dimension where the kernel wants two, which is
EXIT_FAILURE for every kernel rather than a smaller problem. Extents are
the product of each list, so m=4,256 is the same M=1024. The driver also
parses the compiled arity out of the kernel name and reports one clear
message instead of N opaque failures.

Also hardens test_preshuffle_gpu_correctness.py, which trusted --gfx with
no allow-list: a typo'd arch went straight to --offload-arch and reported
a build FAIL instead of a clean skip.

Verified without a GPU: codegen --list-name run to obtain a real kernel
name and validate the driver's filename parsing; driver exercised
end-to-end against stub executables for all four exit paths; ck.groovy
structurally checked (balanced triple-quotes, no dangling backslashes,
signature/call arity, each op present in the cmake/ninja/driver triple);
the three new tests exit 77 with correct skip reasons on gfx90a.

Still needs a gfx942/gfx950 node: the on-GPU pass path for the three new
tests, a real perf-driver run, and the budget regression check. The fp8
OCP/FNUZ path in particular must be run on BOTH arches -- wired backwards
it passes on one and returns NaN on the other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@ozturkosu ozturkosu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My request has been resolved.

@brockhargreaves-amd brockhargreaves-amd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, lgtm after the merge conflicts are fixed.

@ThruptiRajLakshmanaGowda
ThruptiRajLakshmanaGowda merged commit 7080fbe into develop Sep 18, 2026
116 checks passed
@ThruptiRajLakshmanaGowda
ThruptiRajLakshmanaGowda deleted the users/tlakshma/ck/dispatcher_ci branch September 18, 2026 04:57
assistant-librarian Bot pushed a commit to ROCm/composable_kernel that referenced this pull request Sep 18, 2026
feat(ck-tile): add dispatcher correctness and performance CI
 lanes for gfx942/gfx950 (#10897)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

## Motivation

ISSUE ID: 10897

A change to the CK-Tile dispatcher bridge or codegen can break numeric
correctness,
kernel build, or kernel launch for any of the 13 bridged GEMM operators,
and today
nothing catches it until someone runs the tests by hand. Three operators
(stream-K, aquant, abquant) had no GPU correctness test at all, and four
more were
registered in ctest but never invoked from CI.

This adds two opt-in Jenkins lanes that fan out across gfx942 and gfx950
and cover
every operator with a bridge on `develop`, plus the missing tests. Both
parameters
default to **OFF**, so no existing CI run gets slower.

## Dependencies

**Depends on #11591** — `fix(ck-tile): guard the gfx1250 unscaled WMMA
builtin behind __gfx1250__`.

`ck_tile/ops/gemm.hpp` does not compile on any non-gfx1250 target on
current
`develop` (19 errors, in both the host and the device pass), which
breaks four of the
dispatcher GPU correctness tests this PR adds. That fix is unrelated to
this change and
is split out into its own PR. Default CI here is unaffected — both lanes
are
`defaultValue: false` — but Test Plan steps 1, 2 and 4 will not pass
until #11591 merges.

## Technical Details

### 1. `RUN_DISPATCHER_CORRECTNESS_TESTS` — JIT-compiled kernels vs.
host reference

Covers all 13 operators rather than a representative sample: a developer
touching
the bridge needs signal on all of them, and a lane covering four cannot
give that.
Cost is held down by the *search budget* instead — `--budget 64` for the
standard
sweep, `--budget 16` per variant sweep.

| | gfx942 | gfx950 |
|---|---|---|
| shared | `gemm_universal` sweep + parity, `grouped`, `multi_d` (4
layouts), `multi_abd`, `batched_gemm`, `batched_contraction`
(fp16+bf16+fp32), `stream_k`, `rowcolquant`, `tensorquant`, `aquant`,
`abquant` | same |
| arch-only | — | `mx_gemm`, `bquant` C4 (fp8/bf8), C (fp8i4/bf8i4), H3
(`mx_*`) |

Only two things stay gfx950-only, both for ISA reasons rather than
policy. `mx_gemm`
needs the scale-MFMA builtins; it also cannot join the `--variant` sweep
at all,
because `mx_gemm_utils` exposes only `default_fp8_config()` /
`default_fp4_config()`
and never plugs into `expand_sweep`. The `bquant` H3 (`mx_*`) configs
need the same
builtins. `bquant`'s C4/C paths are held to gfx950 for a softer reason:
its config
builders are arch-aware now, so the gate is pending one validating
gfx942 run rather
than a known defect. Everything else — including
stream-K and all three quant operators — was widened to run on gfx942 as
well over
the course of this branch. Both rationales are recorded inline in
`ck.groovy`.

There is deliberately **no gfx1201 stage**:
`gemm_utils._SUPPORTED_ARCHES` excludes
it, and widening that guard does not help, because every warp tile in
`default_ci_config.json` is 64 wide while RDNA4 is warp_size 32, so all
16 strata
enumerate 0 configs and the runner exits 1 on "no configs to run".

One narrowed surface is documented rather than closed:
`grouped_gemm_{a,ab,b}quant`
run only on `rcr`, because all three config builders hardcode
`layout="rcr"` and the
ctypes libs assert packed rcr strides.

### 2. `RUN_DISPATCHER_PERF_TESTS` — ahead-of-time tile_engine instances

Smoke-tier benchmark covering the **same 13 operators** as the
correctness lane, so
the AOT instance path gets the same operator coverage the JIT path gets.
The two are
gated separately and neither substitutes for the other: correctness
JIT-builds each
config with hipcc and checks it against a host reference, while this
lane exercises
tile_engine's codegen, instance builder and benchmark harness.

One dtype, one layout, one problem size, and a fixed **64 AOT instances
per operator**.

| | gfx942 | gfx950 |
|---|---|---|
| fp16 / `rcr` | `gemm_universal`, `batched_gemm`,
`batched_contraction`, `gemm_streamk`, `grouped_gemm` | `gemm_streamk` |
| fp16 / `rcrr` | `gemm_multi_d`, `gemm_multi_abd` | — |
| fp8 / `rcr` | `grouped_gemm_rowcolquant`, `grouped_gemm_tensorquant` |
`gemm_aquant`, `gemm_bquant`, `gemm_abquant`, `mx_gemm` |

Three details that are load-bearing rather than incidental:

- **The per-op cap is explicit, not derived.**
`TILE_ENGINE_SAMPLING_TIER` is a
*total* budget split evenly across every op with a non-empty
`<OP>_DATATYPE`
(`ops/gemm/CMakeLists.txt:16-23`), so adding operators silently shrinks
the coverage
of the ones already there — gfx942 alone would have gone from 125 to 55
instances
per op. Pinning `<OP>_MAX_INSTANCES` uses the first-class override path
(same file,
`:50-59`) and keeps lane cost fixed and independent of how many ops the
lane builds.
The tier is still passed, because each op also forwards it to the
sampler as
  `--tier` to select the sampling strategy.
- **One dtype and one layout per op is not just smoke sizing.** The
per-op budget is
divided again across `(dtype × layout)` combos with integer truncation,
so a
  multi-combo op can floor a combo to zero instances and build nothing.
- **`gemm_multi_d` and `gemm_multi_abd` take 4-character layouts** (A,
B, D, E).
Passing the `rcr` the other ops use is a parse error in the instance
builder, not a
  narrower selection.

`mx_gemm` cannot leave the gfx950 branch: its CMakeLists filters targets
with a
literal regex, `target MATCHES "^gfx950"`, so on any other arch
`benchmark_mx_gemm_all` is never created and ninja fails on an unknown
target rather
than skipping. It also has no fp16 path.

`gemm_streamk` builds on both arches. `DESIRED_TARGETS` was widened to
include gfx950
earlier on this branch, but that CMake change is the one part that could
not be
exercised locally; this lane is its first real confirmation, and it
matches the
correctness lane, which already runs stream-K on both. If the gfx950 AOT
build turns
out to be broken, that `DESIRED_TARGETS` line is revertible on its own
without
touching the lane.

### 3. New search-space runner —
`dispatcher/tests/test_gemm_search_space.py`

One runner covering every variant `expand_sweep` understands (standard,
grouped,
multi_d, multi_abd, stream_k), selected with `--variant` — they share
the same
enumerate/sample/build/report machinery and differ only in which
`Gpu*Runner` to
drive and how the numpy reference is computed.

It enumerates the `GemmKernelConfig` space against tile_engine's
`default_ci_config.json`, samples a budget-limited subset with a daily
rotating seed
**per (dtype, layout) stratum** — so even budget 64 spreads ~4 configs
across all 16
combinations rather than testing one deeply — compiles via the bridge,
runs on GPU,
and reports correctness + TFLOPS as JSON.

This is the dispatcher equivalent of tile_engine's per-op benchmark
scripts, with one
deliberate difference: those never verify numerics and always exit 0.
This one
validates every kernel against a numpy reference and **exits 1 on any
mismatch or
build failure**.

### 4. New GPU correctness tests

- **`test_streamk_gpu_correctness.py`** — all three reduction
strategies. The shared
sweep only ever builds `atomic` (`default_ci_config.json` carries no
`streamk_config`,
so `expand_sweep` falls back to `["atomic"]`), leaving `linear`/`tree`
unverified
through the ctypes bridge. Two shapes: an occupancy-bound 4096³ case,
and a
Stream-K-heavy `M=N=128, K=8192` case that only linear/tree can assert
tightly,
since `estimate_num_wgs_per_tile` is gated on Atomic and returns 1
otherwise.
  Tolerance is CK's own split-K-aware element-wise bound, ported from
  `streamk_driver_common.hpp` + `check_err.hpp`.
- **`test_aquant_gpu_correctness.py`** — A-side per-(m,k)-group scales;
fp8, bf8, and a
tiled shape spanning a 4×4 output-tile grid that the 1×1-tile cases
cannot catch.
- **`test_abquant_gpu_correctness.py`** — scales on *both* operands,
completing the quant
trio; fp8 + bf8 on `compv3`, plus the gfx950-native `eightwaves`
pipeline (192×256
tiles, `TransposeC=True`, `bquant_group_n=128`), a different MFMA path
and B-scale
  granularity than compv3.

All four quant/stream-K bridge tests are now registered in ctest with
`SKIP_RETURN_CODE 77`. They intentionally take **no** `--gfx` from
CMake: each
hipcc-compiles with `--offload-arch` and then runs, so the arch must
match the
*physical* GPU, and the configured `GPU_TARGETS` may legitimately differ
from the card
in the box.

### 5. Skip semantics — exit 77 instead of exit 0

The script-style tests previously returned 0 when no GPU was present, so
a CPU-only
runner reported a green PASS for a test that never touched the GPU. They
now return 77,
which ctest maps to *skipped* via `SKIP_RETURN_CODE` and the Jenkins
lane maps via a
`run_ok` shell helper. Only 77 is swallowed — any other non-zero still
fails the lane.
This matters because `execute_cmd` is one `&&`-joined string: without
it, a single
unsupported arch would abort the lane and every later operator would
silently never run.

`--gfx` also loses its hardcoded `gfx950` default in the quant tests, so
"user asked for
gfx950" stays distinguishable from "we are on an unrelated box" and the
skip can fire.

### 6. Fixes and coverage extensions found while wiring this up

- `gemm_utils.expand_sweep`: skip non-`cshuffle` epilogues for
`stream_k` — the codegen
emits only cshuffle for that variant, so those configs surfaced as
spurious build
  failures.
- `grouped_gemm_aquant_utils._compile_aquant_kernel`: add the arch
defines
  (`CK_USE_OCP_FP8`, `CK_TILE_USE_OCP_FP8`, `CK_USE_NATIVE_MX_SUPPORT`,
`CK_GFX950_SUPPORT`) that CMake normally injects but the standalone
hipcc path omitted,
matching the bquant path. gfx942 is FNUZ, gfx950 is OCP; without this
the encoded
  inputs and the compiled kernel disagree and the device returns NaN.
- `tile_engine/ops/gemm_streamk/CMakeLists.txt`: widen AOT
`DESIRED_TARGETS` to include
gfx950, and correct the skip warning, which still listed only `(gfx90a,
gfx942)`
  afterwards.
- `streamk_gemm_ctypes_lib.cpp`: correct a stale comment claiming the
lib is Atomic-only.
The strategy is a codegen-time template constant and `GetWorkSpaceSize`
returns 0 for
Atomic / non-zero for Linear/Tree, so the one allocate-and-launch path
serves all three.
- Widened two existing GPU tests that were narrower than the operator
they cover:
batched-contraction now exercises bf16 and fp32 alongside fp16, and the
Multi-D GEMM
  test exercises all four layouts rather than one.
- `Dockerfile`: add `ml_dtypes`, required for host-side fp8/bf8
encoding.

Both lanes archive their per-kernel JSON from a `finally` block — a red
lane is exactly
when that artifact is worth having, and `buildAndTest` throws on
failure.

## Test Plan

1. **gfx942 correctness lane** —
`RUN_DISPATCHER_CORRECTNESS_TESTS=true`: the
`gemm_universal` sweep at budget 64 across all 16 dtype × layout strata,
the parity
test, the
grouped/multi_d/multi_abd/batched_gemm/batched_contraction/rowcolquant/
tensorquant/aquant/abquant/bquant bridge tests, the
`grouped`/`multi_d`/`multi_abd`/
`stream_k` variant sweeps at budget 16, and the stream-K registry +
bridge tests.
2. **gfx950 correctness lane** — the same set, plus `mx_gemm` and the
`bquant` H3
   (`mx_*`) configs.
3. **Both perf lanes** — `RUN_DISPATCHER_PERF_TESTS=true` on gfx942 and
gfx950; confirm
all 9 gfx942 and all 5 gfx950 `benchmark_*_all` targets build, every
script runs, and
each `*_results.json` lands as an archived artifact. The gfx950
`gemm_streamk` result
is the specific new signal — it is the first exercise of the
`DESIRED_TARGETS`
   widening.
4. **Skip path** — run the ctest suite on a non-gfx942/gfx950 box and
confirm the
   arch-gated tests report *Skipped*, not Passed and not Failed.
5. **Artifact archiving** — confirm `dispatcher_*_results.json` and
`*_results.json`
   appear as build artifacts, including on a deliberately failed run.

## Test Result

- Will be run on CI

## Submission Checklist

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/ROCm/blob/develop/CONTRIBUTING.md#pull-requests.
@assistant-librarian

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

ThruptiRajLakshmanaGowda added a commit that referenced this pull request Sep 21, 2026
… success (#12320)

ISSUE ID : AICK-2170

PR #10897 converted three declarative `parallel { stage { when {} } }`
blocks into scripted `parallel([...])` maps with plain `if` guards
inside each closure: "Run Downstream Tests", "Run CK_TILE_FMHA Tests"
and "Build CK and run Tests".

The two forms are not equivalent in how Jenkins reports them. A
declarative `when` that evaluates false marks the stage NOT_EXECUTED, so
it shows as Skipped and never claims to have passed. A scripted parallel
branch always runs; with the parameter off the branch body is an empty
`if`, the closure returns normally, and Jenkins records the branch as
SUCCESS.

Because RUN_PYTORCH_TESTS, RUN_AITER_TESTS, RUN_FA_TESTS and
RUN_CK_TILE_FMHA_TESTS all default to false, every DOWNSTREAM and FMHA
branch executed zero work and reported green on a normal PR build. The
arch-gated branches under "Build CK and run Tests" had the same problem.

The conversion also silently dropped fail-fast:
`parallelsAlwaysFailFast()` in the options block applies only to
declarative parallel, so a red branch no longer aborted its siblings.

Restore all three stages to the declarative form they had before #10897.
The DISPATCHER stage stays scripted on purpose -- its branch map is
built dynamically in ck.groovy to keep the declarative method under the
JVM 64KB limit -- and it is gated at the parent `when` on
(RUN_DISPATCHER_CORRECTNESS_TESTS || RUN_DISPATCHER_PERF_TESTS), so when
both are off the whole stage skips rather than reporting a hollow
success. For that one remaining scripted parallel, set failFast
explicitly in runDispatcherTests().

No change to the dispatcher parameters, cron settings, or the DISPATCHER
stage body. The restored file is 895 lines against 1009 before #10897,
so returning to declarative form does not reintroduce the 64KB
method-size pressure.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
ThruptiRajLakshmanaGowda added a commit that referenced this pull request Sep 21, 2026
…11879)

## Motivation
ISSUE ID : AICK-2171

#10897 wired 13 operators into the CK-Tile dispatcher CI lanes and
deferred seven, on the
grounds that they had no dispatcher bridge on `develop`. That premise
was wrong — the bridges
landed as squash-merge #10439, and `git merge-base --is-ancestor` gave a
false negative because
squash rewrites history (`git ls-tree -r origin/develop` confirms every
file is present).
Preshuffle never needed its own bridge; it rides `gemm_utils.py` via
`variant="preshuffle"`.

This PR closes that deferral. All seven now run in **both** dispatcher
lanes on gfx942/gfx950:
`gemm_aquant`, `gemm_abquant`, `gemm_bquant`, `gemm_rowcolquant`,
`gemm_tensorquant`,
Preshuffled GEMM, batched contraction multi-ABD. It also restores the
gfx942 preshuffle /
rowcolquant / tensor_quant coverage dropped when the orphaned
`runTileEngine*` helpers were
retired in #10897.

Stacked on #10897 — base is `users/tlakshma/ck/dispatcher_ci`, merge
after it.

## Technical Details

**Correctness lane** — wire 4 already-registered tests
(`test_gemm_rowcolquant`,
`test_tensor_quant`, `test_preshuffle`, `test_contraction_multi_abd`)
and add 3 new
single-GEMM tests. The existing `test_{a,ab,b}quant_*` files cover the
*grouped* ops and export
identical class names, so the import line is the only distinguishing
token; the single-GEMM
problem descriptors also differ (no `QM_A`, no `aquant_group_m`), so
grouped reference math
would give a plausible but wrong answer. Each new test checks for
**all-zero output** — the
silent failure mode of a wrong `warp_tile_k`, which a tolerance gate
alone won't catch — and
routes fp8 encoding through `dispatcher_common.fp8_uses_ocp` so the
gfx942 FNUZ / gfx950 OCP
split follows the compiled arch. ctest registration uses
`SKIP_RETURN_CODE 77` and no `--gfx`
(autodetect must match the physical GPU).

**Perf lane** — wire 4 ops across all three sections (cmake `-D`, ninja
target, driver call);
move aquant/abquant off the gfx950-only branch (their bridges and
`DESIRED_TARGETS` include
gfx942); bquant and mx_gemm stay gfx950-only. Every new op gets an
explicit
`<OP>_MAX_INSTANCES` — `TILE_ENGINE_SAMPLING_TIER` is a *total* budget
split across active ops,
so omitting it on one op silently shrinks coverage for every op already
in the lane.

**New `contraction_multi_abd_benchmark.py`** — the one real gap.
Modelled on
`batched_contraction_benchmark.py` with the same exit-code contract
(empty run → 1, partial
failure → WARNING + 0); diverges in parsing stdout (no `-json_output`)
and dropping
`split_k`/`flush_cache`/`rotating_count`. Two bugs caught while
verifying it, both of which
would have failed the lane on a GPU node:
- **Dim arity** — kernels compile with `NUM_DIM_M/N = 2`, and the
executable rejects a dim list
of the wrong *length*, so the shared `m=1024` was `EXIT_FAILURE` on
every kernel. Now has its
own `multiAbdConfigs = "g=2;m=4,256;n=4,256;k=64"` (same M=1024, right
arity), plus a driver
  guard that reports one clear message instead of N opaque failures.
- **Doubled name prefix** — codegen and CMake both prepend
`contraction_multi_abd_`; a
  single-slice strip shifted every parsed field by three tokens.

**Also** — `test_preshuffle_gpu_correctness.py` trusted `--gfx` with no
allow-list, so a typo'd
arch reported a build FAIL instead of a clean skip. Three stale
`ck.groovy` comment blocks
corrected.

Files: `groovy/vars/ck.groovy`, `dispatcher/tests/CMakeLists.txt`,
`test_preshuffle_gpu_correctness.py` (M);
`test_gemm_{aquant,abquant,bquant}_gpu_correctness.py`,
`contraction_multi_abd_benchmark.py` (A). No `Jenkinsfile` change; no
C/C++ touched.

## Test Plan

Without a target GPU (dev box is gfx90a): validate the driver's filename
parsing against a real
codegen kernel name; exercise all four driver exit paths against stub
executables; structurally
check the generated `ck.groovy` command strings; confirm the three new
tests take the skip path.

On a gfx942/gfx950 node before merge: on-GPU pass path for the new tests
(**both** arches, to
catch a backwards `fp8_uses_ocp`); a real multi-ABD perf run; budget
regression check; the full
lane across all four branches.

## Test Result

gfx90a, all **PASS**:
- Filename parsing against a real kernel name → `dim_counts
{g:1,m:2,n:2,k:1}`, `tensor_counts
{num_a:1,num_b:1,num_d:1}` (this run exposed the doubled-prefix bug, now
fixed).
- Exit contract: partial failure → `rc=0` + WARNING; wrong arity →
`rc=1` + arity message; empty
  `bin/` → `rc=1`; malformed config → clear error.
- `ck.groovy`: balanced triple-quotes, no dangling backslashes,
signature/call arity 12/12, each
  op present in all three sections.
- The three new tests exit **77** with correct skip reasons.

GPU steps **not yet run**. When reviewing lane logs, confirm each new op
printed a real result
or an explicit `SKIP(77):` — a lane green because every new op silently
skipped looks identical
to success at the stage level.

## Submission Checklist

- [x] Look over the contributing guidelines at
https://github.com/ROCm/TheRock/blob/main/GOVERNANCE.md#pull-requests.
- [ ] Dependent PR #10897 merged first.

Co-authored-by: Claude <noreply@anthropic.com>
ThruptiRajLakshmanaGowda added a commit that referenced this pull request Sep 22, 2026
…12392)

## Proposed changes

Backs the dispatcher CI lanes out of `develop` after they broke the
pipeline, by restoring the three pipeline files to their state
immediately before #10897:

- `projects/composablekernel/Jenkinsfile`
- `projects/composablekernel/Dockerfile`
- `projects/composablekernel/groovy/vars/ck.groovy`

All three are **byte-identical to `7080fbe1ca^`**, so the pipeline
returns to a previously-green configuration.

This is a **CI-files-only** revert. The dispatcher Python, codegen and
test sources are deliberately left untouched on `develop`. It is the
minimal-blast-radius alternative to #12390, which reverts those three
PRs in full (51 files).

Reverts the pipeline changes from:

| PR | Merge commit |
|---|---|
| #10897 — feat(ck-tile): add dispatcher correctness and performance CI
lanes for gfx942/gfx950 | `7080fbe1ca` |
| #12320 — fix(ck): restore declarative stages so skipped CI lanes stop
reporting success | `40995238ed` |
| #11879 — feat(ck): add 7 operators to dispatcher correctness and perf
lanes | `5873d0a0f6` |

### Why restoring only these three files is safe

- **No other author's work is affected.** Every commit that touched
these three files since #10897 is one of the three PRs being backed out.
Verified per file with `git log 7080fbe..develop -- <file>`. This
matters because three gfx1250 PRs (#11043, #10934, #12216) landed on the
*dispatcher* files after #10897 — but none of them touched the pipeline
files, so this revert cannot disturb them.
- **The leftover dispatcher sources are inert for the main build.**
`dispatcher/` is a standalone CMake project and is never reached by an
`add_subdirectory()` from the top-level `CMakeLists.txt`.
`CK_TILE_DISPATCHER` only adds a compile definition and an include
directory, so `dispatcher/tests/CMakeLists.txt` is not configured by a
normal build.
- **The one pre-existing `CK_TILE_DISPATCHER=ON` lane is unaffected.**
`runFullGroupedConvTileTests` predates #10897, uses
`DISPATCHER_RULE_SET=tests` for conv only, and builds and runs three
named conv binaries rather than invoking `ctest`. It does not reach
`dispatcher/tests`.
- **No dangling callers.** `ck.groovy` defines the same 54 top-level
functions before and after; the reverted PRs changed function bodies,
not the API.

### Verification

- The three files are byte-identical to `7080fbe1ca^`, and to the
corresponding files on `users/tlakshma/ck/revert-dispatcher-ci` (#12390)
- Diff is confined to `projects/composablekernel/`; no dispatcher or
tile_engine source is touched
- Per-file authorship of every commit since #10897 confirmed
- `ck.groovy` top-level function set compared before/after

Not verified: the `Jenkinsfile` and `ck.groovy` could not be
syntax-checked locally (no `groovy`/`groovyc` available). Mitigated by
both being byte-identical to a revision that was previously green.

### Relationship to #12390

#12390 and this PR are **alternatives, not companions** — they overlap
on these three files. Whichever lands second will need a rebase, or
should be closed. Pick based on whether the leftover dispatcher sources
on `develop` are acceptable:

- **This PR** — smallest change, restores CI immediately, but leaves
dispatcher Python and its CTest registrations on `develop` with no lane
exercising them.
- **#12390** — also removes that now-unexercised code, at the cost of a
51-file diff with hand-resolved conflicts around the gfx1250 work.

### Follow-up

#12320 was itself a *fix* for skipped lanes falsely reporting success.
Reverting it restores that false-green behaviour. If the breakage is
traced to #10897 or #11879 alone, #12320 should be re-landed on top
rather than left reverted.

Issue IDs: AICK-2170 (#12320), AICK-2171 (#11879). #10897 had no issue
ID.

## Checklist

- [ ] I have added tests relevant to the introduced functionality, and
the unit tests are passing locally
- [ ] I have added the test to REGRESSION_TESTS list defined at the top
of CMakeLists.txt in tests/CMakeLists.txt, **IF** the test takes more
than 30 seconds to run.
- [x] I have added inline documentation which enables the maintainers
with understanding the motivation
- [ ] I have removed the stale documentation which is no longer relevant
after this pull request
- [ ] (If this change is user-facing) I have added release notes which
provide the end users with a brief summary of the improvement from this
pull request
- [ ] I have run `clang-format` on all changed files
- [x] Any dependent changes have been merged

No tests are added: this PR only restores CI pipeline configuration to a
prior state and changes no library or test source.

## Discussion

The alternative is the full revert in #12390. A full revert is tidier in
that it does not leave unexercised code behind, but it requires
hand-resolving conflicts against three gfx1250 PRs that landed on the
dispatcher files after #10897, where a naive resolution silently deletes
another author's work. This PR avoids that risk entirely by touching
only files that no one else has modified, at the cost of leaving the
dispatcher sources in place until they are cleaned up or re-landed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
evedovelli pushed a commit that referenced this pull request Sep 23, 2026
… success (#12320)

ISSUE ID : AICK-2170

PR #10897 converted three declarative `parallel { stage { when {} } }`
blocks into scripted `parallel([...])` maps with plain `if` guards
inside each closure: "Run Downstream Tests", "Run CK_TILE_FMHA Tests"
and "Build CK and run Tests".

The two forms are not equivalent in how Jenkins reports them. A
declarative `when` that evaluates false marks the stage NOT_EXECUTED, so
it shows as Skipped and never claims to have passed. A scripted parallel
branch always runs; with the parameter off the branch body is an empty
`if`, the closure returns normally, and Jenkins records the branch as
SUCCESS.

Because RUN_PYTORCH_TESTS, RUN_AITER_TESTS, RUN_FA_TESTS and
RUN_CK_TILE_FMHA_TESTS all default to false, every DOWNSTREAM and FMHA
branch executed zero work and reported green on a normal PR build. The
arch-gated branches under "Build CK and run Tests" had the same problem.

The conversion also silently dropped fail-fast:
`parallelsAlwaysFailFast()` in the options block applies only to
declarative parallel, so a red branch no longer aborted its siblings.

Restore all three stages to the declarative form they had before #10897.
The DISPATCHER stage stays scripted on purpose -- its branch map is
built dynamically in ck.groovy to keep the declarative method under the
JVM 64KB limit -- and it is gated at the parent `when` on
(RUN_DISPATCHER_CORRECTNESS_TESTS || RUN_DISPATCHER_PERF_TESTS), so when
both are off the whole stage skips rather than reporting a hollow
success. For that one remaining scripted parallel, set failFast
explicitly in runDispatcherTests().

No change to the dispatcher parameters, cron settings, or the DISPATCHER
stage body. The restored file is 895 lines against 1009 before #10897,
so returning to declarative form does not reintroduce the 64KB
method-size pressure.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
evedovelli pushed a commit that referenced this pull request Sep 23, 2026
…11879)

## Motivation
ISSUE ID : AICK-2171

#10897 wired 13 operators into the CK-Tile dispatcher CI lanes and
deferred seven, on the
grounds that they had no dispatcher bridge on `develop`. That premise
was wrong — the bridges
landed as squash-merge #10439, and `git merge-base --is-ancestor` gave a
false negative because
squash rewrites history (`git ls-tree -r origin/develop` confirms every
file is present).
Preshuffle never needed its own bridge; it rides `gemm_utils.py` via
`variant="preshuffle"`.

This PR closes that deferral. All seven now run in **both** dispatcher
lanes on gfx942/gfx950:
`gemm_aquant`, `gemm_abquant`, `gemm_bquant`, `gemm_rowcolquant`,
`gemm_tensorquant`,
Preshuffled GEMM, batched contraction multi-ABD. It also restores the
gfx942 preshuffle /
rowcolquant / tensor_quant coverage dropped when the orphaned
`runTileEngine*` helpers were
retired in #10897.

Stacked on #10897 — base is `users/tlakshma/ck/dispatcher_ci`, merge
after it.

## Technical Details

**Correctness lane** — wire 4 already-registered tests
(`test_gemm_rowcolquant`,
`test_tensor_quant`, `test_preshuffle`, `test_contraction_multi_abd`)
and add 3 new
single-GEMM tests. The existing `test_{a,ab,b}quant_*` files cover the
*grouped* ops and export
identical class names, so the import line is the only distinguishing
token; the single-GEMM
problem descriptors also differ (no `QM_A`, no `aquant_group_m`), so
grouped reference math
would give a plausible but wrong answer. Each new test checks for
**all-zero output** — the
silent failure mode of a wrong `warp_tile_k`, which a tolerance gate
alone won't catch — and
routes fp8 encoding through `dispatcher_common.fp8_uses_ocp` so the
gfx942 FNUZ / gfx950 OCP
split follows the compiled arch. ctest registration uses
`SKIP_RETURN_CODE 77` and no `--gfx`
(autodetect must match the physical GPU).

**Perf lane** — wire 4 ops across all three sections (cmake `-D`, ninja
target, driver call);
move aquant/abquant off the gfx950-only branch (their bridges and
`DESIRED_TARGETS` include
gfx942); bquant and mx_gemm stay gfx950-only. Every new op gets an
explicit
`<OP>_MAX_INSTANCES` — `TILE_ENGINE_SAMPLING_TIER` is a *total* budget
split across active ops,
so omitting it on one op silently shrinks coverage for every op already
in the lane.

**New `contraction_multi_abd_benchmark.py`** — the one real gap.
Modelled on
`batched_contraction_benchmark.py` with the same exit-code contract
(empty run → 1, partial
failure → WARNING + 0); diverges in parsing stdout (no `-json_output`)
and dropping
`split_k`/`flush_cache`/`rotating_count`. Two bugs caught while
verifying it, both of which
would have failed the lane on a GPU node:
- **Dim arity** — kernels compile with `NUM_DIM_M/N = 2`, and the
executable rejects a dim list
of the wrong *length*, so the shared `m=1024` was `EXIT_FAILURE` on
every kernel. Now has its
own `multiAbdConfigs = "g=2;m=4,256;n=4,256;k=64"` (same M=1024, right
arity), plus a driver
  guard that reports one clear message instead of N opaque failures.
- **Doubled name prefix** — codegen and CMake both prepend
`contraction_multi_abd_`; a
  single-slice strip shifted every parsed field by three tokens.

**Also** — `test_preshuffle_gpu_correctness.py` trusted `--gfx` with no
allow-list, so a typo'd
arch reported a build FAIL instead of a clean skip. Three stale
`ck.groovy` comment blocks
corrected.

Files: `groovy/vars/ck.groovy`, `dispatcher/tests/CMakeLists.txt`,
`test_preshuffle_gpu_correctness.py` (M);
`test_gemm_{aquant,abquant,bquant}_gpu_correctness.py`,
`contraction_multi_abd_benchmark.py` (A). No `Jenkinsfile` change; no
C/C++ touched.

## Test Plan

Without a target GPU (dev box is gfx90a): validate the driver's filename
parsing against a real
codegen kernel name; exercise all four driver exit paths against stub
executables; structurally
check the generated `ck.groovy` command strings; confirm the three new
tests take the skip path.

On a gfx942/gfx950 node before merge: on-GPU pass path for the new tests
(**both** arches, to
catch a backwards `fp8_uses_ocp`); a real multi-ABD perf run; budget
regression check; the full
lane across all four branches.

## Test Result

gfx90a, all **PASS**:
- Filename parsing against a real kernel name → `dim_counts
{g:1,m:2,n:2,k:1}`, `tensor_counts
{num_a:1,num_b:1,num_d:1}` (this run exposed the doubled-prefix bug, now
fixed).
- Exit contract: partial failure → `rc=0` + WARNING; wrong arity →
`rc=1` + arity message; empty
  `bin/` → `rc=1`; malformed config → clear error.
- `ck.groovy`: balanced triple-quotes, no dangling backslashes,
signature/call arity 12/12, each
  op present in all three sections.
- The three new tests exit **77** with correct skip reasons.

GPU steps **not yet run**. When reviewing lane logs, confirm each new op
printed a real result
or an explicit `SKIP(77):` — a lane green because every new op silently
skipped looks identical
to success at the stage level.

## Submission Checklist

- [x] Look over the contributing guidelines at
https://github.com/ROCm/TheRock/blob/main/GOVERNANCE.md#pull-requests.
- [ ] Dependent PR #10897 merged first.

Co-authored-by: Claude <noreply@anthropic.com>
evedovelli pushed a commit that referenced this pull request Sep 23, 2026
…12392)

## Proposed changes

Backs the dispatcher CI lanes out of `develop` after they broke the
pipeline, by restoring the three pipeline files to their state
immediately before #10897:

- `projects/composablekernel/Jenkinsfile`
- `projects/composablekernel/Dockerfile`
- `projects/composablekernel/groovy/vars/ck.groovy`

All three are **byte-identical to `7080fbe1ca^`**, so the pipeline
returns to a previously-green configuration.

This is a **CI-files-only** revert. The dispatcher Python, codegen and
test sources are deliberately left untouched on `develop`. It is the
minimal-blast-radius alternative to #12390, which reverts those three
PRs in full (51 files).

Reverts the pipeline changes from:

| PR | Merge commit |
|---|---|
| #10897 — feat(ck-tile): add dispatcher correctness and performance CI
lanes for gfx942/gfx950 | `7080fbe1ca` |
| #12320 — fix(ck): restore declarative stages so skipped CI lanes stop
reporting success | `40995238ed` |
| #11879 — feat(ck): add 7 operators to dispatcher correctness and perf
lanes | `5873d0a0f6` |

### Why restoring only these three files is safe

- **No other author's work is affected.** Every commit that touched
these three files since #10897 is one of the three PRs being backed out.
Verified per file with `git log 7080fbe..develop -- <file>`. This
matters because three gfx1250 PRs (#11043, #10934, #12216) landed on the
*dispatcher* files after #10897 — but none of them touched the pipeline
files, so this revert cannot disturb them.
- **The leftover dispatcher sources are inert for the main build.**
`dispatcher/` is a standalone CMake project and is never reached by an
`add_subdirectory()` from the top-level `CMakeLists.txt`.
`CK_TILE_DISPATCHER` only adds a compile definition and an include
directory, so `dispatcher/tests/CMakeLists.txt` is not configured by a
normal build.
- **The one pre-existing `CK_TILE_DISPATCHER=ON` lane is unaffected.**
`runFullGroupedConvTileTests` predates #10897, uses
`DISPATCHER_RULE_SET=tests` for conv only, and builds and runs three
named conv binaries rather than invoking `ctest`. It does not reach
`dispatcher/tests`.
- **No dangling callers.** `ck.groovy` defines the same 54 top-level
functions before and after; the reverted PRs changed function bodies,
not the API.

### Verification

- The three files are byte-identical to `7080fbe1ca^`, and to the
corresponding files on `users/tlakshma/ck/revert-dispatcher-ci` (#12390)
- Diff is confined to `projects/composablekernel/`; no dispatcher or
tile_engine source is touched
- Per-file authorship of every commit since #10897 confirmed
- `ck.groovy` top-level function set compared before/after

Not verified: the `Jenkinsfile` and `ck.groovy` could not be
syntax-checked locally (no `groovy`/`groovyc` available). Mitigated by
both being byte-identical to a revision that was previously green.

### Relationship to #12390

#12390 and this PR are **alternatives, not companions** — they overlap
on these three files. Whichever lands second will need a rebase, or
should be closed. Pick based on whether the leftover dispatcher sources
on `develop` are acceptable:

- **This PR** — smallest change, restores CI immediately, but leaves
dispatcher Python and its CTest registrations on `develop` with no lane
exercising them.
- **#12390** — also removes that now-unexercised code, at the cost of a
51-file diff with hand-resolved conflicts around the gfx1250 work.

### Follow-up

#12320 was itself a *fix* for skipped lanes falsely reporting success.
Reverting it restores that false-green behaviour. If the breakage is
traced to #10897 or #11879 alone, #12320 should be re-landed on top
rather than left reverted.

Issue IDs: AICK-2170 (#12320), AICK-2171 (#11879). #10897 had no issue
ID.

## Checklist

- [ ] I have added tests relevant to the introduced functionality, and
the unit tests are passing locally
- [ ] I have added the test to REGRESSION_TESTS list defined at the top
of CMakeLists.txt in tests/CMakeLists.txt, **IF** the test takes more
than 30 seconds to run.
- [x] I have added inline documentation which enables the maintainers
with understanding the motivation
- [ ] I have removed the stale documentation which is no longer relevant
after this pull request
- [ ] (If this change is user-facing) I have added release notes which
provide the end users with a brief summary of the improvement from this
pull request
- [ ] I have run `clang-format` on all changed files
- [x] Any dependent changes have been merged

No tests are added: this PR only restores CI pipeline configuration to a
prior state and changes no library or test source.

## Discussion

The alternative is the full revert in #12390. A full revert is tidier in
that it does not leave unexercised code behind, but it requires
hand-resolving conflicts against three gfx1250 PRs that landed on the
dispatcher files after #10897, where a naive resolution silently deletes
another author's work. This PR avoids that risk entirely by touching
only files that no one else has modified, at the cost of leaving the
dispatcher sources in place until they are cleaned up or re-landed.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
illsilin pushed a commit that referenced this pull request Oct 2, 2026
ISSUE ID : AICK-2171

## Motivation

PR #10897 added dispatcher correctness and performance CI lanes for
gfx942/gfx950 but was reverted in #12392 due to unrelated gfx1250
conflicts
in other files. This re-lands the CI infrastructure only — Dockerfile,
Jenkinsfile, and ck.groovy — leaving the Python dispatcher source at the
develop state to preserve Ozturk's gfx1250 work (#11043, #10934,
#12216).

## Technical Details

**Re-landed from #10897:**
- `Dockerfile`: re-pin `ml_dtypes==0.6.0` for consistent fp8 OCP/FNUZ
  reference values across gfx942 (FNUZ) and gfx950 (OCP)
- `Jenkinsfile`: restore `RUN_DISPATCHER_CORRECTNESS_TESTS` and
  `RUN_DISPATCHER_PERF_TESTS` boolean params (default: off), the
  declarative dispatcher stage, and nightly cron entry at 22:00 UTC
- `groovy/vars/ck.groovy`: restore `runDispatcherTests`,
  `runDispatcherCorrectnessTests`, `runDispatcherPerfTests` and helpers
  (573 lines) — correctness lane covers 13+ operators on gfx942/gfx950
  with arch-aware fp8 encoding; bquant/mx_gemm gfx950-only

**New fixes over #10897:**
- `dispatcher/CMakeLists.txt`: add `HIP` to project languages and
  `set_source_files_properties(LANGUAGE HIP)` for `fmha_dispatcher.cpp`
  and `fmha_registry.cpp` — required for the standalone cmake build used
by the correctness lane (these files use `<<<>>>` kernel launch syntax)
- `ck.groovy` correctness cmd: point cmake at `-S ../dispatcher -B
  ../dispatcher/build` and ninja at `-C ../dispatcher/build` so
  `libck_tile_dispatcher.a` lands in `dispatcher/build/` where
  `dispatcher_common.get_build_dir()` expects it
- `tile_engine/sampling/op_weights.json`: register
`contraction_multi_abd`
  with weight `0.0625` — the perf lane activates it via
`CONTRACTION_MULTI_ABD_DATATYPE=fp16` and `allocate_budget()` hard-fails
  in strict mode for any unregistered active op

## Test Plan

- `RUN_DISPATCHER_CORRECTNESS_TESTS=true` on gfx942 and gfx950: cmake +
  ninja build of `ck_tile_dispatcher`, then 13+ operator sweeps via
  `test_gemm_search_space.py` and per-op correctness scripts
- `RUN_DISPATCHER_PERF_TESTS=true` on gfx942 and gfx950: tile_engine AOT
  build of all dispatcher-bridged operators, then benchmark drivers for
  each

## Test Result

CI triggered on this branch — results pending.

## Submission Checklist

- [x] CI infrastructure only; Python dispatcher source unchanged from
develop
- [x] `defaultValue: false` for both dispatcher params (opt-in, not
opt-out)
- [x] `contraction_multi_abd` added to `op_weights.json`
- [x] HIP language fix in `dispatcher/CMakeLists.txt` for standalone
build

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Muhammed  Emin Ozturk <Muhammed.Ozturk@amd.com>
Co-authored-by: Muhammed Emin Ozturk <3836908+ozturkosu@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ck: attention-moe Used to tag composablekernel PRs that require approval from Attention/MOE review team. organization: ROCm project: composablekernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants