Skip to content

test(rocfft): cover unit-length axes, embedded views and preconditions in data_set tests - #14585

Open
regan-amd wants to merge 6 commits into
developfrom
users/regan-amd/rocfft-data-layout-test-gaps
Open

regan-amd wants to merge 6 commits into
developfrom
users/regan-amd/rocfft-data-layout-test-gaps

Conversation

@regan-amd

@regan-amd regan-amd commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

JIRA ID : AIFFT-543

Follow-up to #12667. Deliberately breaking data_set.cpp showed several bugs that the merged data_set_t tests could not catch, mostly because they never generated unit-length axes (e.g. a batch of 1) or embedded views, or only checked a few fixed data sets. Some of those code paths are used by multi-device plans in plan.cpp. Writing the missing tests also turned up a small library issue: get_other_inplace_data_set_for could return a real data set with an innermost length of 0.

This PR is based on #14063 (data_layout_t renamed to data_set_t) and also addresses wording that the rename left behind.

Technical Details

Six commits, best reviewed one at a time:

  1. --num_random_cases option for rocfft-internal-test (default 200, must be positive), next to --seed. The randomized data_set tests use it instead of a hard-coded constant; a failing case replays with the same --seed and at least as many --num_random_cases.
  2. Data set queries:
    • offset_in: random data sets now include unit-length axes; data sets with the same total number of axes but a different length/batch split are rejected.
    • continuous_chunk: random spans (some of them 1) in random axis order, so the slowest-varying axis is not always the last one; the unit-length skip in slowest_varying_axis() was previously untested.
    • same_logical_range: new; has_same_logical_range_as was not called by any test.
    • contiguous_strides: randomized, with the expected contiguity derived from how the data set is built.
    • intersection: different length/batch splits and different embeddings are rejected, and a shared embedding is kept in the result.
  3. In-place data sets:
    • inplace_complex_is_unchanged: random data sets, possibly partial along batch axes and embedded, for either complex direction and either I/O side; embedding maps are compared separately since operator== ignores them.
    • inplace_real_round_trip: also runs on embedded views keeping the embedding's innermost axis, as used by multi-device plans, and checks that the Hermitian side of a view is the view of the Hermitian side of the whole.
    • inplace_real_counterpart_rules (renamed from inplace_real_refuses_impossible_layouts): random data sets built by nesting their axes, for either real direction and either side, checking both acceptance and the derived data set. The data sets are never self-aliased, and neither are their counterparts whenever the per-axis stride rules hold. The test's comment documents that its expected acceptance currently restates the library's per-axis rules (a known weakness that goes away once the library detects self-aliasing).
  4. Library fix: data_set_t::get_other_inplace_data_set_for now throws std::invalid_argument when asked for the real side of a Hermitian innermost length of 1 with other_innermost_length_is_odd = false, which would otherwise give a real innermost length of 0. Current callers in plan.cpp compute that flag from actual lengths and are not affected, so there is no user-visible change. The function's documentation is updated accordingly.
  5. Wording left over from refactor(rocfft): rename data_layout_t to data_set_t #14063 in data_set.{h,cpp}: comments and error messages that still called data_set_t objects layouts now call them data sets (e.g. get_other_inplace_data_set_for was documented to return the "corresponding output (resp. input) layout"). "layout" is kept where it refers to the in-buffer arrangement of the data, to the public rocfft_plan_description_set_data_layout, or to the layout members of descriptions and bricks that refactor(rocfft): rename data_layout_t to data_set_t #14063 leaves for a separate rename. No functional change beyond the wording of error messages.
  6. Same wording in data_set_test.cpp: variables and trace labels named layout (layout_1d, layout_2d, ...) are renamed to data_set, and the matching comments reworded.

Known limitation, not addressed here: get_other_inplace_data_set_for checks strides one axis at a time, so it can accept a real data set whose Hermitian counterpart is self-aliased (e.g. lengths {8, 2, 2} with strides {1, 10, 18}). Self-aliasing detection is planned separately; the tests do not generate such data sets.

The randomized tests use a new random seed on every run by default. On failure, the seed is printed and attached to every assertion message, so the case replays with --seed <value> --gtest_filter=<test>.

Test Plan

Before rebasing onto #14063 (commits 1-4):

  • CMake build of librocfft and rocfft-internal-test (Release, -DWERROR=ON, -DROCFFT_BUILD_INTERNAL_TESTS=ON, RCCL on, gfx1201) with amdclang++ from a TheRock build of ROCm 10.3.0 and from ROCm 7.0.2, then ctest, and the data_layout tests with seeds 0-499 and with --num_random_cases 5000.
  • Each commit built on its own (g++ and amdclang++, project warning flags plus -Werror) and run with 200-500 seeds; the final tree with seeds 0-1999 (g++) and 0-299 (amdclang++).
  • Mutation checks: the library deliberately broken in a few dozen ways (e.g. dropping the unit-length skip in slowest_varying_axis(), making has_same_logical_range_as always true, ignoring batch axes in offset_in / is_contiguous(), dropping the embedding map in in-place copies or intersections, not rescaling batch-axis strides on the Hermitian side, relaxing each stride rule of real in-place layouts).

After rebasing onto #14063 (commits 1-6):

  • Each commit built on its own with g++ (project warning flags plus -Werror); data_set_test.* run with seeds 0-299.
  • rocfft-internal-test (commits 1-4) built with ROCm 7.0.2, then ctest, and data_set_test.* with seeds 0-499 and with --num_random_cases 5000. librocfft itself could not be built with ROCm 7.0.2 on current develop, independently of this PR (also fails without it), so the full build relies on CI.

Test Result

  • Before the rebase: no compiler warnings; ctest 20/20 passed with both ROCm versions; all seed runs pass. Every deliberate bug above makes at least one test fail, including those the merged tests missed; bugs are caught within 20-50 random cases in most cases, and with the default 200 cases per test in at least 99% of runs.
  • After the rebase: no compiler warnings; ctest 25/25 passed; all seed runs pass.

Submission Checklist

@therock-pr-bot

therock-pr-bot Bot commented Oct 28, 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

therock-pr-bot Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

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

@codecov

codecov Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 12 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
projects/rocfft/library/src/data_set.cpp 0.00% 11 Missing and 1 partial ⚠️

❌ Your project check has failed because the head coverage (46.60%) 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   #14585      +/-   ##
===========================================
- Coverage    77.58%   77.46%   -0.11%     
===========================================
  Files         2962     2903      -59     
  Lines       512659   490414   -22245     
  Branches     79368    74227    -5141     
===========================================
- Hits        397713   379899   -17814     
+ Misses       86736    85590    -1146     
+ Partials     28210    24925    -3285     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 51.04% <ø> (ø) Carriedforward from 945eb4a
TensileLite-Unit 84.35% <ø> (ø) Carriedforward from 945eb4a
hipBLAS 90.62% <ø> (ø) Carriedforward from 945eb4a
hipBLASLt 68.77% <ø> (ø) Carriedforward from 945eb4a
hipCUB 82.68% <ø> (+2.19%) ⬆️ Carriedforward from 945eb4a
hipDNN 87.26% <ø> (ø) Carriedforward from 945eb4a
hipFFT 42.47% <ø> (ø) Carriedforward from 945eb4a
hipRAND 76.12% <ø> (ø) Carriedforward from 945eb4a
hipSOLVER 69.67% <ø> (ø) Carriedforward from 945eb4a
hipSPARSE 87.03% <ø> (ø) Carriedforward from 945eb4a
rocBLAS 69.20% <ø> (ø) Carriedforward from 945eb4a
rocFFT 46.60% <0.00%> (+0.11%) ⬆️
rocRAND 57.32% <ø> (ø) Carriedforward from 945eb4a
rocSOLVER 76.74% <ø> (ø) Carriedforward from 945eb4a
rocSPARSE 83.54% <ø> (ø) Carriedforward from 945eb4a
rocThrust 93.15% <ø> (ø) Carriedforward from 945eb4a

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

Files with missing lines Coverage Δ
projects/rocfft/library/src/include/data_set.h 57.14% <ø> (ø)
projects/rocfft/library/src/data_set.cpp 34.72% <0.00%> (-0.47%) ⬇️

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

@regan-amd
regan-amd marked this pull request as ready for review October 29, 2026 15:26
@regan-amd
regan-amd requested a review from a team as a code owner October 29, 2026 15:26
@regan-amd
regan-amd requested a review from Abuudiii October 29, 2026 15:26

const auto counterpart = layout.get_other_inplace_layout_for(other_io, fft_type, odd);
ASSERT_EQ(counterpart.has_value(), follows_rules);
if(counterpart)

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.

Should you also be able to ASSERT_EQ(counterpart) at this point?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

counterpart has no value whenever the layout breaks the rules (roughly half of the random cases): get_other_inplace_layout_for is documented to return a value iff an in-place counterpart exists. So the ASSERT_EQ above checks that part of the contract, and the if then checks the derived layout only when there is one.

@@ -570,6 +570,13 @@ TEST_F(data_layout_test, inplace_real_round_trip)
// operator== ignores the embedding map, so compare it separately
EXPECT_TRUE(back->get_embedding_layout() == full) << back->str();

// a Hermitian innermost length of 1 only comes from a real one of 1

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.

Is L[0]==1 excluded here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, L[0] == 1 goes through the full round trip above. Any Hermitian innermost length $m &gt; 1$ may come from two real lengths, $2(m-1)$ (even) and $2(m-1)+1$ (odd), so the wrong-parity check expects the other one not to give back the original layout. For $m = 1$ though, only the odd real length of 1 makes sense (the even one would be 0), so get_other_inplace_layout_for now rejects it with std::invalid_argument, as documented in the last commit, and the test expects that throw instead.

@malcolmroberts

Copy link
Copy Markdown
Contributor

No concerns with this PR, but I had a couple of questions/clarifications.

@regan-amd
regan-amd force-pushed the users/regan-amd/rocfft-data-layout-test-gaps branch from 112a5db to 7ce1359 Compare November 3, 2026 17:34
regan-amd and others added 4 commits November 3, 2026 14:30
rocfft-internal-test now accepts --num_random_cases (default 200, must
be positive) next to --seed, and the randomized data_set tests use it
instead of a hard-coded constant. A failing case replays with the same
--seed and at least as many --num_random_cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Several data_set_t queries could be broken without failing a test,
because the tests never generated unit-length axes (e.g. a batch of 1),
or checked fixed layouts only:

- offset_in: drop the min_span parameter of random_full_range so its
  random layouts include unit-length axes, and check that layouts with
  the same total number of axes but a different length/batch split are
  rejected.
- continuous_chunk: draw spans (some of them 1) in random axis order
  with random padding, so that the slowest-varying axis is not always
  the last one; removing the unit-length skip in slowest_varying_axis()
  used to pass. Also check that a chunk running past the slowest-varying
  axis is rejected and that strides along unit-length axes are ignored.
- same_logical_range: new test, has_same_logical_range_as was not called
  by any test.
- contiguous_strides: randomize, deriving the expected contiguity from
  the construction; an is_contiguous() ignoring batch axes used to pass.
- intersection: check that different length/batch splits and different
  embeddings are rejected, and that a shared embedding is kept.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- inplace_complex_is_unchanged only checked a packed 1-D layout for a
  forward transform's output. Draw random layouts that may be partial
  along batch axes and embedded, with one transform direction and I/O
  side per case, and compare embedding maps separately since operator==
  ignores them.
- inplace_real_round_trip: multi-device plans also derive in-place
  layouts of embedded views that keep the embedding's innermost axis
  (see plan.cpp). Run the round trip on such views, and check that the
  Hermitian side of a view is the view of the Hermitian side of the
  whole: this catches strides of former length axes (now batch axes) not
  being rescaled, which the round trip alone cannot.
- inplace_real_refuses_impossible_layouts checked one rule at a time on
  a 1-D layout, for a forward transform's real side only. Rename it
  inplace_real_counterpart_rules and build random layouts by nesting
  their axes, with unit-length axes, odd strides and strides around the
  padded-row threshold, for either transform direction and either side,
  checking both acceptance and the derived layout. The layouts are never
  self-aliased, and neither are their counterparts when the per-axis
  stride rules hold, so the expected acceptance stays valid once the
  library detects self-aliasing; until then it restates the library's
  rules, which its comment documents as a known weakness.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
data_set_t::get_other_inplace_data_set_for returned a real layout with
an innermost length of 0 when asked for the real side of a Hermitian
innermost length of 1 with other_innermost_length_is_odd set to false. A
Hermitian length of 1 can only come from a real length of 1, so throw
std::invalid_argument instead, and document it. Callers in plan.cpp
compute the flag from actual lengths and are not affected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@regan-amd
regan-amd force-pushed the users/regan-amd/rocfft-data-layout-test-gaps branch from 7ce1359 to a79f268 Compare November 3, 2026 22:35
Follow-up to #14063, which renamed data_layout_t to data_set_t: several
comments and error messages in data_set.{h,cpp} still called data_set_t
objects layouts, e.g. get_other_inplace_data_set_for was documented to
return the "corresponding output (resp. input) layout".

Call them data sets, and keep "layout" where it refers to the in-buffer
arrangement of the data (e.g. "a contiguous data layout"), to the public
rocfft_plan_description_set_data_layout, or to the layout members of
descriptions and bricks that #14063 leaves for a separate rename. No
functional change beyond the wording of error messages.
Following #14063 and the previous commit, rename the data_set_test.cpp
variables and trace labels that still called data_set_t objects
layouts (layout, layout_1d, layout_2d, ...) and reword the matching
comments. "layout" is kept for client_data_layout_helpers.h and the test
comparing against it.
@regan-amd regan-amd changed the title test(rocfft): cover unit-length axes, embedded views and preconditions in data_layout tests test(rocfft): cover unit-length axes, embedded views and preconditions in data_set tests Nov 3, 2026
@evetsso
evetsso self-requested a review November 4, 2026 20:02

This branch has not been deployed

No deployments
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.

4 participants