############################################################################### # # MIT License # # Copyright (C) 2023-2026 Advanced Micro Devices, Inc. All rights reserved. # # 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. # ############################################################################### include(CMakeDependentOption) # Find / configure LLVM add_subdirectory(llvm) cmake_dependent_option(HIPTENSOR_USE_SYSTEM_GOOGLETEST "Use system Google Test library instead of downloading and building it" OFF "HIPTENSOR_BUILD_TESTS" OFF) if(HIPTENSOR_USE_SYSTEM_GOOGLETEST) find_package(GTest REQUIRED) else() include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.17.0 ) FetchContent_GetProperties(googletest) if(NOT googletest_POPULATED) # Fetch the content using default details FetchContent_Populate(googletest) # Save the shared libs setting, then force to static libs set(BUILD_SHARED_LIBS_OLD ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Build SHARED libraries" FORCE) # Turn off gtest installation set(INSTALL_GTEST OFF) # On MSVC-style toolchains gtest defaults to the static CRT (/MT), but the # rest of hipTensor compiles against the dynamic CRT (/MD). Force gtest to # use the dynamic CRT so lld-link does not reject a RuntimeLibrary mismatch. if(WIN32) set(gtest_force_shared_crt ON CACHE BOOL "Use shared (DLL) run-time lib for gtest" FORCE) endif() # Add gtest targets as static libs add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) # Restore shared libs setting set(BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS_OLD} CACHE INTERNAL "Build SHARED libraries" FORCE) endif() endif() get_target_property(composable_kernel_INCLUDES composable_kernel::device_other_operations INTERFACE_INCLUDE_DIRECTORIES) # Setup a test manifest set(INSTALL_TEST_FILE "${CMAKE_CURRENT_BINARY_DIR}/install_CTestTestfile.cmake") file(WRITE "${INSTALL_TEST_FILE}" [=[ # This is a test file generated by hipTensor for install time. # It differs slightly from the default testfile, and you may encounter issues because of that. ]=] ) set(INSTALL_SMOKE_TEST_FILE "${CMAKE_CURRENT_BINARY_DIR}/install_smoke_CTestTestfile.cmake") file(WRITE "${INSTALL_SMOKE_TEST_FILE}" [=[ # This is a test file generated by hipTensor for install time. # It differs slightly from the default testfile, and you may encounter issues because of that. ]=] ) set(INSTALL_REGRESSION_TEST_FILE "${CMAKE_CURRENT_BINARY_DIR}/install_regression_CTestTestfile.cmake") file(WRITE "${INSTALL_REGRESSION_TEST_FILE}" [=[ # This is a test file generated by hipTensor for install time. # It differs slightly from the default testfile, and you may encounter issues because of that. ]=] ) # YAML-driven CTest test categorisation for the *installed* tree only. # The shared helper apply_ctest_category_labels(yaml, install_test_file) # scans the install-tree CTestTestfile.cmake fragments we hand-roll below # for `add_test()` lines and appends explicit set_tests_properties() lines # so `ctest -L ` works against the install tree. Build-tree tests # are intentionally not labelled here. set(_HIPTENSOR_TEST_CATEGORIES_YAML "${PROJECT_SOURCE_DIR}/test_categories.yaml") set(_HIPTENSOR_SHARED_CTEST "${ROCM_LIBRARIES_ROOT}/shared/ctest/TestCategories.cmake") if(EXISTS "${_HIPTENSOR_SHARED_CTEST}" AND EXISTS "${_HIPTENSOR_TEST_CATEGORIES_YAML}") include("${_HIPTENSOR_SHARED_CTEST}") message(STATUS "hipTensor: YAML-based CTest categorization enabled (install tree only)") else() if(NOT EXISTS "${_HIPTENSOR_SHARED_CTEST}") message(STATUS "hipTensor: shared/ctest not found at ${_HIPTENSOR_SHARED_CTEST}; skipping CTest categories") endif() if(NOT EXISTS "${_HIPTENSOR_TEST_CATEGORIES_YAML}") message(STATUS "hipTensor: ${_HIPTENSOR_TEST_CATEGORIES_YAML} not found; skipping CTest categories") endif() endif() # Target that will trigger build of all tests add_custom_target(hiptensor_tests) # On Windows, DLL search order is: application dir -> System32 -> PATH. # A system-installed ROCm places amdhip64_7.dll and amd_comgr_3.dll in # System32, which always wins over PATH. If the test binary is compiled with # a newer toolchain but an older runtime is loaded from System32, kernel launches # may crash (SEH 0xC0000005) if the code-object format is incompatible. if(WIN32 AND CREATE_TEST_APP_LOCAL_DEPLOY) # hip_DIR is set by find_package(HIP) to /lib/cmake/hip. # Walk up three directory levels to reach , then append /bin. get_filename_component(_hip_cmake_dir "${hip_DIR}" DIRECTORY) # .../lib/cmake get_filename_component(_hip_lib_dir "${_hip_cmake_dir}" DIRECTORY) # .../lib get_filename_component(_hip_root "${_hip_lib_dir}" DIRECTORY) # set(_hip_bin_dir "${_hip_root}/bin") message(STATUS "HIP runtime DLL source: ${_hip_bin_dir}") message(STATUS "HIP runtime DLL destination: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") if(EXISTS "${_hip_bin_dir}") file(MAKE_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") file(GLOB _hip_dlls "${_hip_bin_dir}/amd_comgr*.dll" # code-object manager "${_hip_bin_dir}/amdhip64*.dll" # HIP runtime "${_hip_bin_dir}/amdhiprtc*.dll" # HIP RTC "${_hip_bin_dir}/rocm_kpack*.dll" # kernel packaging ) if(_hip_dlls) foreach(_dll ${_hip_dlls}) file(COPY "${_dll}" DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") endforeach() list(LENGTH _hip_dlls _hip_dll_count) message(STATUS "Staged ${_hip_dll_count} HIP runtime DLL(s) into ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}") else() message(WARNING "No DLLs found in ${_hip_bin_dir} - tests may load wrong HIP runtime from System32") endif() else() message(WARNING "HIP DLL source directory not found: ${_hip_bin_dir} - " "tests may load wrong HIP runtime from System32") endif() endif() set(HIPTENSOR_COMMON_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/common.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hip_resource.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hiptensor_gtest_main.cpp) # Create test executables and deploy function(add_hiptensor_test BINARY_NAME YAML_CONFIG_FILE TEST_SOURCES) # Make sure that all sources are appended to the list. list(APPEND TEST_SOURCES ${ARGN}) message(STATUS "adding hiptensor test: ${BINARY_NAME}") message(STATUS "test config file: ${YAML_CONFIG_FILE}") # Read in the YAML config file that we wish to bundle file(READ ${YAML_CONFIG_FILE} hiptensor_test_YAML_STRING) # Build a file header that includes the YAML config string # Must define in cmake: # - hiptensor_test_NAME # - hiptensor_test_YAML_STRING # - hiptensor_test_YAML_INCLUDE_FILE get_filename_component(hiptensor_test_YAML_DIR "${YAML_CONFIG_FILE}" PATH) get_filename_component(hiptensor_test_NAME "${YAML_CONFIG_FILE}" NAME_WE) set(hiptensor_test_YAML_INCLUDE_FILE "${hiptensor_test_NAME}.hpp") configure_file("${PROJECT_SOURCE_DIR}/test/hiptensor-test-yaml.hpp.in" "${hiptensor_test_YAML_DIR}/${hiptensor_test_YAML_INCLUDE_FILE}") # message(STATUS "test config dir: ${hiptensor_test_YAML_DIR}") # message(STATUS "test name: ${hiptensor_test_NAME}") # message(STATUS "test yaml config: ${hiptensor_test_YAML_STRING}") # message(STATUS "test config include: ${hiptensor_test_YAML_INCLUDE_FILE}") add_executable(${BINARY_NAME} ${TEST_SOURCES}) target_compile_options(${BINARY_NAME} PRIVATE ${CLANG_DRIVER_MODE}) target_link_options(${BINARY_NAME} PRIVATE ${CLANG_DRIVER_MODE}) # Test must propagate the build interface includes to make sure # hiptensor includes are captured at runtime. if(WIN32) target_link_libraries(${BINARY_NAME} PRIVATE hiptensor::hiptensor hiptensor_llvm GTest::gtest "-L${HIPTENSOR_CLANG_ROOT}/lib") else() target_link_libraries(${BINARY_NAME} PRIVATE hiptensor::hiptensor hiptensor_llvm GTest::gtest "-L${HIPTENSOR_CLANG_ROOT}/lib" "-Wl,-rpath=$ORIGIN/../${CMAKE_INSTALL_LIBDIR}" "-fno-rtlib-add-rpath") endif() target_include_directories(${BINARY_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${composable_kernel_INCLUDES} ${PROJECT_SOURCE_DIR}/library/include ${PROJECT_SOURCE_DIR}/library/src/include ${PROJECT_SOURCE_DIR}/library/src ${PROJECT_SOURCE_DIR}/test ${PROJECT_BINARY_DIR}/include/hiptensor ${PROJECT_BINARY_DIR}/include ${hiptensor_test_YAML_DIR}) # -Wno-ignored-attributes to avoid warning: __declspec attribute 'dllimport' is not supported [-Wignored-attributes] which is used by msvc compiler if(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") target_compile_options(${BINARY_NAME} PRIVATE -Wno-ignored-attributes) endif() # C++ code handles the following symbols defined: # - HIPTENSOR_TEST_YAML_INCLUDE # When defined, the test code will attempt to load bundled YAML string. target_compile_definitions(${BINARY_NAME} PRIVATE -D HIPTENSOR_TEST_YAML_INCLUDE=\"${hiptensor_test_YAML_INCLUDE_FILE}\") # Build this test under custom target add_dependencies(hiptensor_tests ${BINARY_NAME}) # Register with ctest add_test(NAME ${BINARY_NAME} COMMAND ${BINARY_NAME}) set_property(TEST ${BINARY_NAME} PROPERTY SKIP_REGULAR_EXPRESSION "HIPTENSOR_STATUS_ARCH_MISMATCH" "unsupported host device") # Set working directory to bin/ for proper DLL/resource loading on Windows set_property(TEST ${BINARY_NAME} PROPERTY WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) # On Windows, ensure the ROCm/HIP DLLs (amdhip64_7.dll, etc.) are discoverable by ctest. # ctest may not inherit the user's PATH that includes the ROCm bin directory, causing # HIP runtime DLL load failures (SEH 0xC0000005) on the first HIP call in a test fixture. if(WIN32) set_property(TEST ${BINARY_NAME} PROPERTY ENVIRONMENT "PATH=${CMAKE_INSTALL_PREFIX}/bin$${CMAKE_RUNTIME_OUTPUT_DIRECTORY}$$ENV{PATH}") endif() # Install with rocm pkg rocm_install_targets( TARGETS ${BINARY_NAME} COMPONENT tests ) # Add to testing manifest get_target_property(EXE_NAME ${BINARY_NAME} RUNTIME_OUTPUT_NAME) if(EXE_NAME STREQUAL "EXE_NAME-NOTFOUND") get_target_property(EXE_NAME ${BINARY_NAME} OUTPUT_NAME) if(EXE_NAME STREQUAL "EXE_NAME-NOTFOUND") set(EXE_NAME "${BINARY_NAME}") endif() endif() file(APPEND "${INSTALL_TEST_FILE}" "add_test(${BINARY_NAME} \"../${BINARY_NAME}\")\n") file(APPEND "${INSTALL_TEST_FILE}" "set_tests_properties(${BINARY_NAME} PROPERTIES SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") file(APPEND "${INSTALL_SMOKE_TEST_FILE}" "add_test(\"${BINARY_NAME} smoke\" \"../../${BINARY_NAME}\")\n") file(APPEND "${INSTALL_SMOKE_TEST_FILE}" "set_tests_properties(\"${BINARY_NAME} smoke\" PROPERTIES SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") file(APPEND "${INSTALL_REGRESSION_TEST_FILE}" "add_test(\"${BINARY_NAME} regression\" \"../../${BINARY_NAME}\")\n") file(APPEND "${INSTALL_REGRESSION_TEST_FILE}" "set_tests_properties(\"${BINARY_NAME} regression\" PROPERTIES SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") endfunction() # Create unit test executables and deploy # Differs from hiptensor_test in that src include directory is linked function(add_hiptensor_unit_test) set(BINARY_NAME ${ARGV0}) message(STATUS "adding hiptensor unit test: ${BINARY_NAME}") list(REMOVE_AT ARGV 0) add_executable(${BINARY_NAME} ${ARGV}) target_compile_options(${BINARY_NAME} PRIVATE ${CLANG_DRIVER_MODE}) target_link_options(${BINARY_NAME} PRIVATE ${CLANG_DRIVER_MODE}) # Test must propagate the build interface includes to make sure # hiptensor includes are captured at runtime. if(WIN32) target_link_libraries(${BINARY_NAME} PRIVATE hiptensor::hiptensor hiptensor_llvm GTest::gtest "-L${HIPTENSOR_CLANG_ROOT}/lib") else() target_link_libraries(${BINARY_NAME} PRIVATE hiptensor::hiptensor hiptensor_llvm GTest::gtest "-L${HIPTENSOR_CLANG_ROOT}/lib" "-Wl,-rpath=$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") endif() target_include_directories(${BINARY_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${composable_kernel_INCLUDES} ${PROJECT_SOURCE_DIR}/library/include ${PROJECT_SOURCE_DIR}/library/src/include ${PROJECT_SOURCE_DIR}/library/src ${PROJECT_SOURCE_DIR}/test ${PROJECT_BINARY_DIR}/include/hiptensor ${PROJECT_BINARY_DIR}/include) # -Wno-ignored-attributes to avoid warning: __declspec attribute 'dllimport' is not supported [-Wignored-attributes] which is used by msvc compiler if(WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") target_compile_options(${BINARY_NAME} PRIVATE -Wno-ignored-attributes) endif() # Build this test under custom target add_dependencies(hiptensor_tests ${BINARY_NAME}) # Register with ctest add_test(NAME ${BINARY_NAME} COMMAND ${BINARY_NAME}) set_property(TEST ${BINARY_NAME} PROPERTY SKIP_REGULAR_EXPRESSION "HIPTENSOR_STATUS_ARCH_MISMATCH" "unsupported host device") # Set working directory to bin/ for proper DLL/resource loading on Windows set_property(TEST ${BINARY_NAME} PROPERTY WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) # On Windows, ensure the ROCm/HIP DLLs (amdhip64_7.dll, etc.) are discoverable by ctest. # ctest may not inherit the user's PATH that includes the ROCm bin directory, causing # HIP runtime DLL load failures (SEH 0xC0000005) on the first HIP call in a test fixture. if(WIN32) set_property(TEST ${BINARY_NAME} PROPERTY ENVIRONMENT "PATH=${CMAKE_INSTALL_PREFIX}/bin$${CMAKE_RUNTIME_OUTPUT_DIRECTORY}$$ENV{PATH}") endif() # Install with rocm pkg rocm_install_targets( TARGETS ${BINARY_NAME} COMPONENT tests ) # Add to testing manifest get_target_property(EXE_NAME ${BINARY_NAME} RUNTIME_OUTPUT_NAME) if(EXE_NAME STREQUAL "EXE_NAME-NOTFOUND") get_target_property(EXE_NAME ${BINARY_NAME} OUTPUT_NAME) if(EXE_NAME STREQUAL "EXE_NAME-NOTFOUND") set(EXE_NAME "${BINARY_NAME}") endif() endif() file(APPEND "${INSTALL_TEST_FILE}" "add_test(${BINARY_NAME} \"../${BINARY_NAME}\")\n") file(APPEND "${INSTALL_TEST_FILE}" "set_tests_properties(${BINARY_NAME} PROPERTIES SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") file(APPEND "${INSTALL_SMOKE_TEST_FILE}" "add_test(\"${BINARY_NAME} smoke\" \"../../${BINARY_NAME}\")\n") file(APPEND "${INSTALL_SMOKE_TEST_FILE}" "set_tests_properties(\"${BINARY_NAME} smoke\" PROPERTIES SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") file(APPEND "${INSTALL_REGRESSION_TEST_FILE}" "add_test(\"${BINARY_NAME} regression\" \"../../${BINARY_NAME}\")\n") file(APPEND "${INSTALL_REGRESSION_TEST_FILE}" "set_tests_properties(\"${BINARY_NAME} regression\" PROPERTIES SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") endfunction() add_subdirectory(00_unit) add_subdirectory(01_contraction) add_subdirectory(02_elementwise) add_subdirectory(03_reduction) add_subdirectory(python) # Test entries for the install-tree category filters. # # Two building-block lists keep the three filters distinct in intent: # _HIPTENSOR_HOST_TESTS - host-only (non-device) tests. They take no config and # no run-count flags. # _HIPTENSOR_DEVICE_TESTS - device tests. Each runs with --hot_runs 1 --cold_runs 0 # and, where applicable, a custom config via -y. # # From these, families of install-tree entries are emitted: # filter test name suffix members config dir # quick " quick" host + device validation/quick # standard " standard" host + device validation/standard # comprehensive " comprehensive" host + device validation/comprehensive # full " full" host + device validation/full # ffm-quick " ffm-quick" device only emulation/quick # ffm-full " ffm-full" device only emulation/full # bench " bench" device (bench) bench # where "config dir" is the bin/hiptensor/configs// subtree the -y path # points at. Host tests are emitted once under quick; the shared parser's tier # nesting (quick->standard->comprehensive->full) carries them up, so they run # under every tier without duplicate entries. Labels are attached by the shared # category parser from test_categories.yaml. set(_HIPTENSOR_HOST_TESTS contraction_mode_test elementwise_cpu_test elementwise_op_test hiptensor_options_test logger_test reduction_cpu_impl_test util_test yaml_test ) # Device tests encoded as "binary|config-or-NONE". The config path is # relative to a per-category config root (bin/hiptensor/configs//), # with supplied per family below. NONE means no -y (the binary # carries its own config) but the run-count flags are still applied. set(_HIPTENSOR_DEVICE_TESTS "bilinear_contraction_test_m1n1k1|01_contraction/bilinear_test_params_rank1.yaml" "bilinear_contraction_test_m2n2k2|01_contraction/bilinear_test_params_rank2.yaml" "bilinear_contraction_test_m3n3k3|01_contraction/bilinear_test_params_rank3.yaml" "bilinear_contraction_test_m4n4k4|01_contraction/bilinear_test_params_rank4.yaml" "bilinear_contraction_test_m5n5k5|01_contraction/bilinear_test_params_rank5.yaml" "bilinear_contraction_test_m6n6k6|01_contraction/bilinear_test_params_rank6.yaml" "complex_bilinear_contraction_test_m1n1k1|01_contraction/complex_bilinear_test_params_rank1.yaml" "complex_bilinear_contraction_test_m2n2k2|01_contraction/complex_bilinear_test_params_rank2.yaml" "complex_bilinear_contraction_test_m3n3k3|01_contraction/complex_bilinear_test_params_rank3.yaml" "complex_bilinear_contraction_test_m4n4k4|01_contraction/complex_bilinear_test_params_rank4.yaml" "complex_bilinear_contraction_test_m5n5k5|01_contraction/complex_bilinear_test_params_rank5.yaml" "complex_bilinear_contraction_test_m6n6k6|01_contraction/complex_bilinear_test_params_rank6.yaml" "scale_contraction_test_m1n1k1|01_contraction/scale_test_params_rank1.yaml" "scale_contraction_test_m2n2k2|01_contraction/scale_test_params_rank2.yaml" "scale_contraction_test_m3n3k3|01_contraction/scale_test_params_rank3.yaml" "scale_contraction_test_m4n4k4|01_contraction/scale_test_params_rank4.yaml" "scale_contraction_test_m5n5k5|01_contraction/scale_test_params_rank5.yaml" "scale_contraction_test_m6n6k6|01_contraction/scale_test_params_rank6.yaml" "complex_scale_contraction_test_m1n1k1|01_contraction/complex_scale_test_params_rank1.yaml" "complex_scale_contraction_test_m2n2k2|01_contraction/complex_scale_test_params_rank2.yaml" "complex_scale_contraction_test_m3n3k3|01_contraction/complex_scale_test_params_rank3.yaml" "complex_scale_contraction_test_m4n4k4|01_contraction/complex_scale_test_params_rank4.yaml" "complex_scale_contraction_test_m5n5k5|01_contraction/complex_scale_test_params_rank5.yaml" "complex_scale_contraction_test_m6n6k6|01_contraction/complex_scale_test_params_rank6.yaml" "trinary_bilinear_contraction_test|NONE" "trinary_scale_contraction_test|NONE" "bilinear_contraction_with_unary_ops_test|NONE" "scale_contraction_with_unary_ops_test|NONE" "rank2_elementwise_permute_test|02_elementwise/permutation/rank2_test_params.yaml" "rank3_elementwise_permute_test|02_elementwise/permutation/rank3_test_params.yaml" "rank4_elementwise_permute_test|02_elementwise/permutation/rank4_test_params.yaml" "rank5_elementwise_permute_test|02_elementwise/permutation/rank5_test_params.yaml" "rank6_elementwise_permute_test|02_elementwise/permutation/rank6_test_params.yaml" "rank2_elementwise_binary_op_test|02_elementwise/binary_op/rank2_binary_op_test_params.yaml" "rank3_elementwise_binary_op_test|02_elementwise/binary_op/rank3_binary_op_test_params.yaml" "rank4_elementwise_binary_op_test|02_elementwise/binary_op/rank4_binary_op_test_params.yaml" "rank5_elementwise_binary_op_test|02_elementwise/binary_op/rank5_binary_op_test_params.yaml" "rank6_elementwise_binary_op_test|02_elementwise/binary_op/rank6_binary_op_test_params.yaml" "rank2_elementwise_trinary_op_test|02_elementwise/trinary_op/rank2_trinary_op_test_params.yaml" "rank3_elementwise_trinary_op_test|02_elementwise/trinary_op/rank3_trinary_op_test_params.yaml" "rank4_elementwise_trinary_op_test|02_elementwise/trinary_op/rank4_trinary_op_test_params.yaml" "rank5_elementwise_trinary_op_test|02_elementwise/trinary_op/rank5_trinary_op_test_params.yaml" "rank6_elementwise_trinary_op_test|02_elementwise/trinary_op/rank6_trinary_op_test_params.yaml" "rank1_reduction_test|03_reduction/rank1_test_params.yaml" "rank2_reduction_test|03_reduction/rank2_test_params.yaml" "rank3_reduction_test|03_reduction/rank3_test_params.yaml" "rank4_reduction_test|03_reduction/rank4_test_params.yaml" "rank5_reduction_test|03_reduction/rank5_test_params.yaml" "rank6_reduction_test|03_reduction/rank6_test_params.yaml" ) # Bench (performance) tests encoded as "binary|config". Same encoding as # _HIPTENSOR_DEVICE_TESTS, but the bench config set is distinct: it has no # trinary/unary contraction variants, and its elementwise configs are flat # (no permutation/binary_op/trinary_op subdirs). Paths are relative to the # bench config root (bin/hiptensor/configs/bench/). Bench runs use different # run-count flags (see the bench family below). set(_HIPTENSOR_BENCH_TESTS "bilinear_contraction_test_m1n1k1|01_contraction/bilinear_test_params_rank1.yaml" "bilinear_contraction_test_m2n2k2|01_contraction/bilinear_test_params_rank2.yaml" "bilinear_contraction_test_m3n3k3|01_contraction/bilinear_test_params_rank3.yaml" "bilinear_contraction_test_m4n4k4|01_contraction/bilinear_test_params_rank4.yaml" "bilinear_contraction_test_m5n5k5|01_contraction/bilinear_test_params_rank5.yaml" "bilinear_contraction_test_m6n6k6|01_contraction/bilinear_test_params_rank6.yaml" "complex_bilinear_contraction_test_m1n1k1|01_contraction/complex_bilinear_test_params_rank1.yaml" "complex_bilinear_contraction_test_m2n2k2|01_contraction/complex_bilinear_test_params_rank2.yaml" "complex_bilinear_contraction_test_m3n3k3|01_contraction/complex_bilinear_test_params_rank3.yaml" "complex_bilinear_contraction_test_m4n4k4|01_contraction/complex_bilinear_test_params_rank4.yaml" "complex_bilinear_contraction_test_m5n5k5|01_contraction/complex_bilinear_test_params_rank5.yaml" "complex_bilinear_contraction_test_m6n6k6|01_contraction/complex_bilinear_test_params_rank6.yaml" "scale_contraction_test_m1n1k1|01_contraction/scale_test_params_rank1.yaml" "scale_contraction_test_m2n2k2|01_contraction/scale_test_params_rank2.yaml" "scale_contraction_test_m3n3k3|01_contraction/scale_test_params_rank3.yaml" "scale_contraction_test_m4n4k4|01_contraction/scale_test_params_rank4.yaml" "scale_contraction_test_m5n5k5|01_contraction/scale_test_params_rank5.yaml" "scale_contraction_test_m6n6k6|01_contraction/scale_test_params_rank6.yaml" "complex_scale_contraction_test_m1n1k1|01_contraction/complex_scale_test_params_rank1.yaml" "complex_scale_contraction_test_m2n2k2|01_contraction/complex_scale_test_params_rank2.yaml" "complex_scale_contraction_test_m3n3k3|01_contraction/complex_scale_test_params_rank3.yaml" "complex_scale_contraction_test_m4n4k4|01_contraction/complex_scale_test_params_rank4.yaml" "complex_scale_contraction_test_m5n5k5|01_contraction/complex_scale_test_params_rank5.yaml" "complex_scale_contraction_test_m6n6k6|01_contraction/complex_scale_test_params_rank6.yaml" "rank2_elementwise_permute_test|02_elementwise/rank2_test_params.yaml" "rank2_elementwise_binary_op_test|02_elementwise/rank2_binary_op_test_params.yaml" "rank2_elementwise_trinary_op_test|02_elementwise/rank2_trinary_op_test_params.yaml" "rank3_elementwise_permute_test|02_elementwise/rank3_test_params.yaml" "rank3_elementwise_binary_op_test|02_elementwise/rank3_binary_op_test_params.yaml" "rank3_elementwise_trinary_op_test|02_elementwise/rank3_trinary_op_test_params.yaml" "rank4_elementwise_permute_test|02_elementwise/rank4_test_params.yaml" "rank4_elementwise_binary_op_test|02_elementwise/rank4_binary_op_test_params.yaml" "rank4_elementwise_trinary_op_test|02_elementwise/rank4_trinary_op_test_params.yaml" "rank5_elementwise_permute_test|02_elementwise/rank5_test_params.yaml" "rank5_elementwise_binary_op_test|02_elementwise/rank5_binary_op_test_params.yaml" "rank5_elementwise_trinary_op_test|02_elementwise/rank5_trinary_op_test_params.yaml" "rank6_elementwise_permute_test|02_elementwise/rank6_test_params.yaml" "rank6_elementwise_binary_op_test|02_elementwise/rank6_binary_op_test_params.yaml" "rank6_elementwise_trinary_op_test|02_elementwise/rank6_trinary_op_test_params.yaml" "rank1_reduction_test|03_reduction/rank1_test_params.yaml" "rank2_reduction_test|03_reduction/rank2_test_params.yaml" "rank3_reduction_test|03_reduction/rank3_test_params.yaml" "rank4_reduction_test|03_reduction/rank4_test_params.yaml" "rank5_reduction_test|03_reduction/rank5_test_params.yaml" "rank6_reduction_test|03_reduction/rank6_test_params.yaml" ) # Helper: append one add_test + set_tests_properties to the main install # fragment. WORKING_DIRECTORY is the install prefix root (../.. from the # installed bin/hiptensor/ fragment) so ./bin/ and the -y config # path resolve regardless of ctest's cwd. function(_hiptensor_emit_test test_name command) file(APPEND "${INSTALL_TEST_FILE}" "add_test(\"${test_name}\" ${command})\n") file(APPEND "${INSTALL_TEST_FILE}" "set_tests_properties(\"${test_name}\" PROPERTIES WORKING_DIRECTORY \"../..\" SKIP_REGULAR_EXPRESSION \"HIPTENSOR_STATUS_ARCH_MISMATCH;unsupported host device\")\n") endfunction() # A config yaml is "effectively empty" when it carries no test parameters. # This is TRUE when the file: # - does not exist, or # - is completely empty (0 bytes), or # - contains nothing beyond YAML document markers (---, ...), blank lines, # and comments. # Any of these is a deliberate signal that a device test is fully covered by an # earlier tier and should NOT run in this one: registering it would hand the # test an empty parameter set, which the GTest-parameterized harness cannot # digest (empty ValuesIn / out-of-bounds param access -> SegFault). We resolve # this at configure time by not emitting the add_test for that (test, tier). function(_hiptensor_config_is_empty config_path out_var) # Default TRUE covers the non-existent and 0-byte cases (file(STRINGS) on an # empty file yields no lines, so the loop below never flips it to FALSE). set(${out_var} TRUE PARENT_SCOPE) if(NOT EXISTS "${config_path}") return() endif() file(STRINGS "${config_path}" _lines) foreach(_line IN LISTS _lines) string(REGEX REPLACE "#.*$" "" _stripped "${_line}") # drop comments string(STRIP "${_stripped}" _stripped) if(_stripped STREQUAL "" OR _stripped STREQUAL "---" OR _stripped STREQUAL "...") continue() endif() set(${out_var} FALSE PARENT_SCOPE) return() endforeach() endfunction() # Tiers (quick / standard / comprehensive / full): host + device. # Each family is "|". # Tier & ffm entries omit run-count flags (the binary defaults are # --hot_runs 1 --cold_runs 0). Host tests are emitted once, under quick, and # nest up into the higher tiers via the parser. foreach(_hiptensor_family "quick|validation/quick" "standard|validation/standard" "comprehensive|validation/comprehensive" "full|validation/full") string(REPLACE "|" ";" _hiptensor_ff "${_hiptensor_family}") list(GET _hiptensor_ff 0 _hiptensor_suffix) list(GET _hiptensor_ff 1 _hiptensor_cfgdir) if(_hiptensor_suffix STREQUAL "quick") foreach(_hiptensor_host IN LISTS _HIPTENSOR_HOST_TESTS) _hiptensor_emit_test("${_hiptensor_host} ${_hiptensor_suffix}" "\"./bin/${_hiptensor_host}\"") endforeach() endif() foreach(_hiptensor_dev IN LISTS _HIPTENSOR_DEVICE_TESTS) string(REPLACE "|" ";" _hiptensor_dev_fields "${_hiptensor_dev}") list(GET _hiptensor_dev_fields 0 _hiptensor_dev_bin) list(GET _hiptensor_dev_fields 1 _hiptensor_dev_cfg) set(_hiptensor_cmd "\"./bin/${_hiptensor_dev_bin}\"") if(NOT _hiptensor_dev_cfg STREQUAL "NONE") # dev_cfg is "/"; the on-disk source lives at # /configs//. Skip this (test, tier) when # that config is empty (covered by an earlier tier). string(FIND "${_hiptensor_dev_cfg}" "/" _hiptensor_dev_slash) string(SUBSTRING "${_hiptensor_dev_cfg}" 0 ${_hiptensor_dev_slash} _hiptensor_dev_comp) math(EXPR _hiptensor_dev_after "${_hiptensor_dev_slash}+1") string(SUBSTRING "${_hiptensor_dev_cfg}" ${_hiptensor_dev_after} -1 _hiptensor_dev_rest) _hiptensor_config_is_empty( "${CMAKE_CURRENT_SOURCE_DIR}/${_hiptensor_dev_comp}/configs/${_hiptensor_cfgdir}/${_hiptensor_dev_rest}" _hiptensor_cfg_empty) if(_hiptensor_cfg_empty) continue() endif() string(APPEND _hiptensor_cmd " -y ./bin/${PROJECT_NAME}/configs/${_hiptensor_cfgdir}/${_hiptensor_dev_cfg}") endif() _hiptensor_emit_test("${_hiptensor_dev_bin} ${_hiptensor_suffix}" "${_hiptensor_cmd}") endforeach() endforeach() # ffm-quick / ffm-full: device only. ffm-quick uses emulation/quick, ffm-full # uses emulation/full (they are now distinct sets, not aliases). foreach(_hiptensor_family "ffm-quick|emulation/quick" "ffm-full|emulation/full") string(REPLACE "|" ";" _hiptensor_ff "${_hiptensor_family}") list(GET _hiptensor_ff 0 _hiptensor_suffix) list(GET _hiptensor_ff 1 _hiptensor_cfgdir) foreach(_hiptensor_dev IN LISTS _HIPTENSOR_DEVICE_TESTS) string(REPLACE "|" ";" _hiptensor_dev_fields "${_hiptensor_dev}") list(GET _hiptensor_dev_fields 0 _hiptensor_dev_bin) list(GET _hiptensor_dev_fields 1 _hiptensor_dev_cfg) set(_hiptensor_cmd "\"./bin/${_hiptensor_dev_bin}\"") if(NOT _hiptensor_dev_cfg STREQUAL "NONE") # Skip this (test, tier) when its config is empty (see tier loop). string(FIND "${_hiptensor_dev_cfg}" "/" _hiptensor_dev_slash) string(SUBSTRING "${_hiptensor_dev_cfg}" 0 ${_hiptensor_dev_slash} _hiptensor_dev_comp) math(EXPR _hiptensor_dev_after "${_hiptensor_dev_slash}+1") string(SUBSTRING "${_hiptensor_dev_cfg}" ${_hiptensor_dev_after} -1 _hiptensor_dev_rest) _hiptensor_config_is_empty( "${CMAKE_CURRENT_SOURCE_DIR}/${_hiptensor_dev_comp}/configs/${_hiptensor_cfgdir}/${_hiptensor_dev_rest}" _hiptensor_cfg_empty) if(_hiptensor_cfg_empty) continue() endif() string(APPEND _hiptensor_cmd " -y ./bin/${PROJECT_NAME}/configs/${_hiptensor_cfgdir}/${_hiptensor_dev_cfg}") endif() _hiptensor_emit_test("${_hiptensor_dev_bin} ${_hiptensor_suffix}" "${_hiptensor_cmd}") endforeach() endforeach() # bench: performance runs. Uses the "bench" config category and performance # run-count flags (more hot runs for stable timings, matching the reference # scripts under scripts/performance/). Named " bench". foreach(_hiptensor_bench IN LISTS _HIPTENSOR_BENCH_TESTS) string(REPLACE "|" ";" _hiptensor_bench_fields "${_hiptensor_bench}") list(GET _hiptensor_bench_fields 0 _hiptensor_bench_bin) list(GET _hiptensor_bench_fields 1 _hiptensor_bench_cfg) set(_hiptensor_cmd "\"./bin/${_hiptensor_bench_bin}\" -y ./bin/${PROJECT_NAME}/configs/bench/${_hiptensor_bench_cfg}") string(APPEND _hiptensor_cmd " --hot_runs 5 --cold_runs 1") _hiptensor_emit_test("${_hiptensor_bench_bin} bench" "${_hiptensor_cmd}") endforeach() # Bake YAML-driven category labels into each install-tree # CTestTestfile.cmake fragment so `ctest --test-dir # /bin/hiptensor[/{smoke,regression}] -L ` works against # the install tree. Passing the install file as the 2nd argument tells # the shared helper to scan it for the test names already written via # add_test() above and emit explicit set_tests_properties(... LABELS ...) # lines (the only label form ctest's script interpreter exposes through # --print-labels / -L). if(COMMAND apply_ctest_category_labels) apply_ctest_category_labels( "${_HIPTENSOR_TEST_CATEGORIES_YAML}" "${INSTALL_TEST_FILE}" ) apply_ctest_category_labels( "${_HIPTENSOR_TEST_CATEGORIES_YAML}" "${INSTALL_SMOKE_TEST_FILE}" ) apply_ctest_category_labels( "${_HIPTENSOR_TEST_CATEGORIES_YAML}" "${INSTALL_REGRESSION_TEST_FILE}" ) endif() include(../cmake/Functions/CopyYamlFolder.cmake) # Copy multiple configuration folders copy_emulation_config_folders( SOURCE_FOLDERS "01_contraction/configs/emulation" "02_elementwise/configs/emulation" "03_reduction/configs/emulation" SOURCE_SCRIPTS "../rtest.py" "../rtest.xml" DESTINATION_PREFIX "test_emulation_config" ) copy_code_coverage_config_files( ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_BINARY_DIR}/code_coverage_config" ) rocm_install( FILES "${INSTALL_TEST_FILE}" DESTINATION "${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}" COMPONENT tests RENAME "CTestTestfile.cmake" ) rocm_install( FILES "${INSTALL_SMOKE_TEST_FILE}" DESTINATION "${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}/smoke" COMPONENT tests RENAME "CTestTestfile.cmake" ) rocm_install( FILES "${INSTALL_REGRESSION_TEST_FILE}" DESTINATION "${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}/regression" COMPONENT tests RENAME "CTestTestfile.cmake" ) # Install the config subtrees so the validation / ffm / bench entries' `-y` paths # resolve at ctest runtime. The on-disk config layout mirrors the install # layout 1:1, so the install path segment IS the on-disk source subtree: # src /configs// # dest bin/hiptensor/configs/// foreach(_hiptensor_cfg_dir validation/quick validation/standard validation/comprehensive validation/full emulation/quick emulation/full bench) foreach(_hiptensor_cfg_component 01_contraction 02_elementwise 03_reduction) rocm_install( DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_hiptensor_cfg_component}/configs/${_hiptensor_cfg_dir}/" DESTINATION "${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}/configs/${_hiptensor_cfg_dir}/${_hiptensor_cfg_component}" COMPONENT tests ) endforeach() endforeach() rocm_install(DIRECTORY ${CMAKE_SOURCE_DIR}/scripts/performance/ DESTINATION "${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}/bench/scripts" COMPONENT tests FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DIRECTORY_PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE GROUP_WRITE WORLD_READ WORLD_EXECUTE )