Skip to content

fix: [hipblaslt] AIHPBLAS-4228 Fix Stream-K launch limits and add unit tests - #12204

Merged
yenong-amd merged 4 commits into
developfrom
users/yenong-amd/fix-sk-launchlimits
Sep 18, 2026
Merged

yenong-amd merged 4 commits into
developfrom
users/yenong-amd/fix-sk-launchlimits

Conversation

@yenong-amd

@yenong-amd yenong-amd commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

JIRA ID: AIHPBLAS-4228

Motivation

hipBLASLt launches Stream-K kernels (work split along the inner dimension K) through TensileLite’s host solution code. For very large problems the old tree-fixup path set the launch grid to the full tile count. When that count is at or above 2^24 work-items (HIP’s 32-bit work-item limit, also the tree-fixup 24-bit dividend bound), the launch fails. One failing size is M=524288, N=98304, K=128 with a 32×96 tile.

Technical Details

In tensilelite/src/ContractionSolution.cpp, the tree-fixup fallback now computes the maximum tile count as (UINT32_MAX+1) / threadsPerWorkGroup. If tiles reach that cap, the grid is cuCount * occupancy (occupancy at least 1, still capped at 3 on the Force-DP-only path). Below the tile cap, the previous data-parallel fallback (skGrid = tiles) is unchanged. workGroupSize is set on Stream-K launch-summary fixtures so the new bound is defined.

Test Plan

  • Host gtest: SKLaunchGridLimitsTest / SKLaunchGridLimitsParamTest in tensilelite/tests/CuCount_test.cpp (tile-cap, origami path, below-threshold DP fallback, bench macro-tiles).
  • Shared CI: Math CI tensilelite-unit-codecov, preliminary, precheckin (hipblaslt); gfx94X hipBLASLt multi-arch shards.
  • Author-run (no CI link): tensilelite-tests on gfx950 and gfx942.

Test Result

tensilelite-unit-codecov, hipblaslt preliminary/precheckin, and gfx94X hipBLASLt shards passed. hipBLASLt ASAN gfx90a quick failed (container/test not classified). codecov(hipblaslt) Math CI failed. gfx950 device results are author-reported only.

Submission Checklist

Risk level

Medium (3/5): changes default Stream-K launch size for huge tile counts. Host unit tests cover the cap; ASAN and hipBLASLt codecov are not green; gfx950 is not in the PR’s GPU CI.

@therock-pr-bot

therock-pr-bot Bot commented Sep 16, 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

Copy link
Copy Markdown

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

@codecov

codecov Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #12204      +/-   ##
===========================================
+ Coverage    70.54%   70.55%   +0.01%     
===========================================
  Files         2812     2812              
  Lines       463054   463065      +11     
  Branches     68187    68189       +2     
===========================================
+ Hits        326661   326705      +44     
+ Misses      112749   112708      -41     
- Partials     23644    23652       +8     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 46.40% <ø> (ø)
TensileLite-Unit 76.10% <ø> (+<0.01%) ⬆️
hipBLAS 90.62% <ø> (ø) Carriedforward from 2ccaf86
hipBLASLt 35.24% <ø> (ø) Carriedforward from 2ccaf86
hipCUB 82.68% <ø> (ø) Carriedforward from 2ccaf86
hipDNN 87.01% <ø> (ø) Carriedforward from 2ccaf86
hipFFT 43.25% <ø> (ø) Carriedforward from 2ccaf86
hipRAND 76.12% <ø> (ø) Carriedforward from 2ccaf86
hipSOLVER 68.96% <ø> (ø) Carriedforward from 2ccaf86
hipSPARSE 86.99% <ø> (ø) Carriedforward from 2ccaf86
rocBLAS 48.31% <ø> (+0.06%) ⬆️ Carriedforward from 2ccaf86
rocFFT 51.59% <ø> (ø) Carriedforward from 2ccaf86
rocRAND 57.42% <ø> (ø) Carriedforward from 2ccaf86
rocSOLVER 76.83% <ø> (ø) Carriedforward from 2ccaf86
rocSPARSE 74.61% <ø> (ø) Carriedforward from 2ccaf86
rocThrust 91.60% <ø> (ø) Carriedforward from 2ccaf86

*This pull request uses carry forward flags. Click here to find out more.
see 8 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.

@yenong-amd yenong-amd changed the title fix: [hipblaslt] Fix Stream-K launch limits and add unit tests fix: [hipblaslt] AIHPBLAS-4228 Fix Stream-K launch limits and add unit tests Sep 18, 2026
@yenong-amd
yenong-amd merged commit e19ff21 into develop Sep 18, 2026
235 of 254 checks passed
@yenong-amd
yenong-amd deleted the users/yenong-amd/fix-sk-launchlimits branch September 18, 2026 18:13
@assistant-librarian

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

tony-davis added a commit that referenced this pull request Sep 25, 2026
…nch guard

#12204, merged after this PR was opened, changed the tree-fixup fallback in
getSKGridImpl(). Once the tile count reaches (UINT32_MAX + 1) /
threadsPerWorkGroup, it now launches cuCount * occupancy instead of one
workgroup per tile. That was the main path StreamKWorkgroupNumberCheck existed
to keep selection away from. With it fixed, the predicate rejects every
Stream-K solution at or above that tile count, including ones that now run
correctly whenever the workspace fits, so it throws away working candidates.

Remove the predicate, its serialization and Python emission, its gtests, the
characterization test for the isStreamK arm, and the DECISIONS.md entry. This
also drops the float-precision test that review found never crossed the
boundary.

The launch guard in SolutionAdapter::launchKernel stays and is now the whole
fix. Paths that still hand Stream-K one workgroup per output tile (the
insufficient-workspace fallback in resolveStreamKSettings(), K == 0, the
data-parallel debug knob) and the skFixedGrid / skGridMultiplier overrides
fail with hipErrorInvalidValue instead of launching a truncated grid. Its
comments now say that instead of pointing at the removed predicate.

A selection-time check that resolves the grid that will actually launch,
workspace fallback included, is the better fix on the selection side. It is
left to a follow-up; see the review discussion on #12283.

tensilelite-tests on gfx950 (MI355X): 500 ran, 497 passed, 3 skipped (the
same three noted in the PR description).

ROCM-31290

Co-authored-by: Cursor <cursoragent@cursor.com>
tony-davis added a commit that referenced this pull request Sep 28, 2026
…2 bits (#12283)

JIRA ID : ROCM-31290

## Motivation

hipBLASLt launches each GEMM kernel with a grid, the number of parallel
work items the hardware should run. `KernelInvocation` holds that grid
in a 64-bit type, but both launch entry points take 32-bit grid
parameters. `hipExtModuleLaunchKernel` declares its `globalWorkSize`
arguments as `unsigned int`, and the cluster path's `gridDim` fields are
the same width. A grid too large to express was narrowed at the call
rather than refused.

That produces two outcomes. A work-item count of exactly 2^32 narrows to
zero, and HIP rejects the launch with an error. A count above 2^32
narrows to its low 32 bits, a small non-zero number, so the launch
succeeds while only a fraction of the intended workgroups run. The
output tiles the missing workgroups would have written keep whatever the
buffer held before, and `hipblasLtMatmul` returns success.

Stream-K kernels reach this most easily. They normally size their grid
to the compute-unit count, but several paths hand them one workgroup per
output tile instead, and solution selection's `LaunchLimits` check
exempts Stream-K.

## Technical Details

`SolutionAdapter::launchKernel` now validates the grid and returns
`hipErrorInvalidValue` when it does not fit, with a diagnostic naming
the offending dimensions. The check runs first, before the code object
is looked up, since that is the last point where the 64-bit values are
still intact.

The two launch paths narrow different quantities, so each is bounded
against the one it actually passes. `hipDrvLaunchKernelEx` takes the
grid in workgroups and is bounded on `numWorkGroups`.
`hipExtModuleLaunchKernel` takes work items and is bounded on
`numWorkItems`. A single shared check would wrongly reject a cluster
launch whose workgroup count fits even though the work-item product does
not.

#12204 already fixed the most common way to get there, the tree-fixup
fallback in `getSKGridImpl()`, which now launches `cuCount * occupancy`
once the tile count reaches the thread-aware cap. The paths that remain
include the insufficient-workspace fallback in
`resolveStreamKSettings()`, K == 0, the data-parallel debug knob, and
the `skFixedGrid` / `skGridMultiplier` overrides. The guard turns all of
them from silent truncation into a loud error.

Earlier revisions of this PR also added a selection-time predicate,
`StreamKWorkgroupNumberCheck`. It was removed in review. After #12204 it
rejected Stream-K solutions that now run correctly, and a check that
resolves the grid that will actually launch is a better fit for the
selection side. That is left to a follow-up.

This changes host-side launch validation only. No kernel code or
solution selection changes.

## Test Plan

- `tensilelite-tests`, `tensilelite/tests/LaunchDimGuard_test.cpp`. Six
cases that drive `SolutionAdapter::launchKernel` directly with a
synthetic `KernelInvocation`, so no GPU work is dispatched and no kernel
needs to exist. They cover the 2^32 boundary, the silent case above it,
the largest grid that must still pass, an oversized y dimension, and
both directions of the cluster path's workgroups-versus-work-items
distinction.
- Full `tensilelite-tests` suite on gfx950 to check nothing else moved.

Not covered: rocblaslt's rocRoller custom kernels call
`hipExtModuleLaunchKernel` directly and never reach `SolutionAdapter`.
That path builds its grid from `uint32_t` tile counts, so its failure
mode is arithmetic overflow rather than narrowing, which is tracked
separately as ROCM-31230.

## Test Result

`tensilelite-tests` on an MI355X (gfx950), MessagePack configuration:
500 ran, 497 passed, 3 skipped. The three skips are unrelated and also
skip on `develop`: `RangeLibraryTest.SpecificSizes/0`,
`MXDataGenFP4Test.ZeroFrequencyWithinBounds/3`, and
`DataInitializationReferenceRecompute.Gfx1250ReusesPreswizzledMXAcrossSolutions`.

For context on impact, a hardware sweep against the TheRock
`10.1.0a20260822` library (which predates #12204) found 39 Stream-K
algorithms at M = 19,398,656, N = 256 that returned success with part of
the output never written, 22 of them leaving exactly 2^32 elements
unwritten. #12204 fixes most of those at that shape. The sweep was not
rerun against a current library.

## Submission Checklist

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

## Risk level

Low (2/5). The guard is a few integer comparisons at the top of the
launch path, and it only changes behavior for grids that could not have
run correctly. Solution selection is unchanged.

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tony-davis <7938412+tony-davis@users.noreply.github.com>
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