[CK_TILE] Add TE -> Dispatcher bridge GEMM example#8193
Conversation
Examples 01-11 drive the Dispatcher's native ctypes Registry; none exercise the Tile Engine -> Dispatcher bridge (dispatcher/python/gemm_utils.py). Add 12_te_bridge.py, which builds via setup_multiple_gemm_dispatchers and runs via GpuGemmRunner across fp16/bf16 and the row/col layout combinations the universal GEMM supports (row-major C), validating each against a NumPy reference. Closes the last FMHA-parity gap (runnable example scripts). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…her-gemm-bridge-example
There was a problem hiding this comment.
Pull request overview
Adds a new runnable Python example under the CK Tile dispatcher GEMM examples to exercise the Tile Engine → Dispatcher bridge path (dispatcher/python/gemm_utils.py) end-to-end: codegen + hipcc build of per-config .so files, then GPU execution and validation against a NumPy reference.
Changes:
- Introduces
12_te_bridge.pyas the first GEMM example that usessetup_multiple_gemm_dispatchers()+GpuGemmRunner(bridge path) instead of the registry-driven examples (01–11). - Sweeps a fixed algorithm across multiple
(dtype, layout)pairs (fp16 and bf16; row-major C) and validates outputs against a CPU reference.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| from gemm_utils import ( # noqa: E402 | ||
| GemmKernelConfig, | ||
| GemmProblem, | ||
| GpuGemmRunner, | ||
| setup_multiple_gemm_dispatchers, | ||
| ) | ||
|
|
| def main() -> int: | ||
| parser = argparse.ArgumentParser( | ||
| description="Tile Engine -> Dispatcher bridge example", | ||
| formatter_class=argparse.RawDescriptionHelpFormatter, | ||
| ) | ||
| parser.add_argument("--size", type=int, default=512, help="M=N=K (default 512)") | ||
| parser.add_argument( | ||
| "--rtol", type=float, default=2e-2, help="relative tolerance (default 2e-2)" | ||
| ) | ||
| args = parser.parse_args() | ||
|
|
||
| problem = GemmProblem(M=args.size, N=args.size, K=args.size) | ||
| configs = [_config(dt, lay) for dt, lay in _CASES] | ||
|
|
| if not result.success: | ||
| print(f" {tag:10s} RUN FAILED (status {result.status})") | ||
| continue | ||
| ref = _emulate(A, dtype) @ _emulate(B, dtype) |
…her-gemm-bridge-example
…her-gemm-bridge-example
…her-gemm-bridge-example
- Add --arch flag (defaults to rocminfo auto-detection) and thread it into GemmKernelConfig so the example is not pinned to gfx942. - Complete the bf16 layout matrix (add ccr/crr) so _CASES matches the docstring's claim of fp16+bf16 across all four row-major-C combinations. - Round the CPU reference's output to dtype_c as well, matching the GPU's back-store of C, so accuracy comparison is faithful end to end. Validated 8/8 on gfx942 (fp16 max_rel 4.9e-4, bf16 3.9e-3). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…her-gemm-bridge-example
Update — example hardened on three review itemsApplied the Copilot suggestions on
Validated 8/8 on gfx942 (fp16 max_rel 4.9e-4, bf16 3.9e-3). |
…her-gemm-bridge-example
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Add tests/test_gemm_parity.py: a GPU-gated end-to-end regression that codegens + hipcc-compiles each (dtype, layout) the bridge supports and checks Dispatcher GPU output against a NumPy reference across square, rectangular, and awkward (non-tile-aligned) shapes. Skips cleanly when hipcc / the dispatcher static lib / a GPU is unavailable so CPU-only CI stays green. Parity uses global relative error (max|gpu-ref|/max|ref|). Expand examples/gemm/python/12_te_bridge.py from a single dtype/layout matrix into a three-demo gallery (matrix / shapes / sweep) covering the full dtype+layout surface, padding-driven shape acceptance, and an algorithm sweep ranked by measured TFLOPS. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
GPU verification on MI300X (gfx942) — results + two bugs foundRan the newly added Parity suite: 10/24 passed
Bug 1 — non-native layouts use the wrong leading dimension on non-square problemsIsolated with a dimension-sweep probe (fp16, padded default algo, row-major C).
The pattern is exact:
Only each operand's native orientation — row-major A, column-major B, i.e. the This is in the C ABI / dispatcher leading-dim plumbing (the kernel reads Bug 2 — odd M/N throws at runtimeThe What this means for this PR
Suggest (1) to land green now and track (2) as the real fix. Either way, the GPU run: |
How validity was checked (oracle = NumPy, not Tile Engine)To be explicit about what the parity numbers above mean: validity is checked The exact check in ref = _emulate(_emulate(A, dtype) @ _emulate(B, dtype), dtype) # fp32 matmul, dtype-rounded
max_rel = max|gpu_out - ref| / max|ref| # global relative error
assert max_rel <= tol # fp16 2e-3, bf16 1.5e-2i.e. Dispatcher GPU output (through the bridge) vs NumPy. Why NumPy and not a bridge-vs-TE comparisonThis matters for interpreting Bug 1 (the leading-dim defect):
The failure is not in the test harnessTraced all four Follow-up in progressNumPy is the right correctness oracle, but a bridge-vs-TE head-to-head on the |
Bridge vs Tile Engine head-to-head (gfx942) — bridge reproduces TE on the
|
| path | kernel name | square 512³ | rect 1024×512×256 |
|---|---|---|---|
Native TE (gemm_universal_...) |
…_compv4_default_intrawave_False_False_False_False_64x64x128_2x2x1_16x16x32 |
verdict correct | verdict correct |
Bridge (GpuGemmRunner) |
same name, minus the _universal_ harness prefix |
max_rel 4.62e-4 | max_rel 3.25e-4 |
Reading the table:
- The two kernel names are identical except the benchmark-harness prefix —
confirming both paths go through the sameunified_gemm_codegenand produce
the same kernel. - Native TE validates against its own CK CPU reference (relative-error
threshold 4.88e-4) → verdictcorrecton both shapes. - The bridge, built from the identical config, lands at 4.6e-4 / 3.3e-4
against an independent NumPy oracle — the same ~e-4 band, both comfortably
under TE's own 4.88e-4 threshold.
So where both are correct, the bridge matches the Tile Engine. This closes the
"follow-up in progress" item from the validity note: NumPy remains the
correctness oracle, and the bridge is now also confirmed to reproduce the native
TE on the passing rcr surface.
GPU run: ctr-cx65-mi300x-30 (MI300X / gfx942). Native: benchmark_gemm_universal_… -verify=1. Bridge: GpuGemmRunner vs NumPy, same config.
Re-ran the parity suite on gfx942 — still 10/24 (layout fix is square-only)Prompted by the "all layouts fixed" update on #8123, I re-ran the full suite
10 pass = all 8 Why this doesn't contradict the #8123 "Fixed" update
Net: the layout support is correct for square; GPU run: |
Addresses the three review items on the TE->Dispatcher GEMM bridge driver:
1. Example configs to sweep
- gemm_full_benchmark.py defaults to the selected variant's
configs/default_ci_config.json (small CI sweep) when no config is
passed, and to configs/example_problems.json when --problems is
omitted; configs/default_config.json remains the full sweep.
- New gemm_universal/configs/example_problems.json (square / rectangular
/ large M,N,K). Nightly-test JSON is meant to drop into the same
configs/ dir -- no driver change needed.
2. Multi-GPU launch in parallel (supersedes grouped_conv's serial-GPU design)
- Phase 3 fans the (kernel x problem) work across every visible GPU:
one worker thread per device pulls batches from a shared queue and
spawns a disposable subprocess pinned via HIP_VISIBLE_DEVICES, so an
N-GPU box runs ~Nx faster while keeping per-batch fault isolation.
- Devices auto-detected (HIP_VISIBLE_DEVICES, then rocm-smi / amd-smi);
--devices overrides with a count (4) or explicit ids (0,2,5).
- CSV gains a "device" column recording which GPU produced each row.
3. Organize per variant + README
- --variant arg with a VARIANT_CONFIGS map
(gemm_universal/gemm_multi_d/gemm_preshuffle/grouped_gemm) selecting
the variant's configs/ dir; gemm_universal is wired today, the rest
are registered for when their bridge paths land.
- README gains a "Dispatcher Bridge Workflow" section (scripts, config
layout, run examples, multi-GPU, supported dtype/layout) and a note
that the legacy *_instance_builder.py is slated for deprecation once
the bridge reaches parity.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
24296bf to
8af03c3
Compare
|
Closing this draft PR as its changes are fully superseded by #8479 ([CK_TILE] TE -> Dispatcher GEMM bridge — all layouts + fp16/bf16). PR #8479 is the consolidated, single-commit re-roll of the entire GEMM bridge work that was previously split across the stacked draft series (#8187 → #8190 → #8191 → #8193). Every file touched by this PR is included in #8479 at the same or an updated path. Please track further work in #8479. |
Summary
dispatcher/examples/gemm/python/12_te_bridge.py, the first runnable example that exercises the Tile Engine -> Dispatcher bridge (dispatcher/python/gemm_utils.py) rather than the Dispatcher's native ctypes Registry (examples 01-11).setup_multiple_gemm_dispatchersand runs viaGpuGemmRunner, sweeping fp16 and bf16 across the row/col layout combinations the universal GEMM supports (row-major C), validating each result against a NumPy reference.gemm_pr_evaluation.md: "FMHA shipped runnable examples; we shipped none."Context
This is the final PR in the stack that brings the regular-GEMM bridge
Validation (gfx942 / MI300X, M=N=K=512)
Test plan
python3 dispatcher/examples/gemm/python/12_te_bridge.pybuilds 6 kernels and passes 6/6 vs NumPy reference on gfx942