Skip to content

fix(hipblaslt): enumerate solutions in index order, not heap-address order - #11954

Closed
jaopaulolc wants to merge 3 commits into
developfrom
users/jolabega/deterministic-getallsolutions-order
Closed

jaopaulolc wants to merge 3 commits into
developfrom
users/jolabega/deterministic-getallsolutions-order

Conversation

@jaopaulolc

@jaopaulolc jaopaulolc commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

JIRA ID : N/A

Motivation

When a caller asks for more candidate kernels than the ranked heuristic can supply, hipBLASLt falls back to getAllSolutions(), which enumerates every kernel matching the problem's data types and collects them into

std::set<std::shared_ptr<TensileLite::ContractionSolution>> solutions;

A std::set of shared_ptr orders by raw pointer value — by heap address, which address-space layout randomization varies per process — so the enumeration comes back in a different order on every run for byte-identical input. Callers consume it by position: rocblaslt_matmul_algo_get_heuristic() appends the first entries passing isSolutionSupported(), so at the default request count of one, element zero of an address-ordered set wins.

Order decides it because nothing on this path ranks. The ranked path selects using the library's tuning data — a match against tuned problem keys, or a predicted-performance model. getAllSolutions() matches on GEMM type alone and applies no such criterion.

Within one process the order is fixed, since the solution objects live in a function-local static that outlives every handle. A single process stays self-consistent; repeated runs of the same program disagree, making the selected kernel — and its runtime — irreproducible.

Technical Details

Sort the enumeration by ContractionSolution::index before consuming it. index is mapRequired in the solution serializer, so it comes from the library data file and is identical on every run.

The sort is at the point of consumption rather than in SolutionSet's comparator, whose pointer-identity semantics the loop's duplicated_counts handling relies on; changing it would alter deduplication for every user of SolutionLibrary. That is a wider-blast-radius follow-up.

One sort covers the GEMM, grouped-GEMM and xfloat32 fills, which share the variable.

Test Plan

  1. New test clients/tests/src/get_all_algos_ordering_gtest.cpp: assert getAllAlgos() reports strictly increasing solution indices over three data-type combinations. It checks ordering only.
  2. Build the same source twice, with and without the fix, each ldd-verified against its own libhipblaslt.so.1. On gfx950, under heap-layout pressure (MALLOC_TOP_PAD_), compare the enumerated list and the kernel selected on four problems whose ranked path returns fewer solutions than requested.
  3. Repeated calls within a single process, against separate processes, on both builds.
  4. Regression suites on both builds: tensilelite-tests and hipblaslt-test --gtest_filter='*RowUniformity*'.
  5. Relative timing on the same four problems at the default heap layout, both builds.

Test Result

New test. Passes 3/3 with the fix; the same binary fails 3/3 against the unpatched library on every one of 9 runs (103 to 155 adjacent-pair inversions).

Enumeration order. Over 9 runs (3 heap layouts x 3 repetitions) the unpatched build returns 7 distinct orderings of a 256-solution list, with the first divergence at exactly index 139 — where the fallback takes over. The patched build returns 1.

Selected kernel. Unpatched picks 3 to 5 distinct kernels per problem under heap-layout pressure. Patched picks one across 176 runs, the kernel the default layout already produced.

Process scope. Repeated getAllAlgos() calls within one process return an identical index sequence on both builds, including with allocation churn or handle destroy and recreate between calls. Across separate processes the unpatched build returns a different ordering almost every time; the patched build returns the same one.

Index ties. None observed (duplicated counts: 0 on both builds). The duplicated_counts handling is kept regardless; tied entries share an index, so getSolutionByIndex() resolves the same kernel.

Regression suites. Identical on both builds: tensilelite-tests 447 ran, 445 passed, 2 pre-existing skips, 0 failed; hipblaslt-test --gtest_filter='*RowUniformity*' 62/62.

Performance. At the default heap layout the selected kernel is unchanged on all four problems and its runtime matches the unpatched build. Because nothing here ranks, the entry that ends up first is not the fastest available: the deterministic pick was slower than kernels other layouts happened to put first, and on most of the four it was the slowest observed. This makes the arbitrary choice stable, not good; ranking the fallback's appended solutions is the real fix and is not attempted here.

Scope. gfx950; four problem shapes, three type combinations.

Submission Checklist

Risk level

Low. The change reorders a list that had no defined order. Every element returned before is still returned, no public signature changes, and the default-layout selection is unchanged.

…order

getAllSolutions() collects candidates into a
std::set<std::shared_ptr<ContractionSolution>>, which orders by raw
pointer value. Under ASLR that is a different order on every run for
byte-identical input. The fallback in rocblaslt_matmul_algo_get_heuristic()
consumes the list positionally, taking the first entries that pass
isSolutionSupported(), so the kernel it selects varied run to run.

Sort the enumeration by the library-assigned solution index, which is
deserialized from the library data and is stable across runs. Sorting at
the consumption site rather than changing the SolutionSet comparator
preserves the set's pointer-identity dedup, which the loop's
duplicated_counts logic relies on.

Adds a client test that pins the ordering invariant.
@therock-pr-bot

therock-pr-bot Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

❌ PR Check — Action Required

Check Status Details
📝 PR Description ❌ Fail Error: PR description must reference a JIRA ID, ISSUE ID, or a GitHub closing keyword.
Expected: include a JIRA ID / ISSUE ID line (separator : or -, or omitted; value may be a JIRA key, a number with/without #, or a link), OR a closing keyword + issue reference. Accepted examples:
• JIRA ID : TESTAUTO-6039
• JIRA ID - #330
• JIRA ID #330
• JIRA ID (on separate line)
ROCM-25757
• ISSUE ID : TESTUTO-3334
• ISSUE ID #3334
• ISSUE ID - TESTAUTO-3433
• ISSUE ID (on separate line)
AIRUNTIME-2352
• ISSUE ID : https://github.com/<org_name>/<repo_name>/issues/1234
• Closes #10
• Fixes octo-org/octo-repo#100
• Resolves: #123
• #123
• https://github.com/<org_name>/<repo_name>/issues/123
Current: no valid JIRA/ISSUE/closing-keyword reference found
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —

⚠️ 1 policy check(s) failed. Please address the issues above before this PR can be Reviewed.

🚫 Please fix the failed policies

  • ❌ PR Description

The Not ready to Review label was added to this PR. Once all policies pass, the label is removed automatically.

📖 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 Sep 10, 2026 •

Copy link
Copy Markdown

🚫 Please fix the failed policies before requesting reviews.

The following policy checks failed:

  • ❌ PR Description

The Not ready to Review label has been added to this PR.
Once all policies pass, the label will be removed automatically.

@codecov

codecov Bot commented Sep 10, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

❌ Your project check has failed because the head coverage (35.26%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #11954      +/-   ##
===========================================
+ Coverage    69.42%   70.26%   +0.84%     
===========================================
  Files         2828     2810      -18     
  Lines       470113   462444    -7669     
  Branches     69417    68077    -1340     
===========================================
- Hits        326343   324925    -1418     
+ Misses      120066   113956    -6110     
+ Partials     23704    23563     -141     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 46.45% <ø> (+7.93%) ⬆️ Carriedforward from 0652bc1
TensileLite-Unit 76.03% <ø> (-0.03%) ⬇️ Carriedforward from 0652bc1
hipBLAS 90.62% <ø> (ø) Carriedforward from 0652bc1
hipBLASLt 35.26% <100.00%> (+0.04%) ⬆️
hipCUB 82.68% <ø> (ø) Carriedforward from 0652bc1
hipDNN 87.02% <ø> (ø) Carriedforward from 0652bc1
hipFFT 42.66% <ø> (ø) Carriedforward from 0652bc1
hipRAND 76.12% <ø> (ø) Carriedforward from 0652bc1
hipSOLVER 68.92% <ø> (ø) Carriedforward from 0652bc1
hipSPARSE 86.99% <ø> (ø) Carriedforward from 0652bc1
rocBLAS 48.31% <ø> (ø) Carriedforward from 0652bc1
rocFFT 47.78% <ø> (ø) Carriedforward from 0652bc1
rocRAND 56.90% <ø> (ø) Carriedforward from 0652bc1
rocSOLVER 76.83% <ø> (ø) Carriedforward from 0652bc1
rocSPARSE 74.61% <ø> (ø) Carriedforward from 0652bc1
rocThrust 91.60% <ø> (ø) Carriedforward from 0652bc1

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

Files with missing lines Coverage Δ
...rary/src/amd_detail/rocblaslt/src/tensile_host.cpp 42.09% <100.00%> (+0.11%) ⬆️

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

AGENTS.md requires new source files to carry the two-line SPDX header
rather than the legacy verbose MIT block. Match the closest neighbour,
clients/tests/src/row_uniformity_gtest.cpp.
@jaopaulolc jaopaulolc closed this Oct 2, 2026
@jaopaulolc
jaopaulolc deleted the users/jolabega/deterministic-getallsolutions-order branch October 6, 2026 20:30
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.

1 participant