Skip to content

fix(rocsparse): clamp extra-nightly launches to the 32-bit dispatch limit - #12546

Merged
kliegeois merged 13 commits into
ROCm:developfrom
kliegeois:task/nightly-sparse-large-grid
Oct 8, 2026
Merged

kliegeois merged 13 commits into
ROCm:developfrom
kliegeois:task/nightly-sparse-large-grid

Conversation

@kliegeois

@kliegeois kliegeois commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #12545

Summary

  • Clamp grid.x with rocsparse::get_grid_size_x, i.e. to min(maxGridSize[0], (2^32-1)/blockDim.x) (the dispatch packet's grid size is a 32-bit work-item count; HIP rejects larger launches with hipErrorInvalidConfiguration), for axpyi / axpby (scale_array), scatter, ELL SpMV (non-transposed and transposed), COO AoS SpMV (atomic non-transposed, and both transposed launches), and roti / rocsparse_rot. At nnz = 2^32 + 512 the roti grid was 8,388,609 blocks of 512, just over the limit.
  • Each clamped kernel grid-strides with a 64-bit index, so a clamped grid still covers the whole range.
  • Straight-line fast paths: scale_kernel, coomvn_aos_atomic_loops, ellmvt_kernel and the roti kernel take a bool GRID_STRIDE template parameter. The host launches the develop-shaped straight-line kernel whenever get_grid_size_x returns the full block count, and the looping kernel only when it actually clamps. A plain grid-stride conversion was measurably slower on MI300A even when the clamp did not engage (float scale_array -12.4% at 1e8+, COO AoS atomic up to -6.7%); with the fast paths every measured config is back within noise of develop (see Performance).
  • Make axpby_extra and rot_extra use size = nnz so the sparse-vector descriptor is valid (nnz <= size). rot_extra had size = 2; its device_memory_gb rises from 55 to 70 for the 64 GiB it needs. axpby_extra now uses beta = 3 so scale_array actually runs, and checks an element past 2^32. COO extra m/n sizing is already on develop via fix(rocsparse): fix sizes of two SPMV COO tests #12345.
  • gfx1151 (Windows, Strix Halo APU): hipMemGetInfo reports ~91 GiB free because it counts shared system memory, so the memory guard let the 64-80 GiB extras run and hipMalloc failed between 48 and 64 GiB. The six 2^32-element extras now use skip_hardware: gfx1151, as bsrgemm and spgemm_bsr already do. The guard itself is unchanged (capping it at host memory would also change filtering on MI300A).
  • Test client: a failed allocation left hipErrorOutOfMemory as the last HIP error, so the next test failed in rocsparse_create_handle (its hipGetLastError check). The allocator now consumes the error, and drops the %' printf flag that MSVC garbled.
  • Addresses the extras that failed in run 35830677766 and run 36391950384: gfx94X with invalid_size (4) or hipErrorInvalidConfiguration / internal_error (6); gfx1151 with invalid_size, thrown_exception (13) and the follow-on quick-test hipErrorOutOfMemory failures.

Performance (MI300A, alola job 68007075)

10 interleaved repeats with rotated order, medians of GB/s, develop vs this PR:

  • COO AoS atomic non-transposed: geomean 1.0005 over 10 configs (range 0.9996-1.0022); complex double on lap2d 1000^2 1.000 (was 0.931 before the fast path).
  • scale_array (beta = 3): geomean 0.999 over 8 configs (range 0.994-1.006); float at 1e8 / 3e8 1.006 (was 0.876 / 0.878).
  • ELL transposed: geomean 1.001; COO AoS transposed: 1.002.
    Occupancy and LDS match develop for every instantiation on gfx942 and gfx1201; the fast-path COO AoS kernels have the same instruction count as develop.

Test plan

  • Alola MI300X (gfx942), job 67983810: rocsparse-test --gtest_filter='nightly/axpby.level1/axpby_extra:nightly/scatter.level1/scatter_extra:nightly/spmv_ell.level2/spmv_ell_extra:nightly/spmv_coo.level2/spmv_coo_extra:nightly/spmv_coo_aos.level2/spmv_coo_aos_extra' — 5/5 PASSED.
  • gfx1201 (15 GB): nightly/*extra* — all six 2^32-element extras filtered by the memory guard (rot at 70 GB); 2513 other nightly .extra tests PASSED.
  • gfx1201: *axpby*:*coomv*:*ellmv*:*spmv_coo*:*spmv_ell* — 2879 PASSED, also with every changed launch capped at 3 blocks to force the grid-stride path; quick + pre_checkin rot / roti / axpby / sctr / scatter — 1094 PASSED; rocsparse-unit-test-device — 504 PASSED, including the new device_level1_roti.grid_stride.
  • gfx1201, custom --yaml: forced rot_extra fails its 32 GiB allocation and the next test in the suite passes. With skip_hardware: gfx1201 the entry is not registered.
  • rot_extra at full size on gfx942 (the nightly will exercise it).
  • PR CI on gfx94X and gfx1151 rocSPARSE shards.
  • hipSPARSE gfx94X in the same nightly already passed; gfx950 hipSPARSE abort was SRAM ECC, not this change.

Made with Cursor

…imit

CDNA rejects grid.x * blockDim.x above UINT32_MAX, and axpby_extra used nnz > size. Clamp axpyi, scatter, ELL-N, and COO AoS atomic launches and make the extra test descriptors valid.

Fixes ROCm#12545

Co-authored-by: Cursor <cursoragent@cursor.com>
@kliegeois
kliegeois requested a review from a team as a code owner September 24, 2026 17:50
@kliegeois
kliegeois requested a review from a team as a code owner September 24, 2026 17:50
@therock-pr-bot

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

Copy link
Copy Markdown

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

@codecov

codecov Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.20611% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...se/library/src/level2/rocsparse_coomv_aos_impl.cpp 75.86% 5 Missing and 2 partials ⚠️
.../rocsparse/library/src/common/rocsparse_common.cpp 77.27% 3 Missing and 2 partials ⚠️
...ts/rocsparse/library/src/level1/rocsparse_roti.cpp 81.48% 3 Missing and 2 partials ⚠️
...sparse/library/src/level2/rocsparse_ellmv_impl.cpp 89.36% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #12546      +/-   ##
===========================================
- Coverage    71.93%   70.60%   -1.33%     
===========================================
  Files         2863     2939      +76     
  Lines       472710   484516   +11806     
  Branches     69829    69781      -48     
===========================================
+ Hits        340010   342058    +2048     
- Misses      109117   118582    +9465     
- Partials     23583    23876     +293     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 48.82% <ø> (-0.51%) ⬇️ Carriedforward from 46a9d55
TensileLite-Unit 82.58% <ø> (-0.71%) ⬇️ Carriedforward from 46a9d55
hipBLAS 90.62% <ø> (ø) Carriedforward from 46a9d55
hipBLASLt 35.59% <ø> (-3.33%) ⬇️ Carriedforward from 46a9d55
hipCUB 82.68% <ø> (ø) Carriedforward from 46a9d55
hipDNN 86.70% <ø> (+0.06%) ⬆️ Carriedforward from 46a9d55
hipFFT 54.32% <ø> (+10.89%) ⬆️ Carriedforward from 46a9d55
hipRAND 76.12% <ø> (ø) Carriedforward from 46a9d55
hipSOLVER 68.96% <ø> (ø) Carriedforward from 46a9d55
hipSPARSE 86.99% <ø> (ø) Carriedforward from 46a9d55
rocBLAS 48.25% <ø> (-<0.01%) ⬇️ Carriedforward from 46a9d55
rocFFT 46.67% <ø> (-0.95%) ⬇️ Carriedforward from 46a9d55
rocRAND 57.42% <ø> (-0.03%) ⬇️ Carriedforward from 46a9d55
rocSOLVER 76.83% <ø> (+<0.01%) ⬆️ Carriedforward from 46a9d55
rocSPARSE 74.63% <83.21%> (-0.01%) ⬇️
rocThrust 78.34% <ø> (-14.81%) ⬇️ Carriedforward from 46a9d55

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...s/rocsparse/library/src/level1/rocsparse_axpyi.cpp 98.55% <100.00%> (-0.02%) ⬇️
...csparse/library/src/level1/rocsparse_sctr_impl.cpp 93.88% <100.00%> (-0.12%) ⬇️
.../rocsparse/library/src/common/rocsparse_common.cpp 88.00% <77.27%> (-2.91%) ⬇️
...ts/rocsparse/library/src/level1/rocsparse_roti.cpp 87.50% <81.48%> (-4.56%) ⬇️
...sparse/library/src/level2/rocsparse_ellmv_impl.cpp 83.71% <89.36%> (-1.14%) ⬇️
...se/library/src/level2/rocsparse_coomv_aos_impl.cpp 61.70% <75.86%> (+0.22%) ⬆️

... and 273 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.

# Conflicts:
#	projects/rocsparse/library/src/include/rocsparse_common.hpp
axpby scales y before axpyi. For size > 2^32 - 256 the scale_kernel<256>
grid exceeded the 32-bit dispatch limit, and scale_device formed its
index with a 32-bit multiply. Clamp the grid with get_grid_size_x and
grid-stride in 64-bit.

axpby_extra now uses beta = 3 so the scale kernel is launched, and
checks the last element of y as well as the probe.
The LOOPS=2 fallback launched ceil(nnz / 512) blocks without a clamp,
which is illegal again past nnz = 2^33 - 512, and the transposed
coomvt_aos launch was never clamped. The atomic kernel now strides over
LOOPS * BLOCKSIZE tiles and coomvt_aos grid-strides over nnz, so both
launches use a get_grid_size_x-clamped grid and the LOOPS=2 variant is
removed.
ellmvt launched ceil(m / 1024) blocks with no clamp, which exceeds the
32-bit dispatch limit for m > 2^32 - 1024. Clamp the grid with
get_grid_size_x and grid-stride over rows in 64-bit, as ellmvn does.
roti_template clamped grid.x only to maxGridSize[0]. For a 64-bit index
and nnz just past 2^32 that is 8388609 blocks of 512 threads, which
exceeds the 2^32 - 1 work-item dispatch limit, so the launch is rejected
with hipErrorInvalidConfiguration.

Clamp with rocsparse::get_grid_size_x and select the kernel variant on
the host: a straight-line kernel with a 32-bit element index when the
grid is not clamped, and a grid-stride loop with a 64-bit index only
when it is. The 64-bit index also removes the signed overflow that the
I-typed grid-stride step could hit for 32-bit indices and nnz > 2^30.
rot_extra created a sparse vector of size 2 holding 2^32 + 512 entries.
A sparse-vector descriptor requires nnz <= size, so rocsparse_rot
returned rocsparse_status_invalid_size before reaching the kernel. Use
size = nnz as axpby_extra does, and raise device_memory_gb to 70 for the
64 GiB of device data this now needs.
On gfx1151 (Windows, Strix Halo APU) hipMemGetInfo reports about 91 GiB
free because it counts shared system memory, so the memory guard lets
the 64-80 GiB extras run. hipMalloc then fails between 48 and 64 GiB:
scatter_extra, spmv_ell_extra, spmv_coo_extra and spmv_coo_aos_extra
threw in the nightly. Skip the six extras there, as bsrgemm and
spgemm_bsr already do, rather than change the guard for every APU.

Also correct the axpby_extra comment: 16 * nnz bytes is 64 GiB.
A failed hipMalloc leaves hipErrorOutOfMemory as the last error. The
client turned it into std::bad_alloc without consuming it, so the next
test failed in rocsparse_create_handle, whose hipGetLastError check
"prior to hipLaunchKernelGGL" picked up the stale error. On gfx1151 the
first quick test after each throwing extra failed this way. Consume the
error when reporting the failure.

Also drop the %' printf flag, which MSVC does not support and which
garbled the size in the message.
…array when the grid is not clamped

The grid-stride loops added for the clamped-grid fixes cost up to 12% on
MI300A even when the grid is not clamped: the float scale_array loop is
unrolled with 64-bit trip-count logic, and the COO AoS atomic kernel pays
for the tile loop and its extra barrier.

scale_kernel, coomvn_aos_atomic_loops and ellmvt_kernel take a GRID_STRIDE
template parameter. The host launches the straight-line instantiation, one
element, tile or row per thread or block as on develop, whenever
get_grid_size_x returns the full block count, and the looping instantiation
only when it clamps.
@kliegeois
kliegeois enabled auto-merge (squash) October 5, 2026 22:09
@kliegeois
kliegeois merged commit 36f9850 into ROCm:develop Oct 8, 2026
115 of 116 checks passed
kliegeois added a commit to kliegeois/rocm-libraries that referenced this pull request Oct 8, 2026
…E-699/700)

ROCm#12546 rewrites scale_device, scale_kernel and the scale_array launch with
a clamped grid.x and a compile-time GRID_STRIDE fast path. This PR rewrote
the same code with an always-on stride loop, so the two conflicted in
rocsparse_common.cpp. Restore those three to develop so ROCm#12546 owns them.

valset_2d, scale_2d, axpby and axpby_batched keep their 64-bit counts,
clamped grids and stride loops; none of them used the removed scale code.
The "why length is widened" comment moves from scale_kernel to
axpby_kernel. The gemmi m * n fix is unchanged and still passes a 64-bit
length to scale_array.

scale_array_grid_stride stays: it passes against develop's unclamped
launch and covers ROCm#12546's GRID_STRIDE path once both are merged.

Co-authored-by: Cursor <cursoragent@cursor.com>
@assistant-librarian

Copy link
Copy Markdown
Contributor

TheRock Submodule Bump Activity

Newest first

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.

[Issue] Linux gfx94X-dcgpu rocsparse nightly: extra tests fail with invalid_size / hipErrorInvalidConfiguration

4 participants