Skip to content
Merged
Show file tree
Hide file tree
Changes from 101 commits
Commits
Show all changes
149 commits
Select commit Hold shift + click to select a range
3cb8e6b
Initial skeleton for RPP test suite revamp
zacharyvincze Jul 20, 2026
5ab2500
Setup references + tests for basic pointwise RPP operations
zacharyvincze Jul 21, 2026
4359e77
Add copy test + reference
zacharyvincze Jul 21, 2026
640c7d1
Add stream level synchronization to tests rather than device wide sync
zacharyvincze Jul 21, 2026
03baa6b
Add 8 element row padding to strides in RPP descriptor construction +…
zacharyvincze Jul 21, 2026
609da94
Gamma correction reference and test units
zacharyvincze Jul 21, 2026
d7528d5
Color twist, hue, lut, saturation, and helpers for RGB <-> HSV conver…
zacharyvincze Jul 21, 2026
31b319f
Add helpers for per pixel traversal and dtype normalization
zacharyvincze Jul 21, 2026
6eb700f
Add channel dropout tests
zacharyvincze Jul 21, 2026
f21abd2
Add crop tests
zacharyvincze Jul 21, 2026
587c47a
Implement statistical tests (min, max, sum, stddev, mean)
zacharyvincze Jul 22, 2026
2ee56c5
Add threshold test
zacharyvincze Jul 22, 2026
16d0cd4
Implement geometric helper, interpolation and warp affine tests
zacharyvincze Jul 22, 2026
18464ec
Add warp_perspective test and reference implementation
zacharyvincze Jul 22, 2026
d1f0c74
Temp fix for statistical operators on HIP due to stage 2 reduction is…
zacharyvincze Jul 23, 2026
9a5505e
Organize testing files
zacharyvincze Jul 23, 2026
5be4c33
Add README.md to test suite and ensure reduction tests convey mismatc…
zacharyvincze Jul 23, 2026
465a74e
Add resize test and reference
zacharyvincze Jul 23, 2026
eba86f9
Add channel_permute tests and reference
zacharyvincze Jul 23, 2026
f6a1a3c
copy_and_patch and remape tests and references
zacharyvincze Jul 23, 2026
dc838f2
Implement rain/snow tests and references
zacharyvincze Jul 23, 2026
2314748
Add dropout tests and references
zacharyvincze Jul 23, 2026
d4c8a60
Add dilate and erode tests and references
zacharyvincze Jul 23, 2026
4537151
Add filter operation tests and references
zacharyvincze Jul 24, 2026
03860e4
Add posterize test and references
zacharyvincze Jul 24, 2026
bdf84c9
Add phase test and reference
zacharyvincze Jul 24, 2026
b1b1c2e
Histogram equalize test and reference
zacharyvincze Jul 24, 2026
7761452
Add resize_crop_mirror test and reference
zacharyvincze Jul 24, 2026
6c98d1d
non_linear blend test and reference
zacharyvincze Jul 24, 2026
5b5759d
rppt_erase test and reference
zacharyvincze Jul 24, 2026
ba388ab
Generic tensor descriptor helpers and bitwise_tensor tests and refere…
zacharyvincze Jul 27, 2026
2edc86f
Normalize tests and reference
zacharyvincze Jul 27, 2026
335960a
Remove references to local tracking documents in comments
zacharyvincze Jul 27, 2026
1441252
Add gridmask, ricap tests and reference
zacharyvincze Jul 28, 2026
d47cec2
Golden ref cleanup
zacharyvincze Jul 28, 2026
4f7278f
General cleanup to references/helpers/tests
zacharyvincze Jul 28, 2026
41fd2b2
lens_correction, pixelate, resize_mirror_normalize references and tests
zacharyvincze Jul 28, 2026
22bcd0d
Add color conversion tests and references
zacharyvincze Jul 28, 2026
fb23b11
Emboss test and reference
zacharyvincze Jul 28, 2026
7d5d04a
Glob test source files instead of adding manually
zacharyvincze Jul 29, 2026
09ce632
Resolve warnings in test sources
zacharyvincze Jul 29, 2026
7d23e1b
Remove planar slice tests due to memory corruption issues
zacharyvincze Jul 29, 2026
2d77b1c
Add flip test and PLN1 test to color_cast
zacharyvincze Aug 4, 2026
5cb6050
Add crop_mirror_normalize test and refs
zacharyvincze Aug 4, 2026
6da7fda
Add JPEG compression distortion reference and tests
zacharyvincze Aug 5, 2026
5d93fab
Add voxel arithmetic tests and references
zacharyvincze Aug 5, 2026
5a04f18
Add flip_voxel test and ref
zacharyvincze Aug 6, 2026
8f937a5
jitter, noise shot, random_erase tests and refs
zacharyvincze Aug 7, 2026
c57db8c
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 7, 2026
4c57ec2
Rename shot_noise and reorganize testing categories
zacharyvincze Aug 7, 2026
94d112e
Changes to jitter and noise_shot tests
zacharyvincze Aug 10, 2026
b4f1020
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 10, 2026
ecaf088
Add fisheye test and ref
zacharyvincze Aug 10, 2026
763ed61
Add glitch test and ref
zacharyvincze Aug 10, 2026
a62d226
Add water test and ref
zacharyvincze Aug 10, 2026
d8bc988
Add vignette test and ref
zacharyvincze Aug 10, 2026
4e67eb2
Add spatter/color_jitter test and ref
zacharyvincze Aug 11, 2026
8b69b7f
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 11, 2026
43a956d
Add fog tests and negative tests
zacharyvincze Aug 12, 2026
8fde285
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 12, 2026
8fa6565
gaussian_noise tests and refs
zacharyvincze Aug 12, 2026
5984f70
Add (skipped for now) slice tests causing memory faults
zacharyvincze Aug 12, 2026
d13139e
Remove refs to .gitignored files
zacharyvincze Aug 13, 2026
b4025df
Add copyright lines
zacharyvincze Aug 17, 2026
4dd384d
dtype dispatch helper for boilerplate reduction
zacharyvincze Aug 18, 2026
1cbe239
Add skip list to test for genuine defects that must be fixed later
zacharyvincze Aug 18, 2026
53b2533
Update README.md
zacharyvincze Aug 19, 2026
cf25a81
Remove lengthy parameter printing
zacharyvincze Aug 19, 2026
7e5b5c9
Cleanup and improved reporter
zacharyvincze Aug 20, 2026
2de450a
Consolidate comparison types nto single header
zacharyvincze Aug 20, 2026
e0d514d
Reorganized framework folder
zacharyvincze Aug 20, 2026
4c6882a
Revert skip list
zacharyvincze Aug 20, 2026
ff45a6f
Standardize reference documentation
zacharyvincze Aug 21, 2026
218f249
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 24, 2026
9da23bd
Update test suite CMake
zacharyvincze Aug 25, 2026
4668f11
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 25, 2026
5d87177
Print string version of RppStatus upon failure
zacharyvincze Aug 27, 2026
7417652
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 27, 2026
003ee02
Move RppStatus print to separate helper file
zacharyvincze Aug 27, 2026
7b6130d
Comment cleanup
zacharyvincze Aug 27, 2026
e5e75d3
Implement independent input/output layout types
zacharyvincze Aug 28, 2026
ebe5b13
Cleanup
zacharyvincze Aug 28, 2026
c86fd47
Add layout switch cases to remaining supported operators
zacharyvincze Aug 28, 2026
b318713
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Aug 28, 2026
ef03e7a
Add option to revert back to standard GTest stdout
zacharyvincze Aug 31, 2026
78bce87
Add odd tensor sizes to brightness tests
zacharyvincze Aug 31, 2026
346ac3a
Create default presets for common edge cases
zacharyvincze Sep 1, 2026
af8bce4
Add more edge cases to Image_Color category
zacharyvincze Sep 1, 2026
160f8a4
Add more cases to Data_Exchange category
zacharyvincze Sep 1, 2026
605c799
Update bitwise tests
zacharyvincze Sep 1, 2026
e2ca94b
Remove 1x1 unit tests
zacharyvincze Sep 1, 2026
7c40fb5
Ensure test grid configuration is handled by the units themselves rat…
zacharyvincze Sep 2, 2026
75ce8bc
Expand testing grid for remaining operators
zacharyvincze Sep 2, 2026
a60442f
Update skip list
zacharyvincze Sep 2, 2026
10ba64e
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Sep 3, 2026
e94780e
Run pre-commit hook and format
zacharyvincze Sep 3, 2026
926f81f
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Sep 8, 2026
a518eb1
Remove root cause mentions from skip_list.hpp
zacharyvincze Sep 8, 2026
218572c
Switch to source defined PI constant rather than M_PI
zacharyvincze Sep 8, 2026
38335b1
Separate CTests based on operator type and add labels
zacharyvincze Sep 9, 2026
b46ed0f
Ensure warp references sample about the ROI origin rather than the im…
zacharyvincze Sep 9, 2026
6067db6
Merge branch 'develop' into users/zacharyvincze/rpp-test-suite-revamp
zacharyvincze Sep 10, 2026
952780a
Remove PLN1 for 3-channel only color_cast test
zacharyvincze Sep 10, 2026
defee7d
Use separate roi for reference model to ensure HIP version of geometr…
zacharyvincze Sep 10, 2026
40c4073
Ensure assertions happen outside of lambda bodies
zacharyvincze Sep 11, 2026
c2deef4
Address review comments/issues with some test setups
zacharyvincze Sep 11, 2026
ffeaf1d
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Sep 11, 2026
911cce8
Modify GTest fetching method so that it works on network isolated builds
zacharyvincze Sep 14, 2026
0eb06cb
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Sep 14, 2026
8de3126
Remove hardware specific numbers from README
zacharyvincze Sep 14, 2026
dc0cd4f
Add multiple border mode handling to sample() method
zacharyvincze Sep 15, 2026
0884bca
Remove fixed test cases from skip list
zacharyvincze Sep 16, 2026
498c772
Ensure I8 shifting occurs in sobel_filter reference model
zacharyvincze Sep 16, 2026
df13ef5
Change gridmask ref to rotate before translating in grid space, match…
zacharyvincze Sep 16, 2026
e678d0e
Honor dstRoi in crop_and_patch reference model
zacharyvincze Sep 21, 2026
bae531c
Mark resize roiWidth tie in skip list
zacharyvincze Sep 21, 2026
3096b16
Commit uncommited file
zacharyvincze Sep 21, 2026
c0b82ae
Match YUV -> RGB reference to actual kernel intent rather than incorr…
zacharyvincze Sep 21, 2026
fda6564
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Sep 21, 2026
5544baa
Add flaky test to skip list
zacharyvincze Sep 22, 2026
676ca39
Address review comments
zacharyvincze Sep 23, 2026
91a431d
Remove GPU support from CMake
zacharyvincze Sep 23, 2026
fd08f76
Re-add I8 to exposure and saturation
zacharyvincze Sep 23, 2026
ca2b1f1
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Sep 24, 2026
b56e0da
Simplify blend and exposure scalar methods in refs
zacharyvincze Oct 1, 2026
11b8950
Use strict U8 type for bitwise_binary and bitwise_not refs
zacharyvincze Oct 1, 2026
f7b6835
Fix pre-commit formatting issues
zacharyvincze Oct 1, 2026
1843b07
Check that destination ROIs to not write beyond image width in crop_a…
zacharyvincze Oct 1, 2026
45d5d14
Add additional kernel sizes for the emboss reference model to further…
zacharyvincze Oct 1, 2026
6836800
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Oct 1, 2026
da49aff
Simplify grid_dropout reference
zacharyvincze Oct 2, 2026
aa19abb
Merge struct template into single function in arithmetic_tensor ref
zacharyvincze Oct 2, 2026
2919df0
Simplify coarse_dropout ref
zacharyvincze Oct 2, 2026
5b0a1ba
Add per-channel stdDev in resize_mirror_normalize ref
zacharyvincze Oct 5, 2026
494dc3b
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Oct 5, 2026
ded7e9b
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Oct 6, 2026
4efb322
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Oct 7, 2026
f8d4680
Address PR comments
zacharyvincze Oct 8, 2026
a94ee3f
Merge remote-tracking branch 'origin/develop' into users/zacharyvincz…
zacharyvincze Oct 8, 2026
24dca5b
Merge branch 'develop' into users/zacharyvincze/rpp-test-suite-revamp
zacharyvincze Oct 13, 2026
7b6064c
Address padded tail behavior in slice_test.cpp
zacharyvincze Oct 13, 2026
e4e6d4e
Update reference model comment for yub_to_rgb_ref.hpp
zacharyvincze Oct 14, 2026
8f50a6d
Comment cleanup sweep
zacharyvincze Oct 14, 2026
b9d0515
Reduce comments in build system files for new test suite
zacharyvincze Oct 14, 2026
ae28ff9
Add DensePadded to slice test
zacharyvincze Oct 15, 2026
9fb60ed
Clarify documentation for reference models
zacharyvincze Oct 19, 2026
64f2cc5
Merge branch 'develop' into users/zacharyvincze/rpp-test-suite-revamp
zacharyvincze Oct 19, 2026
8b542a7
Address documentation gaps in histogram_equalize and normalize refere…
zacharyvincze Oct 19, 2026
43f92a1
Merge branch 'develop' into users/zacharyvincze/rpp-test-suite-revamp
LakshmiKumar23 Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions projects/rpp/utilities/test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build
.cache
.notes
87 changes: 87 additions & 0 deletions projects/rpp/utilities/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#[[
MIT License

Copyright (c) 2026 Advanced Micro Devices, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]

cmake_minimum_required(VERSION 3.14)

project(rpp-test CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# ROCm path (only used to locate the installed rpp package by default)
if(DEFINED ENV{ROCM_PATH})
set(ROCM_PATH $ENV{ROCM_PATH} CACHE PATH "ROCm installation path")
else()
set(ROCM_PATH /opt/rocm CACHE PATH "ROCm installation path")
endif()
list(APPEND CMAKE_PREFIX_PATH ${ROCM_PATH}/lib/cmake)

# Standalone build finds an installed rpp; in-tree build reuses the existing target.
if(NOT TARGET rpp)
find_package(rpp 3.0.0 REQUIRED)
set(RPP_TEST_LINK_LIB rpp::rpp)
else()
set(RPP_TEST_LINK_LIB rpp)
endif()

include(cmake/gtest.cmake)
include(cmake/grouped_tests.cmake)

enable_testing()
include(GoogleTest)
include(CTest)

file(GLOB_RECURSE RPP_TEST_SOURCES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/src/tests/*.cpp)

if(NOT RPP_TEST_SOURCES)
message(FATAL_ERROR "No test sources found under ${CMAKE_CURRENT_SOURCE_DIR}/src/tests")
endif()

add_executable(rpp_tests ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ${RPP_TEST_SOURCES})
target_include_directories(rpp_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)

# Warnings are errors for the suite's own sources.
target_compile_options(rpp_tests PRIVATE -Wall -Wextra -Werror)

# src/main.cpp provides main() (it installs the suite's own reporter), so gtest_main is not used.
target_link_libraries(rpp_tests PRIVATE ${RPP_TEST_LINK_LIB} GTest::gtest)

if(rpp_BACKEND_TYPE STREQUAL "HIP" OR BACKEND STREQUAL "HIP")
# GPU_SUPPORT exposes the HIP-only API symbols guarded behind it in the installed
# headers (e.g. rppt_erode/rppt_dilate); the legacy HIP suite defines it the same way.
target_compile_definitions(rpp_tests PRIVATE RPP_TEST_HAVE_HIP=1 GPU_SUPPORT=1)
Comment thread
zacharyvincze marked this conversation as resolved.
Resolved
endif()

Comment thread
zacharyvincze marked this conversation as resolved.
Resolved
# One CTest test per GTest suite (per operator) by default -- see cmake/grouped_tests.cmake for
# why. Per-case registration stays available: it isolates every case in its own process, so a
# segfault or GPU fault takes down one case rather than its whole operator suite, at the cost of
# ~25000 process starts.
option(RPP_TEST_CTEST_PER_CASE "Register one CTest test per GTest case (slow: one process each)" OFF)

if(RPP_TEST_CTEST_PER_CASE)
gtest_discover_tests(rpp_tests)
else()
rpp_discover_grouped_tests(rpp_tests)
endif()
101 changes: 101 additions & 0 deletions projects/rpp/utilities/test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# RPP Test Suite

A standalone [GoogleTest](https://github.com/google/googletest) correctness suite for RPP tensor operations. Each op is checked against an independent, host-computed reference model across data types, layouts, ROIs, and both backends (HOST + HIP). It builds standalone against an *installed* RPP, or in-tree against an RPP build.

## Requirements
- An RPP install discoverable under `ROCM_PATH` (not needed for an in-tree build).
- `ROCM_PATH` pointing at your ROCm install (defaults to `/opt/rocm` if unset).

GoogleTest is fetched automatically at configure time (pinned to a tag; see `cmake/gtest.cmake`). Configure with `-DRPP_TEST_USE_SYSTEM_GTEST=ON` to use an installed GoogleTest instead, for builds with no network access. HIP tests are compiled only when the RPP being built against has the HIP backend.

## Building
```shell
mkdir build && cd build
cmake ..
cmake --build . --parallel
```

Configured in-tree (as a subdirectory of an RPP build) the suite reuses that build's `rpp` target instead of finding an installed one; no other setup differs.

## Running
```shell
./rpp_tests # run every test
./rpp_tests --gtest_list_tests # list tests without running
./rpp_tests --help # full GTest options
ctest -j8 # run via CTest, one test per operator
```

CTest registers one test per GTest suite — that is, one per operator — discovered from the binary
after each build. A failure names the operator that failed, and `--output-on-failure` prints the
reporter's detail for it:

```shell
ctest -j8 --output-on-failure # print the failing operator's output
ctest -R Rotate # one operator (CTest test names are the GTest suite names)
ctest -L Image_Geometric # one category
ctest -L voxel # one domain: image, misc, voxel, core
ctest -N # list the registered tests
ctest --no-label-summary # drop the per-label timing block CTest prints after a run
GTEST_COLOR=yes ctest ... # keep colour; CTest captures output, so it is off by default
```

> [!NOTE]
> Registering one CTest test per *case* instead is available via `cmake -DRPP_TEST_CTEST_PER_CASE=ON ..`.
> It isolates each of the ~25000 cases in its own process, so a segfault or GPU fault takes down one
> case rather than its whole operator suite. The isolation costs a process start plus RPP/HIP handle
> setup per case: roughly 0.33s each, turning a ~17s run into hours. Use it when chasing a crash,
> not routinely.
Comment thread
zacharyvincze marked this conversation as resolved.
Resolved

## Output

Console output comes from the suite's own reporter, which prints one line per test suite plus the
detail of every failure. It replaces GTest's console printer only: `--gtest_list_tests` and
`--gtest_output=xml:<path>` / `json:<path>` are unaffected, so IDE and CI integrations that read
those work as they would against any GTest binary.

```shell
RPP_TEST_PLAIN_OUTPUT=1 ./rpp_tests # stock GTest console output instead
```

Set `RPP_TEST_PLAIN_OUTPUT=1` for tooling that scrapes the `[ RUN ]` / `[ OK ]` stream.

## Test names & filtering

Every case has a structured, greppable name:

```
{Domain}_{Category}/{Op}Test.{Intent}/{Backend}_{DType}_{Layout}_{Roi}_{Size}
```

e.g. `Image_Color/BrightnessTest.Correctness/HIP_U8toU8_PKD3_FullRoi_2x36x48`.

Select subsets with `--gtest_filter` (wildcard `*`, `:`-separated patterns):

| Goal | Filter |
|------|--------|
| One operation | `--gtest_filter='*BrightnessTest*'` |
| One category | `--gtest_filter='Image_Color/*'` |
| HIP cases only | `--gtest_filter='*/HIP_*'` |
| All F32 PKD3, any op | `--gtest_filter='*F32*PKD3*'` |

## Known-defect skip list

Cases that fail against a documented kernel defect (or a non-reproducible result) are skipped rather
than left red, so a normal run stays green. The list lives in `src/framework/skip_list.hpp` as
GTest-filter-glob patterns; fixing a kernel means deleting the matching entry in the same change.
Set `RPP_TEST_NO_SKIP_LIST=1` to run the listed cases anyway and check whether any have been fixed.

## Layout
```
src/
main.cpp entry point; installs the suite's console reporter
framework/ shared harness. config grid, backend memory, comparators
reference/ independent golden models for comparison
tests/ the tests themselves
core/ core RPP tests unrelated to op correctness
image/ image ops, grouped by category (color, geometric, ...)
misc/ misc ops, grouped by category
voxel/ voxel ops, grouped by category
```

Adding an op = a `reference/<op>_ref.hpp` golden model plus a short `TEST_P` under `tests/`.
77 changes: 77 additions & 0 deletions projects/rpp/utilities/test/cmake/grouped_tests.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#[[
MIT License

Copyright (c) 2026 Advanced Micro Devices, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]

# Registers one CTest test per GTest suite (i.e. per RPP operator) instead of one per case.
#
# gtest_discover_tests() registers every case separately, which for this suite is ~25000 CTest
# tests, each paying a fresh process start plus RPP/HIP handle setup. That overhead dominates:
# ~0.33s per case of spawn cost against a whole 8000-case category that runs in 18s in one
# process. Grouping by suite keeps a named CTest test per operator -- so a failure still points at
# an operator without reading any logs -- while cutting the process count by ~250x.
#
# Discovery mirrors gtest_discover_tests' POST_BUILD mode: the built binary is asked for its suite
# list and a CTest include file is generated from it, so the registration cannot drift as
# operators are added or renamed.

set(RPP_GROUPED_TESTS_IMPL "${CMAKE_CURRENT_LIST_DIR}/grouped_tests_impl.cmake"
CACHE INTERNAL "Script that turns --gtest_list_tests output into add_test() calls")

# rpp_discover_grouped_tests(<target> [TIMEOUT <seconds>] [WORKING_DIRECTORY <dir>])
function(rpp_discover_grouped_tests TARGET)
cmake_parse_arguments(_arg "" "TIMEOUT;WORKING_DIRECTORY" "" ${ARGN})

if(NOT _arg_TIMEOUT)
# Suites run 0.5-3s each here; the margin is for slow or contended machines.
set(_arg_TIMEOUT 900)
endif()
if(NOT _arg_WORKING_DIRECTORY)
set(_arg_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()

set(_testsFile "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_grouped_tests.cmake")
set(_includeFile "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_grouped_include.cmake")

add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${_testsFile}"
COMMAND ${CMAKE_COMMAND}
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_OUTPUT_FILE=${_testsFile}"
-D "TEST_WORKING_DIRECTORY=${_arg_WORKING_DIRECTORY}"
-D "TEST_TIMEOUT=${_arg_TIMEOUT}"
-P "${RPP_GROUPED_TESTS_IMPL}"
VERBATIM
COMMENT "Discovering GTest suites in ${TARGET}")

# Indirection so that configuring before the first build still yields a CTest file. The
# placeholder test fails loudly rather than reporting an empty, all-green run.
file(WRITE "${_includeFile}"
"if(EXISTS \"${_testsFile}\")\n"
" include(\"${_testsFile}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT ${TARGET}_NOT_BUILT)\n"
"endif()\n")

set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES "${_includeFile}")
endfunction()
123 changes: 123 additions & 0 deletions projects/rpp/utilities/test/cmake/grouped_tests_impl.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#[[
MIT License

Copyright (c) 2026 Advanced Micro Devices, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]

# Script-mode half of rpp_discover_grouped_tests(). Run as a POST_BUILD step with
# TEST_EXECUTABLE / TEST_OUTPUT_FILE / TEST_WORKING_DIRECTORY / TEST_TIMEOUT defined.

cmake_minimum_required(VERSION 3.14)

foreach(_required TEST_EXECUTABLE TEST_OUTPUT_FILE TEST_WORKING_DIRECTORY TEST_TIMEOUT)
if(NOT DEFINED ${_required})
message(FATAL_ERROR "grouped_tests_impl.cmake: ${_required} is not set")
endif()
endforeach()

execute_process(
COMMAND "${TEST_EXECUTABLE}" --gtest_list_tests
WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}"
OUTPUT_VARIABLE _listing
ERROR_VARIABLE _listingErrors
RESULT_VARIABLE _listingResult)

if(NOT _listingResult EQUAL 0)
message(FATAL_ERROR
"Failed to list GTest suites: '${TEST_EXECUTABLE} --gtest_list_tests' exited with "
"${_listingResult}\n${_listingErrors}")
endif()

# Split into lines. Semicolons would otherwise be read as list separators; GTest names contain
# none, but the escape keeps a stray one in a parameter comment from corrupting the parse.
string(REPLACE ";" "\\;" _listing "${_listing}")
string(REPLACE "\n" ";" _lines "${_listing}")

# --gtest_list_tests prints a suite per unindented line ending in '.', with its cases indented
# beneath it:
#
# Image_Geometric/RotateTest.
# Correctness/HOST_U8toU8_PKD3_FullRoi_2x36x48_a0_NN # GetParam() =
#
# Only the suite lines are of interest -- one CTest test is registered per suite.
set(_suites "")
foreach(_line IN LISTS _lines)
if(_line MATCHES "^[ \t]")
continue() # an individual case
endif()
string(REGEX REPLACE "[ \t]*#.*$" "" _line "${_line}") # '# TypeParam = ...' annotation
string(STRIP "${_line}" _line)
if(NOT _line MATCHES "\\.$")
continue() # blank line, or a banner GTest printed before the listing
endif()
string(REGEX REPLACE "\\.$" "" _line "${_line}")
list(APPEND _suites "${_line}")
endforeach()

if(NOT _suites)
message(FATAL_ERROR
"No GTest suites found in the output of '${TEST_EXECUTABLE} --gtest_list_tests'. "
"Registering nothing would make `ctest` pass without running anything.")
endif()

set(_content "# Generated by rpp_discover_grouped_tests(). Do not edit.\n")
foreach(_suite IN LISTS _suites)
# Labels give back the category-level selection that per-suite registration would otherwise
# lose: `ctest -L Image_Geometric` or `ctest -L voxel`. Suite names follow
# {Domain}_{Category}/{Op}Test; the core suites carry no prefix. Setting them makes CTest
# print its "Label Time Summary" block after a run -- `ctest --no-label-summary` drops it.
if(_suite MATCHES "^(([A-Za-z0-9]+)_[A-Za-z0-9]+)/")
# Read both captures before any further regex call: every string(REGEX ...) resets
# CMAKE_MATCH_<n>.
set(_category "${CMAKE_MATCH_1}")
string(TOLOWER "${CMAKE_MATCH_2}" _domain)
set(_labels "${_category};${_domain}")
else()
set(_labels "core")
endif()

# SKIP_REGULAR_EXPRESSION deliberately does NOT match GTest's bare '[ SKIPPED ]' token the
# way gtest_discover_tests' per-case registration does. With a whole suite in one process, a
# single skip-list entry would then mark the entire CTest test as skipped and hide real
# failures alongside it. The reporter prints this phrase only when nothing failed and nothing
# ran, so it can never mask a failure.
#
# The legacy add_test(<name> <command> [args...]) form is used because this file is read by
# CTest itself, whose add_test() does not implement the NAME/COMMAND keyword signature.
string(APPEND _content
"add_test([==[${_suite}]==]\n"
" [==[${TEST_EXECUTABLE}]==] [==[--gtest_filter=${_suite}.*]==])\n"
"set_tests_properties([==[${_suite}]==] PROPERTIES\n"
" WORKING_DIRECTORY [==[${TEST_WORKING_DIRECTORY}]==]\n"
" TIMEOUT ${TEST_TIMEOUT}\n"
" LABELS [==[${_labels}]==]\n"
" SKIP_REGULAR_EXPRESSION [==[no cases ran \\(]==])\n")
endforeach()

# Write through a temporary so an unchanged suite list leaves the timestamp alone; CTest re-reads
# TEST_INCLUDE_FILES on every run, and touching it on every build would churn needlessly.
file(WRITE "${TEST_OUTPUT_FILE}.tmp" "${_content}")
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${TEST_OUTPUT_FILE}.tmp" "${TEST_OUTPUT_FILE}")
file(REMOVE "${TEST_OUTPUT_FILE}.tmp")

list(LENGTH _suites _suiteCount)
message(STATUS "Registered ${_suiteCount} CTest tests, one per GTest suite")
Loading
Loading