Skip to content

fix(frontend): stop autotune demanding variant pack entries for value-carrying scalars - #11506

Open
SamuelReeder wants to merge 1 commit into
developfrom
users/sareeder/autotune-pass-by-value-uids
Open

fix(frontend): stop autotune demanding variant pack entries for value-carrying scalars#11506
SamuelReeder wants to merge 1 commit into
developfrom
users/sareeder/autotune-pass-by-value-uids

Conversation

@SamuelReeder

@SamuelReeder SamuelReeder commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

autotuneImpl() requires the variantPack to carry a UID for every non-virtual tensor. A scalar that carries a baked value — a compile-time constant, or a runtime-with-default — reaches the provider through the op-graph flatbuffer, not the variantPack (RFC 0016 §2.2), so it has no pointer to give. execute() accepts a pack that omits it; autotune() rejects the same pack. Any graph containing a baked scalar is therefore impossible to autotune.

JIRA ID : ALMIOPEN-2462

Risk Assessment

Risk level: 2 (low). The change narrows one predicate to exempt a tensor class that provably has no pointer to supply, matching the pack shape execute() already accepts. It cannot mask a genuinely absent operand: non-virtual tensors that carry no baked value — including runtime user-supplied scalars, which are variantPack-delivered as host pointers — remain required, and a dedicated test pins that. The blast radius is autotuneImpl()'s pre-flight check; no execution, compilation, or ranking path changes. The main residual risk is a provider that expects a pointer for a tensor carrying a baked value, which would contradict RFC 0016 §2.2 and would already be broken under execute().

ASIC Coverage

Passing PR CI is sufficient — no specific-ASIC run required. The change is host-side graph validation with no kernel, code-object, or arch-dependent behavior: it reads TensorAttributes metadata and decides whether to append a UID to an error list. Behavior is identical across all GFX families. The functional evidence below was nonetheless collected on gfx90a (MI210).

Testing Summary

Before the fix, five engine rows across three op classes could not be tuned:

batchnorm_training           -> missing required ... UIDs: 4, 7   (epsilon, momentum)
rmsnorm                      -> missing required ... UIDs: 3      (epsilon)
batchnorm_inference_variance -> missing required ... UIDs: 6      (epsilon)

After the fix, the same sweep over 21 sample graphs tunes 22 of 22 applicable rows with 0 errors (previously 17 of 22 with 5 errors). Correctness results are unchanged.

Writing R for _isRuntimePassByValue and V for hasValue(), the three states and the two getters that discriminate them:

R V kind get_has_compile_time_constant() get_pass_by_value().has_value() required?
0 0 ordinary tensor yes
0 1 compile-time constant no
1 1 runtime-with-default no
1 0 runtime user-supplied yes

Both terms are load-bearing. Rebuilding the validator against four predicates fails a distinct test each time:

predicate ...CompileTimeConstantScalars ...RuntimeDefaultScalars ...RuntimeUserSuppliedScalars
unpatched (no exemption) FAIL FAIL pass
get_is_pass_by_value() pass pass FAIL
compile-time-constant term only pass FAIL pass
this change pass pass pass

Row 2 is why the predicate is not get_is_pass_by_value(): that getter is R || V, true also for the runtime user-supplied kind, which must appear in the pack. Row 3 is why one term does not suffice: get_has_compile_time_constant() is !R && V, so it misses runtime-with-default, whose value is equally baked.

Testing Checklist

  • Unit (frontend) - ./bin/hipdnn_frontend_tests - Status: Passed (2123 tests from 129 suites)
  • Unit (targeted) - --gtest_filter="TestGraph.Autotune*Scalars" - Status: Passed (3/3)
  • Negative control - rebuilt against three alternative predicates - Status: Each fails a distinct test, as tabulated above
  • Functional (gfx90a / MI210) - autotune sweep over 21 sample graphs via Python frontend - Status: Passed (22/22 rows tuned, 0 errors)
  • Formatting - clang-format --dry-run --Werror on both changed files - Status: Passed
  • PR CI - GitHub PR checks - Status: Pending

Technical Changes

projects/hipdnn/frontend/include/hipdnn_frontend/Graph.hpp

The variantPack completeness check inside autotuneImpl() gains two predicates:

if(tensor && tensor->has_uid() && !tensor->get_is_virtual()
   && !tensor->get_has_compile_time_constant()
   && !tensor->get_pass_by_value().has_value())

The two terms are disjoint (!R && V and R && V) and their union is exactly the private hasValue(), spelled through public getters.

The check itself is deliberately kept. It fails fast with a precise message before a sweep compiles and benchmarks many plans; without it an incomplete pack reaches populateBaseVariantPackDescriptor, which copies the map verbatim with no notion of a required tensor, and the failure surfaces backend-side as a missing pointer. Only the predicate was wrong. Removing the block entirely — restoring symmetry with execute(), which performs no completeness check at all — is a defensible but separate design decision, and would delete the three existing tests under "Autotune UID Validation Tests"; I did not take it.

projects/hipdnn/frontend/tests/TestGraph.cpp

Adds AutotuneDoesNotRequireUidsForCompileTimeConstantScalars, AutotuneDoesNotRequireUidsForRuntimeDefaultScalars and AutotuneStillRequiresUidsForRuntimeUserSuppliedScalars beside the existing autotune UID-validation tests, sharing a small createBatchnormGraphWithEpsilon helper. All three build a batchnorm graph with an epsilon scalar, mirroring the graphs that failed in practice, and differ only in epsilon's state.

Notes for reviewers

Two incidental observations, neither addressed here:

  • The tensor->has_uid() term in this loop appears vestigial. lowerGraphToDescriptors() calls assignUnsetTensorUids() before validation, and this check runs only after hasReadyGraphDesc() passes, so every tensor already has a UID by then. Pre-existing; left alone to keep the diff minimal.
  • Adding an equivalent completeness check to execute() would restore symmetry, but gatherHipdnnTensorsSubtree() builds a hash set over the whole graph on every call, which would land inside the timed region of any benchmark loop. If it is ever wanted, computing the required-UID set once at build time and caching it would avoid the per-execute traversal.

autotuneImpl() requires the variantPack to carry a UID for every
non-virtual tensor. A scalar that carries a baked value - a compile-time
constant, or a runtime-with-default - reaches the provider through the
op-graph flatbuffer, not the variantPack (RFC 0016 section 2.2), so it
has no pointer to give. execute() accepts a pack that omits it;
autotune() rejects the same pack, which makes any graph containing a
baked scalar impossible to autotune.

Observed on gfx90a through the Python frontend:

  batchnorm_training           -> missing required ... UIDs: 4, 7
                                  (epsilon, momentum)
  rmsnorm                      -> missing required ... UIDs: 3  (epsilon)
  batchnorm_inference_variance -> missing required ... UIDs: 6  (epsilon)

The requirement is also unsatisfiable for the runtime-with-default kind:
RFC 0016 section 2.2 states an attempted variantPack override of one
errors, so the caller can neither omit the entry nor supply it.

Exempt the two value-carrying kinds. get_is_pass_by_value() is not the
right predicate: it is _isRuntimePassByValue || hasValue(), true also for
a runtime user-supplied scalar, which carries no value and *is* delivered
through the variantPack as a host pointer. get_has_compile_time_constant()
alone is not sufficient either: it is !_isRuntimePassByValue && hasValue(),
so it misses the runtime-with-default kind whose value is equally baked.
The two terms are disjoint and their union is exactly hasValue(), which
is private.

The check itself is kept. It fails fast with a precise message before a
sweep compiles and benchmarks many plans; without it an incomplete pack
reaches the backend as a missing pointer. Only its predicate was wrong.

Adds three tests on a batchnorm graph with an epsilon scalar, one per
state, mirroring the graphs that failed in practice:

  ...ForCompileTimeConstantScalars      (!runtime,  value) -> exempt
  ...ForRuntimeDefaultScalars           ( runtime,  value) -> exempt
  ...ForRuntimeUserSuppliedScalars      ( runtime, novalue) -> required

Each term is load-bearing; rebuilding the validator against four
predicates fails a distinct test:

  unpatched (no exemption)         first two FAIL
  get_is_pass_by_value() (broad)   third FAILS
  compile-time constant term only  second FAILS
  this change                      all pass

Existing coverage is untouched: AutotuneRejectsMissingTensorUids,
AutotuneAcceptsCompleteVariantPack and AutotuneAcceptsExtraUidsInVariantPack
use no value-carrying tensors and pass unmodified.

Test: hipdnn_frontend_tests, 2123 tests from 129 suites, all pass.
@therock-pr-bot

therock-pr-bot Bot commented Aug 31, 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.

@SamuelReeder
SamuelReeder marked this pull request as ready for review August 31, 2026 20:39
@SamuelReeder
SamuelReeder requested a review from a team as a code owner August 31, 2026 20:39
@SamuelReeder SamuelReeder changed the title fix(frontend): stop autotune demanding UIDs for value-carrying scalars fix(frontend): stop autotune demanding variant pack entries for value-carrying scalars Aug 31, 2026
@SamuelReeder SamuelReeder self-assigned this Aug 31, 2026

@BrianHarrisonAMD BrianHarrisonAMD 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.

LGTM, thanks for the fix.

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../hipdnn/frontend/include/hipdnn_frontend/Graph.hpp 66.67% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #11506      +/-   ##
===========================================
+ Coverage    69.72%   69.72%   +0.01%     
===========================================
  Files         2810     2811       +1     
  Lines       464097   464154      +57     
  Branches     68444    68447       +3     
===========================================
+ Hits        323551   323625      +74     
+ Misses      117028   117017      -11     
+ Partials     23518    23512       -6     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 38.33% <ø> (ø) Carriedforward from e7b7720
TensileLite-Unit 76.15% <ø> (ø) Carriedforward from e7b7720
hipBLAS 90.62% <ø> (ø) Carriedforward from e7b7720
hipBLASLt 35.22% <ø> (ø) Carriedforward from e7b7720
hipCUB 82.68% <ø> (ø) Carriedforward from e7b7720
hipDNN 86.88% <66.67%> (+0.04%) ⬆️
hipFFT 43.77% <ø> (ø) Carriedforward from e7b7720
hipRAND 76.12% <ø> (ø) Carriedforward from e7b7720
hipSOLVER 69.03% <ø> (ø) Carriedforward from e7b7720
hipSPARSE 86.99% <ø> (ø) Carriedforward from e7b7720
rocBLAS 48.26% <ø> (ø) Carriedforward from e7b7720
rocFFT 51.48% <ø> (ø) Carriedforward from e7b7720
rocRAND 56.91% <ø> (ø) Carriedforward from e7b7720
rocSOLVER 77.32% <ø> (ø) Carriedforward from e7b7720
rocSPARSE 74.60% <ø> (ø) Carriedforward from e7b7720
rocThrust 91.60% <ø> (ø) Carriedforward from e7b7720

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

Files with missing lines Coverage Δ
.../hipdnn/frontend/include/hipdnn_frontend/Graph.hpp 79.61% <66.67%> (+0.01%) ⬆️

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