Skip to content

fix(hipblaslt): correct MI300A kernel selection in the WGMXCC predicate and KD-tree search - #13293

Merged
NaveenElumalaiAMD merged 5 commits into
developfrom
users/nelumala/hipBLASLt/mi300a-wgmxcc-predicate
Oct 9, 2026
Merged

NaveenElumalaiAMD merged 5 commits into
developfrom
users/nelumala/hipBLASLt/mi300a-wgmxcc-predicate

Conversation

@NaveenElumalaiAMD

Copy link
Copy Markdown
Contributor

Motivation

On MI300A (gfx942, 228 CUs) WorkgroupMappingXCCCheck rejects 150,639 of 195,438 generic gfx942 solutions (77.1%; 99.7% of GridBased) because 228 % 8 != 0, starving the heuristic across every data type — fp8/bf8 collapse to a single macro-tile per transpose combination. A second, independent bug lets the grid-based KD-tree search read out of bounds when a cell holds no row for the problem's batch count.

Technical Details

The rejection is spurious: generic gfx942 solutions are CU-fallbacks on MI300A and are already launched at WGMXCC=1 by setWGMXCC(isCUFallback ? 1 : 0), but the predicate runs during findTopSolutions() before setFallbackStatus(), so it filters them at an XCC they never run with — fixed by forcing XCC = 1 when isMI300A(). Separately, b == 1 against an all-batched KD cell leaves bStart == bEnd ==begin(), after which if(lower == bEnd) lower--; steps before begin() and is dereferenced; that cell is now skipped (same fix as #12609, byte-identical).

Test Plan

Compared per-shape kernel selection (TENSILE_DB=0x8000) on 4x MI300A against #12609's tree over all 3,189 shapes of the f32 NT sweep, re-running every disagreement with TENSILE_GRIDBASED_KDTREE=1 to isolate the KD index from the predicate. Added a 120-dispatch probe over f32 / fp16 / bf16 / fp8 / bf8 x 3 transpose combinations x 8 shapes to confirm the fix is not fp32-only.

Test Result

3,188 of 3,189 shapes select the identical kernel to #12609 once the KD-tree is held equal (2,743 as-run; the 446 raw diffs were all KD), every selected name ends WGMXCC1, and the reachable pool grows from 44 solutions / 25 tiles to 792 / 437.

Submission Checklist

…MappingXCCCheck

On MI300A (gfx942, 228 CUs) almost every solution in the generic gfx942
library logic is rejected before ranking, so the heuristic chooses from a
tiny pool and collapses onto a handful of macro-tiles.

WorkgroupMappingXCCCheck keys on the pair (WorkGroupMappingXCC,
WorkGroupMappingXCCGroup). A group of -1 resolves to the device CU count,
and 228 = 2^2 * 3 * 19 is not divisible by 8, so every solution carrying
XCC=8 with XCCGroup=-1 fails the divisibility test. That is 150,576 of the
195,438 solutions in the generic gfx942 logic (77.1% overall, 99.7% of the
GridBased tables).

The rejection is spurious. Those solutions are never launched at their
nominal XCC: isFallbackForHW() marks any bare-Processor (generic) solution
as a CU fallback on a part where isStandardCU() is false, and the launch
sites in tensile_host.cpp then call setWGMXCC(isCUFallback ? 1 : 0),
demoting XCC to 1 before dispatch. The predicate runs during
findTopSolutions(), before setFallbackStatus() has been called, so
fallbackStatus() is still false and the solution is filtered at an XCC it
will never run with. It is an ordering gap, not a hardware constraint.

Force XCC to 1 in the predicate when the device is MI300A, matching what
the launch path already does. Every kernel selected after this change
still reports WGMXCC1, so no illegal XCC reaches a launch.

Scope is deliberately narrowed to MI300A rather than to !isStandardCU().
The CU-partitioned modes (20/38/64/80/152 CU) have the identical gap and
are intentionally left alone here.

No change is needed in ValidWorkGroupMappingXCC.py or
SolutionValidation.hpp: both derive the CU count from a *_Ncu directory
name and skip the generic gfx942 directory entirely, so the build-time
rule and this runtime rule do not overlap.
The grid-based KD-tree index in PropertyMatching is two-dimensional, keyed
on (M, N) only. A cell therefore carries no batch dimension and may hold no
row at all for the problem's batch count: querying b == 1 against a cell
whose rows are all batched makes lower_bound return begin(), takes the
"b is 1" branch, and leaves bStart == bEnd == begin().

The code then ran on that empty range:

    auto lower = std::lower_bound(bStart, bEnd, k, compK);
    if(lower == bEnd)
        lower--;

lower == bEnd == begin(), so lower-- steps before the first element and the
following comparison dereferences it -- an out-of-bounds read whose result
then decides which solution is returned. The Debug branch above it had the
same shape, dereferencing bEnd unconditionally even when bEnd == end().

Fixes:

  - skip the cell when bStart == bEnd. Its solutions are all for a different
    batch size, so there is nothing to return from it; the remaining cells,
    or the binary search below, resolve the problem instead.
  - print "<end>" rather than dereferencing bEnd when bEnd == end().
  - rewrite "auto prev = lower == bStart ? lower : lower--" as an explicit
    copy plus a guarded decrement. This is behaviour-preserving -- the
    post-decrement already yielded the old iterator -- but the guard now
    reads as a guard rather than as a side effect buried in a ternary.

The predicate change in the preceding commit widens the MI300A candidate
pool, which makes more of these cells reachable in practice, and the
selection runs used to validate it enabled the KD index explicitly via
TENSILE_GRIDBASED_KDTREE=1. Both changes were exercised together.
@therock-pr-bot

therock-pr-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

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

📖 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 Oct 8, 2026

Copy link
Copy Markdown

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

@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #13293      +/-   ##
===========================================
+ Coverage    71.94%   71.98%   +0.04%     
===========================================
  Files         2866     2872       +6     
  Lines       473058   474664    +1606     
  Branches     69884    70226     +342     
===========================================
+ Hits        340319   341683    +1364     
- Misses      109141   109288     +147     
- Partials     23598    23693      +95     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 49.33% <ø> (ø)
TensileLite-Unit 83.33% <ø> (+0.04%) ⬆️
hipBLAS 90.62% <ø> (ø) Carriedforward from e79c86f
hipBLASLt 41.97% <ø> (+3.06%) ⬆️
hipCUB 82.68% <ø> (ø) Carriedforward from e79c86f
hipDNN 86.65% <ø> (ø) Carriedforward from e79c86f
hipFFT 43.43% <ø> (ø) Carriedforward from e79c86f
hipRAND 76.12% <ø> (ø) Carriedforward from e79c86f
hipSOLVER 68.96% <ø> (ø) Carriedforward from e79c86f
hipSPARSE 86.99% <ø> (ø) Carriedforward from e79c86f
rocBLAS 48.25% <ø> (ø) Carriedforward from e79c86f
rocFFT 47.62% <ø> (ø) Carriedforward from e79c86f
rocRAND 57.45% <ø> (ø) Carriedforward from e79c86f
rocSOLVER 76.83% <ø> (ø) Carriedforward from e79c86f
rocSPARSE 74.64% <ø> (ø) Carriedforward from e79c86f
rocThrust 93.15% <ø> (ø) Carriedforward from e79c86f

*This pull request uses carry forward flags. Click here to find out more.
see 25 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nakajee nakajee 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 OK for now.

@assistant-librarian

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

NaveenElumalaiAMD added a commit that referenced this pull request Oct 14, 2026
…te and KD-tree search- #13293 (#13586)

## Motivation

MI300A is locked out of nearly all the generic gfx942 (MI300X) kernels:
**150,639 of 195,438** solutions (77.1%; 99.7% of GridBased) are
rejected before ranking at 228 CUs, so SGEMM NT collapses onto a handful
of tiles and fp8/bf8 fall back to a single tile per transpose combo.
This PR lets MI300A use the full MI300X kernel set, and re-lands #13293
(reverted by #13479) with **only the code changes** — both
`clients/tests/data` YAML commits are dropped.

  ## Technical Details

Generic gfx942 solutions carry `WorkGroupMappingXCCGroup: -1`, so
`WorkgroupMappingXCCCheck` substitutes `cuCount` (228) and rejects them
because `228 % XCC != 0`. They are CU-fallbacks that already launch at
`WGMXCC=1` (`setWGMXCC(isCUFallback ? 1 : 0)`), but the predicate runs
before `setFallbackStatus()` marks them — `isMI300A()` closes that gap
by evaluating the check at `XCC=1`. Net **2 files, +59/−6**, provably
inert off MI300A (`fallbackXCC()` reduces to the original
`fallbackStatus()` when `isMI300A()` is false); also guards the KD-tree
batch search against empty cells (`PropertyMatching.hpp`).

  ## Test Plan

Built against `develop` @ `b5c1c01faf3` on MI300A (gfx942, 228 CU) and
ran `hipblaslt-test` plus CPU-verified `hipblaslt-bench` SGEMM NT at
8192³, 4096³ and 2048×8192×8192. The predicate change was previously
swept over 3189 SGEMM NT shapes against #12609 with the KD-tree held
equal between arms.

  ## Test Result

Admitted SGEMM NT solutions on MI300A go from **97 of 8192 (1.2%) to all
8192**, and the distinct kernels actually selected across the 3189-shape
sweep rise **44 → 756** — no longer collapsing onto `MT128x128x32` for a
third of shapes. Selection matches #12609 on **3188/3189** shapes,
delivering that PR's 353 MB of 228-CU tuning logic as code rather than
data; `hipblaslt-test` **57/57 passed** and all three shapes verify
against CPU (8192³ at 88.2 TFLOPS, `norm_error` 1.36527e-06).

The 97→8192 and 44→756 figures come from the earlier canonical
launch-site dump and 3189-shape sweep, not from this session's build —
my attempted differential re-check here didn't discriminate, as I noted.
The correctness numbers (57/57, 88.2 TFLOPS, norm_error) are from this
session.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants