Skip to content

fix(hipsparselt): fix TDM sparse GSU-offset and metadata batch-stride calc on gfx1250 - #12339

Open
xarey0629 wants to merge 1 commit into
developfrom
users/ed/fix-tdm-gsu-batch-sparse-gfx1250
Open

xarey0629 wants to merge 1 commit into
developfrom
users/ed/fix-tdm-gsu-batch-sparse-gfx1250

Conversation

@xarey0629

@xarey0629 xarey0629 commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

JIRA ID - AIHPSPAR-278
AIHPSPAR-278

Motivation

TDM (TDMInst=3) sparse (2:4) GEMM kernels on gfx1250 produced numerically wrong results in two independent, previously-untested scenarios:

  • TDMInst=3 + GlobalSplitU > 1: ~98% of output elements incorrect.
  • TDMInst=3 (or any TDM) + StridedBatched count > 1: metadata read from the wrong batch offset, corrupting every batch beyond batch 0.

Both TensorDataMoverLoad.calculateStartAddr() and calculateStartAddrWaveSeparated() (Components/TensorDataMover.py) treat the sparse-tracked operand's/Metadata's DepthU/bpe scaling inconsistently between the tile-address path and the GSU/batch-offset path. Existing spmm_tdm_*.yaml regression configs never caught this because they all used GlobalSplitU=[1] and Batch=1.

Technical Details

  • GSU offset (Q1): gsuOffsetBytes was computed as depthU * bpe using the full (uncompressed) DepthU for the sparse-tracked A/B operand and for Metadata, while every other address computation in this file (and initTDMDescriptor/tdmSplitLdsBoundary) already halves DepthU to account for the 2:4 compression. Each GSU group beyond group 0 therefore advanced by double the correct stride, reading from the wrong K range. Fixed by halving depthU before computing gsuOffsetBytes whenever (Sparse==1 and isA) or (Sparse==2 and isB) or isM, in both calculateStartAddr() and calculateStartAddrWaveSeparated().
  • Batch offset (Q2): the per-batch pointer advance scaled StrideXX (from the host) by bpe=0.25 for the Metadata tensor, same as for A/B. But per ContractionProblem::normalizeSparse, Metadata's host-provided stride is already expressed in metadata-native Int8 byte units (bpe=1), unlike A/B whose strides are in units of their own element type. Scaling by 0.25 again quartered the per-batch metadata offset, so batches beyond 0 read metadata from the wrong location. Fixed by using batchBpe=1 for Metadata (bpe for A/B unchanged), in both address-calc methods.
  • Extended spmm_tdm_all.yaml (gfx1250) with two new BenchmarkProblems blocks (NN, fp16, Sparse=1 and Sparse=2) covering GlobalSplitU=[1,2] combined with Batch=[1,2] — the previously-untested combination that exposed both bugs.

Test Plan

  • New GSU/batch blocks in spmm_tdm_all.yaml on real gfx1250 hardware.
  • Full regression pass over existing TDM/sparse suites: spmm_tdm_all, spmm_tdm_multicast, spmm_tdm_gl2prefetch, spmm_tdm_ldspadding, spmm_tdm_f16_transposes, tdm_general_batched_gfx1250, tdm_gfx1250, tdm_multicast_gfx1250, tdmpluslds_tdm_gfx1250.
  • gfx1250 tox (Tensile/Tests -m common -k "gfx1250 and not streamk").

Test Result

  • New GSU/batch blocks: previously ~98% mismatched elements (Q1) / batch>0 corrupted (Q2); after fix, both Sparse=1 and Sparse=2 blocks PASSED for GlobalSplitU=[1,2] x Batch=[1,2].
  • Full TDM/sparse regression sweep: 22 passed / 0 failed, no change vs. pre-fix baseline.
  • gfx1250 tox (-k "gfx1250 and not streamk"): in progress, 0 failures so far — will update this section with final counts once complete.

JIRA: https://amd-hub.atlassian.net/browse/AIHPSPAR-278

Submission Checklist

…calculation on gfx1250

TensorDataMoverLoad.calculateStartAddr() / calculateStartAddrWaveSeparated()
(Components/TensorDataMover.py) had two independent address-calc bugs for
TDM (TDMInst=3) sparse (2:4) kernels, neither caught by existing
spmm_tdm_*.yaml regression configs (all GlobalSplitU=[1], Batch=1):

- GSU offset: gsuOffsetBytes used the full (uncompressed) DepthU for the
  sparse-tracked A/B operand and for Metadata, instead of the halved
  DepthU used everywhere else in this file for those tensors. Each GSU
  group beyond group 0 advanced by double the correct stride, corrupting
  ~98% of output elements for GlobalSplitU>1.

- Batch offset: Metadata's per-batch pointer advance scaled the
  host-provided StrideXX by bpe=0.25 (same as A/B), but per
  ContractionProblem::normalizeSparse, Metadata's stride is already in
  metadata-native Int8 byte units (bpe=1). Scaling by 0.25 again
  quartered the offset, so batches beyond 0 read metadata from the
  wrong location.

Fixed both by halving depthU for the sparse-tracked operand/Metadata
before computing gsuOffsetBytes, and by using batchBpe=1 for Metadata
when scaling the batch stride, in both address-calc methods.

Extended spmm_tdm_all.yaml with two new BenchmarkProblems blocks
(Sparse=1 and Sparse=2, NN, fp16) covering GlobalSplitU=[1,2] combined
with Batch=[1,2] -- the previously-untested combination that exposed
both bugs.

Verified on gfx1250 hardware: full sparse/gfx1250 TDM regression suite
(spmm_tdm_all, spmm_tdm_multicast, spmm_tdm_gl2prefetch,
spmm_tdm_ldspadding, spmm_tdm_f16_transposes, tdm_general_batched_gfx1250,
tdm_gfx1250, tdm_multicast_gfx1250, tdmpluslds_tdm_gfx1250) passes with
no regressions; new GSU/batch blocks pass where they previously failed.

Co-authored-by: Cursor <cursoragent@cursor.com>
@therock-pr-bot

therock-pr-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass
Forbidden Files ✅ Pass
🧪 Unit Test ⚠️ Warning Error: Source/code files changed without an accompanying unit test.
Expected: add at least one test file named like test_<name>.py / test_<name>.cpp (or <name>_test.*).
Current: code file(s) changed: projects/hipblaslt/tensilelite/Tensile/Components/TensorDataMover.py; no test file found
🔎 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.

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.

Copilot review overview

🔵 Needs a closer look

One or more issues must be addressed before approval.

Review effort: Lite
Findings: None

What changed in this PR

Fixes gfx1250 sparse TDM address calculations for GSU and strided batches.

Changes:

  • Corrects compressed DepthU scaling for sparse operands and metadata.
  • Uses byte-native metadata batch strides.
  • Adds Sparse A/B GSU-and-batch regression configurations.
File Description
projects/​hipblaslt/​tensilelite/​Tensile/​Tests/​common/​sparse/​gfx1250/​spmm_tdm_all.yaml Updated as part of this pull request.
projects/​hipblaslt/​tensilelite/​Tensile/​Components/​TensorDataMover.py Updated as part of this pull request.

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

@codecov

codecov Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../tensilelite/Tensile/Components/TensorDataMover.py 60.00% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #12339      +/-   ##
===========================================
+ Coverage    70.71%   70.75%   +0.04%     
===========================================
  Files         2847     2849       +2     
  Lines       466776   468153    +1377     
  Branches     68835    69160     +325     
===========================================
+ Hits        330060   331234    +1174     
- Misses      112771   112925     +154     
- Partials     23945    23994      +49     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 48.80% <ø> (ø)
TensileLite-Unit 76.65% <60.00%> (+0.18%) ⬆️
hipBLAS 90.62% <ø> (ø) Carriedforward from 7a1cd6d
hipBLASLt 35.28% <ø> (ø) Carriedforward from 7a1cd6d
hipCUB 82.68% <ø> (ø) Carriedforward from 7a1cd6d
hipDNN 86.98% <ø> (ø) Carriedforward from 7a1cd6d
hipFFT 54.81% <ø> (ø) Carriedforward from 7a1cd6d
hipRAND 76.12% <ø> (ø) Carriedforward from 7a1cd6d
hipSOLVER 68.96% <ø> (ø) Carriedforward from 7a1cd6d
hipSPARSE 86.99% <ø> (ø) Carriedforward from 7a1cd6d
rocBLAS 48.31% <ø> (ø) Carriedforward from 7a1cd6d
rocFFT 46.27% <ø> (ø) Carriedforward from 7a1cd6d
rocRAND 57.42% <ø> (ø) Carriedforward from 7a1cd6d
rocSOLVER 76.83% <ø> (ø) Carriedforward from 7a1cd6d
rocSPARSE 74.61% <ø> (-<0.01%) ⬇️ Carriedforward from 7a1cd6d
rocThrust 93.15% <ø> (ø) Carriedforward from 7a1cd6d

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

Files with missing lines Coverage Δ
.../tensilelite/Tensile/Components/TensorDataMover.py 71.76% <60.00%> (-0.69%) ⬇️

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

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