SWDEV-277697 - Adding Infra and dependent libs: Catch2 and json parser, for new HIP Testing framework

Change-Id: Iedfa041ec9acc13eeb631ff67e1677e2fe29463d


[ROCm/hip-tests commit: be6809d8d1]
This commit is contained in:
cjatin
2021-04-08 14:09:19 +05:30
committed by Maneesh Gupta
orang tua f753eef330
melakukan abab64b35a
33 mengubah file dengan 20941 tambahan dan 0 penghapusan
@@ -0,0 +1,58 @@
# Set HIP Path
if(NOT DEFINED HIP_PATH)
if(DEFINED ENV{HIP_PATH})
set(HIP_PATH $ENV{HIP_PATH} CACHE STRING "HIP Path")
else()
set(HIP_PATH "${PROJECT_BINARY_DIR}")
endif()
endif()
message(STATUS "HIP Path: ${HIP_PATH}")
set(CMAKE_CXX_COMPILER "${HIP_PATH}/bin/hipcc")
if(NOT DEFINED CATCH2_PATH)
if(DEFINED ENV{CATCH2_PATH})
set(CATCH2_PATH $ENV{CATCH2_PATH} CACHE STRING "Catch2 Path")
else()
set(CATCH2_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/Catch2")
endif()
endif()
message(STATUS "Catch2 Path: ${CATCH2_PATH}")
# Set JSON Parser path
if(NOT DEFINED JSON_PARSER)
if(DEFINED ENV{JSON_PARSER})
set(JSON_PARSER $ENV{JSON_PARSER} CACHE STRING "JSON Parser Path")
else()
set(JSON_PARSER "${CMAKE_CURRENT_SOURCE_DIR}/external/picojson")
endif()
endif()
message(STATUS "Searching Catch2 in: ${CMAKE_CURRENT_SOURCE_DIR}/external")
find_package(Catch2 REQUIRED
PATHS
${CMAKE_CURRENT_SOURCE_DIR}/external
PATH_SUFFIXES
Catch2/cmake/Catch2
)
include(Catch)
include(CTest)
include_directories(
${CATCH2_PATH}
"./include"
${HIP_PATH}/include
${JSON_PARSER}
)
cmake_policy(PUSH)
if(POLICY CMP0037)
cmake_policy(SET CMP0037 OLD)
endif()
add_custom_target(build_tests)
add_custom_target(test COMMAND ${CMAKE_CTEST_COMMAND})
add_dependencies(test build_tests)
add_subdirectory(unit)
add_subdirectory(hipTestMain)
add_subdirectory(stress)
cmake_policy(POP)
+76
Melihat File
@@ -0,0 +1,76 @@
# HIP Tests - with Catch2
## Intro and Motivation
HIP Tests were using HIT framework (a custom framework tailored for HIP) to add, build and run tests. As time progressed the frame got big and took substantial amount of effort to maintain and extend. It also took substantial amount of time to configure. We took this oppurtunity to rewrite the HIP's testing framework and porting the test infra to Catch2 format.
## How to write tests
Tests in Catch2 are declared via ```TEST_CASE```.
[Please read the Catch2 documentation on how to write test cases](https://github.com/catchorg/Catch2/blob/v2.13.6/docs/tutorial.md#top)
[Catch2 Detailed Reference](https://github.com/catchorg/Catch2/blob/v2.13.6/docs/Readme.md#top)
## Taking care of existing features
- Dont build on platform: EXCLUDE_(HIP_PLATFORM/HIP_RUNTIME), can be done via CMAKE. Adding source in if(HIP_PLATFORM == amd/nvidia).
- HIPCC_OPTIONS/CLANG Options: Can be done via: set_source_files_properties(src.cc PROPERTIES COMPILE_FLAGS “…”).
- Additional libraries: Can be done via target_link_libraries()
- Multiple runs with different args: This can be done by Catchs Feature: GENERATE(…)
Running Subtest: ctest R “...” (Regex to match the subtest name)
## New Features
- Skip test without recompiling tests, by addition of a json file. Default name is ```config.json``` , this can be overridden by using the variable ```HT_CONFIG_FILE=some_config.json```.
- Json file supports regex. Ex: All tests which has the word Memset can be skipped using *Memset*
- Support multiple skip test list which can be set via environment variable, so you can have multiple files containing different skip test lists and can pick and choose among them depending on your platform and os.
- Better CI integration via xunit compatible output
## Testing Context
HIP testing framework gives you a context for each test. This context will have useful information about the environment your test is running.
Some useful functions are:
- `bool isWindows()` : true if os is windows
- `bool isLinux()` : true if os is linux
- `bool isAmd()` : true if platform is AMD
- `bool isNvidia()` : true if platform is NVIDIA
- `std::vector<std::string> getDevices()` : returns a vector of strings that contains device names (eg: For AMD: gfx906, gfx908 etc / For NVIDIA: RTX 2070 Super)
- `std::vector<std::string> getTargetId()` : (AMD Only) returns target id for gpus (eg: gfx906:sramecc+:xnack- etc)
This information can be accessed in any test via using: `TestContext::get().isAmd()`.
## Config file schema
Some tests can be skipped using a config file placed in same directory as the exe.
The schema of the json file is as follows:
```json
{
"DisabledTests":
[
"TestName1",
"TestName2",
...
]
}
```
## Env Variables
- `HT_CONFIG_FILE` : This variable can be set to the config file name or full path. Disabled tests will be read from this.
- `HT_LOG_ENABLE` : This is for debugging the HIP Test Framework itself. Setting it to 1, all `LogPrintf` will be printed on screen
## Enabling New Tests
Initially, the new tests can be enabled via using ```-DHIP_CATCH_TEST=ON```. After porting existing tests, this will be turned on by default.
## Building a single test
```bash
hipcc <path_to_test.cpp> -I<HIP_SRC_DIR>/tests/newTests/include <HIP_SRC_DIR>/tests/newTests/hipTestMain/standalone_main.cc -I<HIP_SRC_DIR>/tests/newTests/external/Catch2 -g -o <out_file_name>
```
## Debugging support
Catch2 allows multiple ways in which you can debug the test case.
- `-b` options breaks into a debugger as soon as there is a failure encountered [Catch2 Options Reference](https://github.com/catchorg/Catch2/blob/devel/docs/command-line.md#breaking-into-the-debugger)
- Catch2 provided [logging macro](https://github.com/catchorg/Catch2/blob/v2.13.6/docs/logging.md#top) that print useful information on test case failure
- User can also call [CATCH_BREAK_INTO_DEBUGGER](https://github.com/catchorg/Catch2/blob/devel/docs/configuration.md#overriding-catchs-debug-break--b) macro to break at a certain point in a test case.
- User can also mention filename.cc:__LineNumber__ to break into a test case via gdb.
## External Libs being used
- [Catch2](https://github.com/catchorg/Catch2) - Testing framework
- [taocpp/json](https://github.com/taocpp/json) - For config file parsing
- [taocpp/PEGTL](https://github.com/taocpp/PEGTL) - Helper lib for taojson
+23
Melihat File
@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
File diff ditekan karena terlalu besar Load Diff
@@ -0,0 +1,206 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
Catch
-----
This module defines a function to help use the Catch test framework.
The :command:`catch_discover_tests` discovers tests by asking the compiled test
executable to enumerate its tests. This does not require CMake to be re-run
when tests change. However, it may not work in a cross-compiling environment,
and setting test properties is less convenient.
This command is intended to replace use of :command:`add_test` to register
tests, and will create a separate CTest test for each Catch test case. Note
that this is in some cases less efficient, as common set-up and tear-down logic
cannot be shared by multiple test cases executing in the same instance.
However, it provides more fine-grained pass/fail information to CTest, which is
usually considered as more beneficial. By default, the CTest test name is the
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
.. command:: catch_discover_tests
Automatically add tests with CTest by querying the compiled test executable
for available tests::
catch_discover_tests(target
[TEST_SPEC arg1...]
[EXTRA_ARGS arg1...]
[WORKING_DIRECTORY dir]
[TEST_PREFIX prefix]
[TEST_SUFFIX suffix]
[PROPERTIES name1 value1...]
[TEST_LIST var]
[REPORTER reporter]
[OUTPUT_DIR dir]
[OUTPUT_PREFIX prefix}
[OUTPUT_SUFFIX suffix]
)
``catch_discover_tests`` sets up a post-build command on the test executable
that generates the list of tests by parsing the output from running the test
with the ``--list-test-names-only`` argument. This ensures that the full
list of tests is obtained. Since test discovery occurs at build time, it is
not necessary to re-run CMake when the list of tests changes.
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
in order to function in a cross-compiling environment.
Additionally, setting properties on tests is somewhat less convenient, since
the tests are not available at CMake time. Additional test properties may be
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
more fine-grained test control is needed, custom content may be provided
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
directory property. The set of discovered tests is made accessible to such a
script via the ``<target>_TESTS`` variable.
The options are:
``target``
Specifies the Catch executable, which must be a known CMake executable
target. CMake will substitute the location of the built executable when
running the test.
``TEST_SPEC arg1...``
Specifies test cases, wildcarded test cases, tags and tag expressions to
pass to the Catch executable with the ``--list-test-names-only`` argument.
``EXTRA_ARGS arg1...``
Any extra arguments to pass on the command line to each test case.
``WORKING_DIRECTORY dir``
Specifies the directory in which to run the discovered test cases. If this
option is not provided, the current binary directory is used.
``TEST_PREFIX prefix``
Specifies a ``prefix`` to be prepended to the name of each discovered test
case. This can be useful when the same test executable is being used in
multiple calls to ``catch_discover_tests()`` but with different
``TEST_SPEC`` or ``EXTRA_ARGS``.
``TEST_SUFFIX suffix``
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
be specified.
``PROPERTIES name1 value1...``
Specifies additional properties to be set on all tests discovered by this
invocation of ``catch_discover_tests``.
``TEST_LIST var``
Make the list of tests available in the variable ``var``, rather than the
default ``<target>_TESTS``. This can be useful when the same test
executable is being used in multiple calls to ``catch_discover_tests()``.
Note that this variable is only available in CTest.
``REPORTER reporter``
Use the specified reporter when running the test case. The reporter will
be passed to the Catch executable as ``--reporter reporter``.
``OUTPUT_DIR dir``
If specified, the parameter is passed along as
``--out dir/<test_name>`` to Catch executable. The actual file name is the
same as the test name. This should be used instead of
``EXTRA_ARGS --out foo`` to avoid race conditions writing the result output
when using parallel test execution.
``OUTPUT_PREFIX prefix``
May be used in conjunction with ``OUTPUT_DIR``.
If specified, ``prefix`` is added to each output file name, like so
``--out dir/prefix<test_name>``.
``OUTPUT_SUFFIX suffix``
May be used in conjunction with ``OUTPUT_DIR``.
If specified, ``suffix`` is added to each output file name, like so
``--out dir/<test_name>suffix``. This can be used to add a file extension to
the output e.g. ".xml".
#]=======================================================================]
#------------------------------------------------------------------------------
function(catch_discover_tests TARGET)
cmake_parse_arguments(
""
""
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;REPORTER;OUTPUT_DIR;OUTPUT_PREFIX;OUTPUT_SUFFIX"
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
${ARGN}
)
if(NOT _WORKING_DIRECTORY)
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
if(NOT _TEST_LIST)
set(_TEST_LIST ${TARGET}_TESTS)
endif()
## Generate a unique name based on the extra arguments
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS} ${_REPORTER} ${_OUTPUT_DIR} ${_OUTPUT_PREFIX} ${_OUTPUT_SUFFIX}")
string(SUBSTRING ${args_hash} 0 7 args_hash)
# Define rule to generate test list for aforementioned test executable
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
get_property(crosscompiling_emulator
TARGET ${TARGET}
PROPERTY CROSSCOMPILING_EMULATOR
)
add_custom_command(
TARGET ${TARGET} POST_BUILD
BYPRODUCTS "${ctest_tests_file}"
COMMAND "${CMAKE_COMMAND}"
-D "TEST_TARGET=${TARGET}"
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
-D "TEST_SPEC=${_TEST_SPEC}"
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
-D "TEST_PROPERTIES=${_PROPERTIES}"
-D "TEST_PREFIX=${_TEST_PREFIX}"
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
-D "TEST_LIST=${_TEST_LIST}"
-D "TEST_REPORTER=${_REPORTER}"
-D "TEST_OUTPUT_DIR=${_OUTPUT_DIR}"
-D "TEST_OUTPUT_PREFIX=${_OUTPUT_PREFIX}"
-D "TEST_OUTPUT_SUFFIX=${_OUTPUT_SUFFIX}"
-D "CTEST_FILE=${ctest_tests_file}"
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
VERBATIM
)
file(WRITE "${ctest_include_file}"
"if(EXISTS \"${ctest_tests_file}\")\n"
" include(\"${ctest_tests_file}\")\n"
"else()\n"
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
"endif()\n"
)
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
# Add discovered tests to directory TEST_INCLUDE_FILES
set_property(DIRECTORY
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
)
else()
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
if (NOT ${test_include_file_set})
set_property(DIRECTORY
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
)
else()
message(FATAL_ERROR
"Cannot set more than one TEST_INCLUDE_FILE"
)
endif()
endif()
endfunction()
###############################################################################
set(_CATCH_DISCOVER_TESTS_SCRIPT
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
CACHE INTERNAL "Catch2 full path to CatchAddTests.cmake helper file"
)
@@ -0,0 +1,34 @@
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was Catch2Config.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()
####################################################################################
# Avoid repeatedly including the targets
if(NOT TARGET Catch2::Catch2)
# Provide path for scripts
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
include(${CMAKE_CURRENT_LIST_DIR}/Catch2Targets.cmake)
endif()
@@ -0,0 +1,51 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major version is the same as the current one.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "2.13.6")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("2.13.6" MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
else()
set(CVF_VERSION_MAJOR "2.13.6")
endif()
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
# if the installed project requested no architecture check, don't perform the check
if("FALSE")
return()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "")
math(EXPR installedBits " * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
@@ -0,0 +1,99 @@
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6...3.17)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget Catch2::Catch2)
list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endif()
if(TARGET ${_expectedTarget})
list(APPEND _targetsDefined ${_expectedTarget})
endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target Catch2::Catch2
add_library(Catch2::Catch2 INTERFACE IMPORTED)
set_target_properties(Catch2::Catch2 PROPERTIES
INTERFACE_COMPILE_FEATURES "cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_defaulted_functions;cxx_deleted_functions;cxx_final;cxx_lambdas;cxx_noexcept;cxx_override;cxx_range_for;cxx_rvalue_references;cxx_static_assert;cxx_strong_enums;cxx_trailing_return_types;cxx_unicode_literals;cxx_user_literals;cxx_variadic_macros"
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)
if(CMAKE_VERSION VERSION_LESS 3.0.0)
message(FATAL_ERROR "This file relies on consumers using CMake 3.0.0 or greater.")
endif()
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/Catch2Targets-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
if(NOT EXISTS "${file}" )
message(FATAL_ERROR "The imported target \"${target}\" references the file
\"${file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
@@ -0,0 +1,135 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
set(prefix "${TEST_PREFIX}")
set(suffix "${TEST_SUFFIX}")
set(spec ${TEST_SPEC})
set(extra_args ${TEST_EXTRA_ARGS})
set(properties ${TEST_PROPERTIES})
set(reporter ${TEST_REPORTER})
set(output_dir ${TEST_OUTPUT_DIR})
set(output_prefix ${TEST_OUTPUT_PREFIX})
set(output_suffix ${TEST_OUTPUT_SUFFIX})
set(script)
set(suite)
set(tests)
function(add_command NAME)
set(_args "")
# use ARGV* instead of ARGN, because ARGN splits arrays into multiple arguments
math(EXPR _last_arg ${ARGC}-1)
foreach(_n RANGE 1 ${_last_arg})
set(_arg "${ARGV${_n}}")
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
else()
set(_args "${_args} ${_arg}")
endif()
endforeach()
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
endfunction()
# Run test executable to get list of available tests
if(NOT EXISTS "${TEST_EXECUTABLE}")
message(FATAL_ERROR
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
)
endif()
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
OUTPUT_VARIABLE output
RESULT_VARIABLE result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
if(${result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
)
elseif(${result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${result}\n"
" Output: ${output}\n"
)
endif()
string(REPLACE "\n" ";" output "${output}")
# Run test executable to get list of available reporters
execute_process(
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-reporters
OUTPUT_VARIABLE reporters_output
RESULT_VARIABLE reporters_result
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
)
if(${reporters_result} EQUAL 0)
message(WARNING
"Test executable '${TEST_EXECUTABLE}' contains no reporters!\n"
)
elseif(${reporters_result} LESS 0)
message(FATAL_ERROR
"Error running test executable '${TEST_EXECUTABLE}':\n"
" Result: ${reporters_result}\n"
" Output: ${reporters_output}\n"
)
endif()
string(FIND "${reporters_output}" "${reporter}" reporter_is_valid)
if(reporter AND ${reporter_is_valid} EQUAL -1)
message(FATAL_ERROR
"\"${reporter}\" is not a valid reporter!\n"
)
endif()
# Prepare reporter
if(reporter)
set(reporter_arg "--reporter ${reporter}")
endif()
# Prepare output dir
if(output_dir AND NOT IS_ABSOLUTE ${output_dir})
set(output_dir "${TEST_WORKING_DIR}/${output_dir}")
if(NOT EXISTS ${output_dir})
file(MAKE_DIRECTORY ${output_dir})
endif()
endif()
# Parse output
foreach(line ${output})
set(test ${line})
# Escape characters in test case names that would be parsed by Catch2
set(test_name ${test})
foreach(char , [ ])
string(REPLACE ${char} "\\${char}" test_name ${test_name})
endforeach(char)
# ...add output dir
if(output_dir)
string(REGEX REPLACE "[^A-Za-z0-9_]" "_" test_name_clean ${test_name})
set(output_dir_arg "--out ${output_dir}/${output_prefix}${test_name_clean}${output_suffix}")
endif()
# ...and add to script
add_command(add_test
"${prefix}${test}${suffix}"
${TEST_EXECUTOR}
"${TEST_EXECUTABLE}"
"${test_name}"
${extra_args}
"${reporter_arg}"
"${output_dir_arg}"
)
add_command(set_tests_properties
"${prefix}${test}${suffix}"
PROPERTIES
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
${properties}
)
list(APPEND tests "${prefix}${test}${suffix}")
endforeach()
# Create a list of all discovered tests, which users may use to e.g. set
# properties on the tests
add_command(set ${TEST_LIST} ${tests})
# Write CTest script
file(WRITE "${CTEST_FILE}" "${script}")
@@ -0,0 +1,252 @@
#==================================================================================================#
# supported macros #
# - TEST_CASE, #
# - TEMPLATE_TEST_CASE #
# - SCENARIO, #
# - TEST_CASE_METHOD, #
# - CATCH_TEST_CASE, #
# - CATCH_TEMPLATE_TEST_CASE #
# - CATCH_SCENARIO, #
# - CATCH_TEST_CASE_METHOD. #
# #
# Usage #
# 1. make sure this module is in the path or add this otherwise: #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# 2. make sure that you've enabled testing option for the project by the call: #
# enable_testing() #
# 3. add the lines to the script for testing target (sample CMakeLists.txt): #
# project(testing_target) #
# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake.modules/") #
# enable_testing() #
# #
# find_path(CATCH_INCLUDE_DIR "catch.hpp") #
# include_directories(${INCLUDE_DIRECTORIES} ${CATCH_INCLUDE_DIR}) #
# #
# file(GLOB SOURCE_FILES "*.cpp") #
# add_executable(${PROJECT_NAME} ${SOURCE_FILES}) #
# #
# include(ParseAndAddCatchTests) #
# ParseAndAddCatchTests(${PROJECT_NAME}) #
# #
# The following variables affect the behavior of the script: #
# #
# PARSE_CATCH_TESTS_VERBOSE (Default OFF) #
# -- enables debug messages #
# PARSE_CATCH_TESTS_NO_HIDDEN_TESTS (Default OFF) #
# -- excludes tests marked with [!hide], [.] or [.foo] tags #
# PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME (Default ON) #
# -- adds fixture class name to the test name #
# PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME (Default ON) #
# -- adds cmake target name to the test name #
# PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF) #
# -- causes CMake to rerun when file with tests changes so that new tests will be discovered #
# #
# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way #
# a test should be run. For instance to use test MPI, one can write #
# set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) #
# just before calling this ParseAndAddCatchTests function #
# #
# The AdditionalCatchParameters optional variable can be used to pass extra argument to the test #
# command. For example, to include successful tests in the output, one can write #
# set(AdditionalCatchParameters --success) #
# #
# After the script, the ParseAndAddCatchTests_TESTS property for the target, and for each source #
# file in the target is set, and contains the list of the tests extracted from that target, or #
# from that file. This is useful, for example to add further labels or properties to the tests. #
# #
#==================================================================================================#
if (CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.8)
message(FATAL_ERROR "ParseAndAddCatchTests requires CMake 2.8.8 or newer")
endif()
option(PARSE_CATCH_TESTS_VERBOSE "Print Catch to CTest parser debug messages" OFF)
option(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS "Exclude tests with [!hide], [.] or [.foo] tags" OFF)
option(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME "Add fixture class name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME "Add target name to the test name" ON)
option(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS "Add test file to CMAKE_CONFIGURE_DEPENDS property" OFF)
function(ParseAndAddCatchTests_PrintDebugMessage)
if(PARSE_CATCH_TESTS_VERBOSE)
message(STATUS "ParseAndAddCatchTests: ${ARGV}")
endif()
endfunction()
# This removes the contents between
# - block comments (i.e. /* ... */)
# - full line comments (i.e. // ... )
# contents have been read into '${CppCode}'.
# !keep partial line comments
function(ParseAndAddCatchTests_RemoveComments CppCode)
string(ASCII 2 CMakeBeginBlockComment)
string(ASCII 3 CMakeEndBlockComment)
string(REGEX REPLACE "/\\*" "${CMakeBeginBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\\*/" "${CMakeEndBlockComment}" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "${CMakeBeginBlockComment}[^${CMakeEndBlockComment}]*${CMakeEndBlockComment}" "" ${CppCode} "${${CppCode}}")
string(REGEX REPLACE "\n[ \t]*//+[^\n]+" "\n" ${CppCode} "${${CppCode}}")
set(${CppCode} "${${CppCode}}" PARENT_SCOPE)
endfunction()
# Worker function
function(ParseAndAddCatchTests_ParseFile SourceFile TestTarget)
# If SourceFile is an object library, do not scan it (as it is not a file). Exit without giving a warning about a missing file.
if(SourceFile MATCHES "\\\$<TARGET_OBJECTS:.+>")
ParseAndAddCatchTests_PrintDebugMessage("Detected OBJECT library: ${SourceFile} this will not be scanned for tests.")
return()
endif()
# According to CMake docs EXISTS behavior is well-defined only for full paths.
get_filename_component(SourceFile ${SourceFile} ABSOLUTE)
if(NOT EXISTS ${SourceFile})
message(WARNING "Cannot find source file: ${SourceFile}")
return()
endif()
ParseAndAddCatchTests_PrintDebugMessage("parsing ${SourceFile}")
file(STRINGS ${SourceFile} Contents NEWLINE_CONSUME)
# Remove block and fullline comments
ParseAndAddCatchTests_RemoveComments(Contents)
# Find definition of test names
# https://regex101.com/r/JygOND/1
string(REGEX MATCHALL "[ \t]*(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([ \t\n]*\"[^\"]*\"[ \t\n]*(,[ \t\n]*\"[^\"]*\")?(,[ \t\n]*[^\,\)]*)*\\)[ \t\n]*\{+[ \t]*(//[^\n]*[Tt][Ii][Mm][Ee][Oo][Uu][Tt][ \t]*[0-9]+)*" Tests "${Contents}")
if(PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS AND Tests)
ParseAndAddCatchTests_PrintDebugMessage("Adding ${SourceFile} to CMAKE_CONFIGURE_DEPENDS property")
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS ${SourceFile}
)
endif()
# check CMP0110 policy for new add_test() behavior
if(POLICY CMP0110)
cmake_policy(GET CMP0110 _cmp0110_value) # new add_test() behavior
else()
# just to be thorough explicitly set the variable
set(_cmp0110_value)
endif()
foreach(TestName ${Tests})
# Strip newlines
string(REGEX REPLACE "\\\\\n|\n" "" TestName "${TestName}")
# Get test type and fixture if applicable
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
string(REGEX MATCH "(CATCH_)?(TEMPLATE_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
# Get string parts of test definition
string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
# Strip wrapping quotation marks
string(REGEX REPLACE "^\"(.*)\"$" "\\1" TestStrings "${TestStrings}")
string(REPLACE "\";\"" ";" TestStrings "${TestStrings}")
# Validate that a test name and tags have been provided
list(LENGTH TestStrings TestStringsLength)
if(TestStringsLength GREATER 2 OR TestStringsLength LESS 1)
message(FATAL_ERROR "You must provide a valid test name and tags for all tests in ${SourceFile}")
endif()
# Assign name and tags
list(GET TestStrings 0 Name)
if("${TestType}" STREQUAL "SCENARIO")
set(Name "Scenario: ${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME AND "${TestType}" MATCHES "(CATCH_)?TEST_CASE_METHOD" AND TestFixture )
set(CTestName "${TestFixture}:${Name}")
else()
set(CTestName "${Name}")
endif()
if(PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME)
set(CTestName "${TestTarget}:${CTestName}")
endif()
# add target to labels to enable running all tests added from this target
set(Labels ${TestTarget})
if(TestStringsLength EQUAL 2)
list(GET TestStrings 1 Tags)
string(TOLOWER "${Tags}" Tags)
# remove target from labels if the test is hidden
if("${Tags}" MATCHES ".*\\[!?(hide|\\.)\\].*")
list(REMOVE_ITEM Labels ${TestTarget})
endif()
string(REPLACE "]" ";" Tags "${Tags}")
string(REPLACE "[" "" Tags "${Tags}")
else()
# unset tags variable from previous loop
unset(Tags)
endif()
list(APPEND Labels ${Tags})
set(HiddenTagFound OFF)
foreach(label ${Labels})
string(REGEX MATCH "^!hide|^\\." result ${label})
if(result)
set(HiddenTagFound ON)
break()
endif(result)
endforeach(label)
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
ParseAndAddCatchTests_PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
else()
ParseAndAddCatchTests_PrintDebugMessage("Adding test \"${CTestName}\"")
if(Labels)
ParseAndAddCatchTests_PrintDebugMessage("Setting labels to ${Labels}")
endif()
# Escape commas in the test spec
string(REPLACE "," "\\," Name ${Name})
# Work around CMake 3.18.0 change in `add_test()`, before the escaped quotes were necessary,
# only with CMake 3.18.0 the escaped double quotes confuse the call. This change is reverted in 3.18.1
# And properly introduced in 3.19 with the CMP0110 policy
if(_cmp0110_value STREQUAL "NEW" OR ${CMAKE_VERSION} VERSION_EQUAL "3.18")
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to NEW, no need for add_test(\"\") workaround")
else()
ParseAndAddCatchTests_PrintDebugMessage("CMP0110 set to OLD adding \"\" for add_test() workaround")
set(CTestName "\"${CTestName}\"")
endif()
# Handle template test cases
if("${TestTypeAndFixture}" MATCHES ".*TEMPLATE_.*")
set(Name "${Name} - *")
endif()
# Add the test and set its properties
add_test(NAME "${CTestName}" COMMAND ${OptionalCatchTestLauncher} $<TARGET_FILE:${TestTarget}> ${Name} ${AdditionalCatchParameters})
# Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
ParseAndAddCatchTests_PrintDebugMessage("Setting DISABLED test property")
set_tests_properties("${CTestName}" PROPERTIES DISABLED ON)
else()
set_tests_properties("${CTestName}" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
LABELS "${Labels}")
endif()
set_property(
TARGET ${TestTarget}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
set_property(
SOURCE ${SourceFile}
APPEND
PROPERTY ParseAndAddCatchTests_TESTS "${CTestName}")
endif()
endforeach()
endfunction()
# entry point
function(ParseAndAddCatchTests TestTarget)
message(DEPRECATION "ParseAndAddCatchTest: function deprecated because of possibility of missed test cases. Consider using 'catch_discover_tests' from 'Catch.cmake'")
ParseAndAddCatchTests_PrintDebugMessage("Started parsing ${TestTarget}")
get_target_property(SourceFiles ${TestTarget} SOURCES)
ParseAndAddCatchTests_PrintDebugMessage("Found the following sources: ${SourceFiles}")
foreach(SourceFile ${SourceFiles})
ParseAndAddCatchTests_ParseFile(${SourceFile} ${TestTarget})
endforeach()
ParseAndAddCatchTests_PrintDebugMessage("Finished parsing ${TestTarget}")
endfunction()
+25
Melihat File
@@ -0,0 +1,25 @@
Copyright 2009-2010 Cybozu Labs, Inc.
Copyright 2011-2014 Kazuho Oku
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
File diff ditekan karena terlalu besar Load Diff
@@ -0,0 +1,11 @@
if(CMAKE_BUILD_TYPE MATCHES "^Debug$")
add_definitions(-DHT_LOG_ENABLE)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTAO_PEGTL_STD_EXPERIMENTAL_FILESYSTEM=1")
add_library(ht_context SHARED EXCLUDE_FROM_ALL hip_test_context.cc)
set_property(TARGET ht_context PROPERTY CXX_STANDARD 17)
target_link_libraries(ht_context PRIVATE stdc++fs)
add_executable(UnitTests EXCLUDE_FROM_ALL main.cc)
target_link_libraries(UnitTests PRIVATE ht_context DeviceLibs MemoryTest Kernels stdc++fs)
catch_discover_tests(UnitTests PROPERTIES SKIP_REGULAR_EXPRESSION "HIP_SKIP_THIS_TEST")
add_dependencies(build_tests UnitTests)
@@ -0,0 +1,205 @@
#include <hip_test_common.hh>
#include <picojson.h>
#include <fstream>
#include <sstream>
#if __has_include(<filesystem>)
#include <filesystem>
namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#else
#error "gg filesystem"
#endif
#include <regex>
static std::string getValue(std::string option, const std::string& opt_str) {
std::string s_opt = opt_str;
return s_opt.erase(0, option.size());
}
static std::string trimName(std::string input, char trim) {
auto pos_ = input.find(trim);
auto res = input;
if (pos_ == std::string::npos) {
input = "";
} else {
res = input.substr(0, pos_);
input = input.substr(pos_);
}
return res;
}
const std::vector<std::string>& TestContext::getDevices() const { return config_.devices; }
const std::vector<std::string>& TestContext::getTargetId() const { return config_.targetId; }
void TestContext::detectOS() {
#if (HT_WIN == 1)
p_windows = true;
#elif (HT_LINUX == 1)
p_linux = true;
#endif
}
void TestContext::detectPlatform() {
#if (HT_AMD == 1)
amd = true;
#elif (HT_NVIDIA == 1)
nvidia = true;
#endif
}
void TestContext::fillConfig() {
const char* env_config = std::getenv("HT_CONFIG_FILE");
LogPrintf("Env Config file: %s",
(env_config != nullptr) ? env_config : "Not found, using default config");
// Check if path has been provided
std::string config_str;
if (env_config != nullptr) {
config_str = env_config;
} else {
config_str = "config.json";
}
fs::path config_path = config_str;
if (config_path.has_parent_path()) {
config_.json_file = config_str;
} else {
config_.json_file = exe_path + config_str;
}
LogPrintf("Config file path: %s", config_.json_file.c_str());
config_.platform = (amd ? "amd" : (nvidia ? "nvidia" : "unknown"));
config_.os = (p_windows ? "windows" : (p_linux ? "linux" : "unknown"));
if (config_.os == "unknown" || config_.platform == "unknown") {
LogPrintf("%s", "Either Config or Os is unknown, this wont end well");
abort();
}
int deviceCount = 0;
auto res = hipGetDeviceCount(&deviceCount);
if (res != hipSuccess) {
LogPrintf("HIP Device Count query failed with: %s", hipGetErrorString(res));
abort();
}
if (deviceCount == 0) {
LogPrintf("%s", "No hip devices found");
abort();
}
config_.devices.reserve(deviceCount);
for (int i = 0; i < deviceCount; i++) {
hipDeviceProp_t props;
res = hipGetDeviceProperties(&props, i);
if (res != hipSuccess) {
LogPrintf("HIP Device Count query failed with: %s", hipGetErrorString(res));
abort();
}
if (amd) {
std::string tid = std::string(props.gcnArchName);
config_.targetId.push_back(tid);
std::string dev = trimName(tid, ':');
config_.devices.push_back(dev);
} else if (nvidia) {
config_.devices.push_back(std::string(props.name));
} else {
LogPrintf("%s", "Unknown platform");
abort();
}
}
}
TestContext::TestContext(int argc, char** argv) {
detectOS();
detectPlatform();
setExePath(argc, argv);
fillConfig();
parseJsonFile();
parseOptions(argc, argv);
}
void TestContext::setExePath(int argc, char** argv) {
fs::path p = std::string(argv[0]);
if (p.has_filename()) p.remove_filename();
exe_path = p.string();
}
bool TestContext::isWindows() const { return p_windows; }
bool TestContext::isLinux() const { return p_linux; }
bool TestContext::isNvidia() const { return nvidia; }
bool TestContext::isAmd() const { return amd; }
void TestContext::parseOptions(int argc, char** argv) {
// Test name is at [1] position
if (argc != 2) return;
current_test = std::string(argv[1]);
}
bool TestContext::skipTest() const {
// Direct Match
auto flags = std::regex::ECMAScript;
for (const auto& i : skip_test) {
auto regex = std::regex(i.c_str(), flags);
if (std::regex_match(current_test, regex)) {
return true;
}
}
// TODO add test case skip as well
return false;
}
std::string TestContext::currentPath() { return fs::current_path().string(); }
bool TestContext::parseJsonFile() {
// Check if file exists
if (!fs::exists(config_.json_file)) {
LogPrintf("Unable to find the file: %s", config_.json_file.c_str());
return true;
}
// Open the file
std::ifstream js_file(config_.json_file);
std::string json_str((std::istreambuf_iterator<char>(js_file)), std::istreambuf_iterator<char>());
LogPrintf("Json contents:: %s", json_str.data());
picojson::value v;
std::string err;
const char* json_end =
picojson::parse(v, json_str.data(), json_str.data() + json_str.size(), &err);
if (err.size() > 1) {
LogPrintf("Error from PicoJson: %s", err.data());
return false;
}
if (!v.is<picojson::object>()) {
LogPrintf("%s", "Data in json is not in correct format, it should be an object");
return false;
}
const picojson::object &o = v.get<picojson::object>();
for (picojson::object::const_iterator i = o.begin(); i != o.end(); ++i) {
// Processing for DisabledTests
if (i->first == "DisabledTests") {
// Value should contain list of values
if (!i->second.is<picojson::array>()) return false;
auto& val = i->second.get<picojson::array>();
for (auto ai = val.begin(); ai != val.end(); ai++) {
std::string tmp = ai->get<std::string>();
std::string newRegexName;
for(const auto &c : tmp) {
if (c == '*')
newRegexName += ".*";
else
newRegexName += c;
}
skip_test.insert(newRegexName);
}
}
}
return true;
}
@@ -0,0 +1,13 @@
#define CATCH_CONFIG_RUNNER
#include <hip_test_common.hh>
#include <iostream>
int main(int argc, char** argv) {
auto& context = TestContext::get(argc, argv);
if (context.skipTest()) {
// CTest uses this regex to figure out if the test has been skipped
std::cout << "HIP_SKIP_THIS_TEST" << context.getCurrentTest() << std::endl;
return 0;
}
return Catch::Session().run(argc, argv);
}
@@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
@@ -0,0 +1,2 @@
#include "hip_test_context.hh"
#include <catch.hpp>
@@ -0,0 +1,84 @@
#pragma once
#include <hip/hip_runtime.h>
#include <vector>
#include <string>
#include <set>
#if defined(_WIN32)
#define HT_WIN 1
#define HT_LINUX 0
#elif defined(__linux__)
#define HT_WIN 0
#define HT_LINUX 1
#else
#error "OS not recognized"
#endif
#if defined(__HIP_PLATFORM_HCC__) || defined(__HIP_PLATFORM_AMD__)
#define HT_AMD 1
#define HT_NVIDIA 0
#elif defined(__HIP_PLATFORM_NVCC__) || defined(__HIP_PLATFORM_NVIDIA__)
#define HT_AMD 0
#define HT_NVIDIA 1
#else
#error "Platform not recognized"
#endif
static int _log_enable = (std::getenv("HT_LOG_ENABLE") ? 1 : 0);
#define LogPrintf(format, ...) \
{ \
if (_log_enable) { \
printf(format, __VA_ARGS__); \
printf("%c", '\n'); \
} \
}
typedef struct Config_ {
std::string json_file; // Json file
std::string platform; // amd/nvidia
std::vector<std::string> devices; // gfx906, etc
std::vector<std::string> targetId; // Target Ids, only for AMD, gfx906:sramecc+:xnack-
std::string os; // windows/linux
} Config;
class TestContext {
bool p_windows = false, p_linux = false; // OS
bool amd = false, nvidia = false; // HIP Platform
std::string exe_path;
std::string current_test;
std::set<std::string> skip_test;
Config config_;
void detectOS();
void detectPlatform();
void fillConfig();
void setExePath(int, char**);
void parseOptions(int, char**);
bool parseJsonFile();
const Config& getConfig() const { return config_; }
TestContext(int argc, char** argv);
public:
static const TestContext& get(int argc = 0, char** argv = nullptr) {
static TestContext instance(argc, argv);
return instance;
}
bool isWindows() const;
bool isLinux() const;
bool isNvidia() const;
bool isAmd() const;
bool skipTest() const;
const std::vector<std::string>& getDevices() const;
const std::vector<std::string>& getTargetId() const;
const std::string& getCurrentTest() const { return current_test; }
std::string currentPath();
TestContext(const TestContext&) = delete;
void operator=(const TestContext&) = delete;
};
@@ -0,0 +1,7 @@
add_custom_target(build_stress_test)
add_executable(StressTest EXCLUDE_FROM_ALL ../hipTestMain/main.cc)
add_dependencies(build_stress_test StressTest)
add_custom_target(stress_test COMMAND StressTest)
#add_dependencies(stress_test build_stress_test)
add_subdirectory(memory)
target_link_libraries(StressTest PRIVATE memory ht_context)
@@ -0,0 +1,10 @@
# Common Tests - Test independent of all platforms
set(TEST_SRC
memcpy.cc
)
# Create shared lib of all tests
add_library(memory SHARED EXCLUDE_FROM_ALL ${TEST_SRC})
# Add dependency on build_tests to build it on this custom target
add_dependencies(build_stress_test memory)
@@ -0,0 +1,34 @@
#include <hip_test_common.hh>
TEST_CASE("hipMalloc", "DifferentSizes") {
int* d_a = nullptr;
SECTION("Size 10") {
auto res = hipMalloc(&d_a, sizeof(10));
REQUIRE(res == hipSuccess);
hipFree(d_a);
d_a = nullptr;
}
SECTION("Size 100") {
auto res = hipMalloc(&d_a, sizeof(100));
REQUIRE(res == hipSuccess);
hipFree(d_a);
d_a = nullptr;
}
SECTION("Size 1000") {
auto res = hipMalloc(&d_a, sizeof(1000));
REQUIRE(res == hipSuccess);
hipFree(d_a);
d_a = nullptr;
}
SECTION("Size 10000") {
auto res = hipMalloc(&d_a, sizeof(10000));
REQUIRE(res == hipSuccess);
hipFree(d_a);
d_a = nullptr;
}
SECTION("Size MAX") {
auto res = hipMalloc(&d_a, ~(size_t)0);
REQUIRE(res == hipErrorOutOfMemory);
d_a = nullptr;
}
}
@@ -0,0 +1,4 @@
add_subdirectory(memory)
add_subdirectory(deviceLib)
add_subdirectory(kernels)
add_subdirectory(rtc)
@@ -0,0 +1,11 @@
# Common Tests - Test independent of all platforms
set(TEST_SRC
floatMath.cc
vectorTypesDevice.cc
)
# Create shared lib of all tests
add_library(DeviceLibs SHARED EXCLUDE_FROM_ALL ${TEST_SRC})
# Add dependency on build_tests to build it on this custom target
add_dependencies(build_tests DeviceLibs)
@@ -0,0 +1,41 @@
#include <hip_test_common.hh>
#define LEN 512
#define SIZE LEN << 2
__global__ void floatMath(float* In, float* Out) {
int tid = threadIdx.x + blockIdx.x * blockDim.x;
Out[tid] = __cosf(In[tid]);
Out[tid] = __exp10f(Out[tid]);
Out[tid] = __expf(Out[tid]);
Out[tid] = __frsqrt_rn(Out[tid]);
#if defined OCML_BASIC_ROUNDED_OPERATIONS
Out[tid] = __fsqrt_rd(Out[tid]);
#endif
Out[tid] = __fsqrt_rn(Out[tid]);
#if defined OCML_BASIC_ROUNDED_OPERATIONS
Out[tid] = __fsqrt_ru(Out[tid]);
Out[tid] = __fsqrt_rz(Out[tid]);
#endif
Out[tid] = __log10f(Out[tid]);
Out[tid] = __log2f(Out[tid]);
Out[tid] = __logf(Out[tid]);
Out[tid] = __powf(2.0f, Out[tid]);
__sincosf(Out[tid], &In[tid], &Out[tid]);
Out[tid] = __sinf(Out[tid]);
Out[tid] = __cosf(Out[tid]);
Out[tid] = __tanf(Out[tid]);
}
TEST_CASE("FloatMathTest") {
float *Ind, *Outd;
auto res = hipMalloc((void**)&Ind, SIZE);
REQUIRE(res == hipSuccess);
res = hipMalloc((void**)&Outd, SIZE);
REQUIRE(res == hipSuccess);
hipLaunchKernelGGL(floatMath, dim3(LEN, 1, 1), dim3(1, 1, 1), 0, 0, Ind, Outd);
res = hipDeviceSynchronize();
REQUIRE(res == hipSuccess);
res = hipGetLastError();
REQUIRE(res == hipSuccess);
}
@@ -0,0 +1,246 @@
#include <hip_test_common.hh>
#include <type_traits>
#include <memory>
#include <type_traits>
#include <utility>
template <bool b, typename T = void> using Enable_if_t = typename std::enable_if<b, T>::type;
using namespace std;
template <class T> __device__ typename std::add_rvalue_reference<T>::type _declval() noexcept;
template <typename V, Enable_if_t<!is_integral<decltype(_declval<V>().x)>{}>* = nullptr>
__device__ constexpr bool integer_unary_tests(const V&, const V&) {
return true;
}
template <typename V, Enable_if_t<is_integral<decltype(_declval<V>().x)>{}>* = nullptr>
__device__ bool integer_unary_tests(V& f1, V& f2) {
f1 %= f2;
if (f1 != V{0}) return false;
f1 &= f2;
if (f1 != V{0}) return false;
f1 |= f2;
if (f1 != V{1}) return false;
f1 ^= f2;
if (f1 != V{0}) return false;
f1 = V{1};
f1 <<= f2;
if (f1 != V{2}) return false;
f1 >>= f2;
if (f1 != V{1}) return false;
f2 = ~f1;
return f2 == V{~1};
return true;
}
template <typename V, Enable_if_t<!is_integral<decltype(_declval<V>().x)>{}>* = nullptr>
__device__ constexpr bool integer_binary_tests(const V&, const V&, const V&) {
return true;
}
template <typename V, Enable_if_t<is_integral<decltype(_declval<V>().x)>{}>* = nullptr>
__device__ bool integer_binary_tests(V& f1, V& f2, V& f3) {
f3 = f1 % f2;
if (f3 != V{0}) return false;
f1 = f3 & f2;
if (f1 != V{0}) return false;
f2 = f1 ^ f3;
if (f2 != V{0}) return false;
f1 = V{1};
f2 = V{2};
f3 = f1 << f2;
if (f3 != V{4}) return false;
f2 = f3 >> f1;
return f2 == V{2};
}
template <typename V> __device__ bool TestVectorType() {
constexpr V v1{1};
constexpr V v2{2};
constexpr V v3{3};
constexpr V v4{4};
V f1{1};
V f2{1};
V f3 = f1 + f2;
if (f3 != V{2}) return false;
f2 = f3 - f1;
if (f2 != V{1}) return false;
f1 = f2 * f3;
if (f1 != V{2}) return false;
f2 = f1 / f3;
if (f2 != V{1}) return false;
if (!integer_binary_tests(f1, f2, f3)) return false;
f1 = v2;
f2 = v1;
f1 += f2;
if (f1 != v3) return false;
f1 -= f2;
if (f1 != v2) return false;
f1 *= f2;
if (f1 != v2) return false;
f1 /= f2;
if (f1 != v2) return false;
if (!integer_unary_tests(f1, f2)) return false;
f1 = v2;
f2 = f1++;
if (f1 != v3) return false;
if (f2 != v2) return false;
f2 = f1--;
if (f2 != v3) return false;
if (f1 != v2) return false;
f2 = ++f1;
if (f1 != v3) return false;
if (f2 != v3) return false;
f2 = --f1;
if (f1 != v2) return false;
if (f2 != v2) return false;
f1 = v3;
f2 = v4;
f3 = v3;
if (f1 == f2) return false;
if (!(f1 != f2)) return false;
#if 0 // TODO: investigate on GFX8
using T = typename V::value_type;
const T& x = f1.x;
T& y = f2.x;
const volatile T& z = f3.x;
volatile T& w = f2.x;
if (x != T{3}) return false;
if (y != T{4}) return false;
if (z != T{3}) return false;
if (w != T{4}) return false;
#endif
return true;
}
template <typename... Ts, Enable_if_t<sizeof...(Ts) == 0>* = nullptr>
__device__ bool TestVectorTypes() {
return true;
}
template <typename T, typename... Ts> __device__ bool TestVectorTypes() {
if (!TestVectorType<T>()) return false;
return TestVectorTypes<Ts...>();
}
__global__ void CheckVectorTypes(bool* ptr) {
ptr[0] = TestVectorTypes<char1, char2, char3, char4, uchar1, uchar2, uchar3, uchar4, short1,
short2, short3, short4, ushort1, ushort2, ushort3, ushort4, int1, int2,
int3, int4, uint1, uint2, uint3, uint4, long1, long2, long3, long4,
ulong1, ulong2, ulong3, ulong4, longlong1, longlong2, longlong3,
longlong4, ulonglong1, ulonglong2, ulonglong3, ulonglong4, float1,
float2, float3, float4, double1, double2, double3, double4>();
}
template <typename V> __global__ void CheckSharedVectorType(bool* ptr) {
constexpr V v1{1};
constexpr V v2{2};
constexpr V v3{3};
constexpr V v4{4};
__shared__ V f1, f2, f3;
*ptr = true;
f1 = V{1};
f2 = V{1};
f3 = f1 + f2;
*ptr = *ptr && f3 == V{2};
f2 = f3 - f1;
*ptr = *ptr && f2 == V{1};
f1 = f2 * f3;
*ptr = *ptr && f1 == V{2};
f2 = f1 / f3;
*ptr = *ptr && f2 == V{1};
*ptr = *ptr && integer_binary_tests(f1, f2, f3);
f1 = v2;
f2 = v1;
f1 += f2;
*ptr = *ptr && f1 == v3;
f1 -= f2;
*ptr = *ptr && f1 == v2;
f1 *= f2;
*ptr = *ptr && f1 == v2;
f1 /= f2;
*ptr = *ptr && f1 == v2;
*ptr = *ptr && integer_unary_tests(f1, f2);
f1 = v2;
f2 = f1++;
*ptr = *ptr && f1 == v3;
*ptr = *ptr && f2 == v2;
f2 = f1--;
*ptr = *ptr && f2 == v3;
*ptr = *ptr && f1 == v2;
f2 = ++f1;
*ptr = *ptr && f1 == v3;
*ptr = *ptr && f2 == v3;
f2 = --f1;
*ptr = *ptr && f1 == v2;
*ptr = *ptr && f2 == v2;
f1 = v3;
f2 = v4;
f3 = v3;
*ptr = *ptr && f1 != f2;
}
template <typename V> bool run_CheckSharedVectorType() {
bool* ptr = nullptr;
if (hipMalloc(&ptr, sizeof(bool)) != HIP_SUCCESS) return false;
unique_ptr<bool, decltype(hipFree)*> correct{ptr, hipFree};
hipLaunchKernelGGL((CheckSharedVectorType<V>), dim3(1, 1, 1), dim3(1, 1, 1), 0, 0, correct.get());
bool passed = true;
if (hipMemcpyDtoH(&passed, correct.get(), sizeof(bool)) != HIP_SUCCESS) {
return false;
}
return passed;
}
template <typename... Ts, Enable_if_t<sizeof...(Ts) == 0>* = nullptr>
bool run_CheckSharedVectorTypes() {
return true;
}
template <typename V, typename... Vs> bool run_CheckSharedVectorTypes() {
return run_CheckSharedVectorType<V>() && run_CheckSharedVectorTypes<Vs...>();
}
TEST_CASE("VectorTypesTest") {
static_assert(sizeof(float1) == 4, "");
static_assert(sizeof(float2) >= 8, "");
static_assert(sizeof(float3) >= 12, "");
static_assert(sizeof(float4) >= 16, "");
bool* ptr = nullptr;
auto res = hipMalloc(&ptr, sizeof(bool));
REQUIRE(res == hipSuccess);
unique_ptr<bool, decltype(hipFree)*> correct{ptr, hipFree};
hipLaunchKernelGGL(CheckVectorTypes, dim3(1, 1, 1), dim3(1, 1, 1), 0, 0, correct.get());
bool passed = true;
res = hipMemcpyDtoH(&passed, correct.get(), sizeof(bool));
REQUIRE(res == hipSuccess);
passed = passed &&
run_CheckSharedVectorTypes<
char1, char2, char3, char4, uchar1, uchar2, uchar3, uchar4, short1, short2, short3,
short4, ushort1, ushort2, ushort3, ushort4, int1, int2, int3, int4, uint1, uint2,
uint3, uint4, long1, long2, long3, long4, ulong1, ulong2, ulong3, ulong4, longlong1,
longlong2, longlong3, longlong4, ulonglong1, ulonglong2, ulonglong3, ulonglong4,
float1, float2, float3, float4, double1, double2, double3, double4>();
REQUIRE(passed == true);
}
@@ -0,0 +1,10 @@
# Common Tests - Test independent of all platforms
set(TEST_SRC
add.cc
)
# Create shared lib of all tests
add_library(Kernels SHARED EXCLUDE_FROM_ALL ${TEST_SRC})
# Add dependency on build_tests to build it on this custom target
add_dependencies(build_tests Kernels)
@@ -0,0 +1,41 @@
#include <hip_test_common.hh>
#include <iostream>
template <typename T> __global__ void add(T* a, T* b, T* c, size_t size) {
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
TEMPLATE_TEST_CASE("Add Kernel", "[kernel][add]", int, long, float, long long, double) {
auto addKernel = add<TestType>;
auto size = GENERATE(as<size_t>{}, 100, 500, 1000);
TestType *d_a, *d_b, *d_c;
auto res = hipMalloc(&d_a, sizeof(TestType) * size);
REQUIRE(res == hipSuccess);
res = hipMalloc(&d_b, sizeof(TestType) * size);
REQUIRE(res == hipSuccess);
res = hipMalloc(&d_c, sizeof(TestType) * size);
REQUIRE(res == hipSuccess);
std::vector<TestType> a, b, c;
for (int i = 0; i < size; i++) {
a.push_back(i + 1);
b.push_back(i + 1);
c.push_back(2 * (i + 1));
}
res = hipMemcpy(d_a, a.data(), sizeof(TestType) * size, hipMemcpyHostToDevice);
REQUIRE(res == hipSuccess);
res = hipMemcpy(d_b, b.data(), sizeof(TestType) * size, hipMemcpyHostToDevice);
REQUIRE(res == hipSuccess);
hipLaunchKernelGGL(addKernel, 1, size, 0, 0, d_a, d_b, d_c, size);
res = hipMemcpy(a.data(), d_c, sizeof(TestType) * size, hipMemcpyDeviceToHost);
REQUIRE(res == hipSuccess);
hipFree(d_a);
hipFree(d_b);
hipFree(d_c);
REQUIRE(a == c);
}
@@ -0,0 +1,11 @@
# Common Tests - Test independent of all platforms
set(TEST_SRC
memset.cc
malloc.cc
)
# Create shared lib of all tests
add_library(MemoryTest SHARED EXCLUDE_FROM_ALL ${TEST_SRC})
# Add dependency on build_tests to build it on this custom target
add_dependencies(build_tests MemoryTest)
@@ -0,0 +1,17 @@
#include <hip_test_common.hh>
TEST_CASE("HostAllocBasic") {
int* d_a;
auto res = hipHostMalloc(&d_a, sizeof(int), 0);
REQUIRE(res == hipSuccess);
res = hipHostFree(d_a);
REQUIRE(res == hipSuccess);
}
TEST_CASE("AllocateBasic") {
int* d_a;
auto res = hipMalloc(&d_a, sizeof(int));
REQUIRE(res == hipSuccess);
res = hipFree(d_a);
REQUIRE(res == hipSuccess);
}
@@ -0,0 +1,19 @@
#include <hip_test_common.hh>
TEST_CASE("MemsetBasic") {
int* d_a;
auto res = hipMalloc(&d_a, sizeof(int));
REQUIRE(res == hipSuccess);
res = hipMemset(d_a, 0, sizeof(int));
REQUIRE(res == hipSuccess);
hipFree(d_a);
}
TEST_CASE("HostMemsetBasic") {
int* d_a;
auto res = hipHostMalloc(&d_a, sizeof(int), 0);
REQUIRE(res == hipSuccess);
res = hipMemset(d_a, 0, sizeof(int));
REQUIRE(res == hipSuccess);
hipHostFree(d_a);
}
@@ -0,0 +1,14 @@
# Common Tests - Test independent of all platforms
set(TEST_SRC
saxpy.cc
)
# Set source File properties
set_source_files_properties(saxpy.cc PROPERTIES COMPILE_FLAGS " -std=c++14 ")
set_source_files_properties(test.cc PROPERTIES COMPILE_FLAGS " -std=c++17 ")
# Create shared lib of all tests
add_library(RTC SHARED EXCLUDE_FROM_ALL ${TEST_SRC})
# Add dependency on build_tests to build it on this custom target
add_dependencies(build_tests RTC)
@@ -0,0 +1,113 @@
#include <hip_test_common.hh>
#include <hip/hiprtc.h>
#include <hip/hip_runtime.h>
#include <cassert>
#include <cstddef>
#include <memory>
#include <iostream>
#include <iterator>
#include <vector>
static constexpr auto NUM_THREADS{128};
static constexpr auto NUM_BLOCKS{32};
static constexpr auto saxpy{
R"(
#include <hip/hip_runtime.h>
extern "C"
__global__
void saxpy(float a, float* x, float* y, float* out, size_t n)
{
size_t tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < n) {
out[tid] = a * x[tid] + y[tid] ;
}
}
)"};
TEST_CASE("saxpy", "[hiprtc][saxpy]") {
using namespace std;
hiprtcProgram prog;
hiprtcCreateProgram(&prog, // prog
saxpy, // buffer
"saxpy.cu", // name
0, nullptr, nullptr);
hipDeviceProp_t props;
int device = 0;
hipGetDeviceProperties(&props, device);
std::string sarg = std::string("--gpu-architecture=") + props.gcnArchName;
const char* options[] = {sarg.c_str()};
hiprtcResult compileResult{hiprtcCompileProgram(prog, 1, options)};
size_t logSize;
hiprtcGetProgramLogSize(prog, &logSize);
if (logSize) {
string log(logSize, '\0');
hiprtcGetProgramLog(prog, &log[0]);
std::cout << log << '\n';
}
REQUIRE(compileResult == HIPRTC_SUCCESS);
size_t codeSize;
hiprtcGetCodeSize(prog, &codeSize);
vector<char> code(codeSize);
hiprtcGetCode(prog, code.data());
hiprtcDestroyProgram(&prog);
hipModule_t module;
hipFunction_t kernel;
hipModuleLoadData(&module, code.data());
hipModuleGetFunction(&kernel, module, "saxpy");
size_t n = NUM_THREADS * NUM_BLOCKS;
size_t bufferSize = n * sizeof(float);
float a = 5.1f;
unique_ptr<float[]> hX{new float[n]};
unique_ptr<float[]> hY{new float[n]};
unique_ptr<float[]> hOut{new float[n]};
for (size_t i = 0; i < n; ++i) {
hX[i] = static_cast<float>(i);
hY[i] = static_cast<float>(i * 2);
}
hipDeviceptr_t dX, dY, dOut;
hipMalloc(&dX, bufferSize);
hipMalloc(&dY, bufferSize);
hipMalloc(&dOut, bufferSize);
hipMemcpyHtoD(dX, hX.get(), bufferSize);
hipMemcpyHtoD(dY, hY.get(), bufferSize);
struct {
float a_;
hipDeviceptr_t b_;
hipDeviceptr_t c_;
hipDeviceptr_t d_;
size_t e_;
} args{a, dX, dY, dOut, n};
auto size = sizeof(args);
void* config[] = {HIP_LAUNCH_PARAM_BUFFER_POINTER, &args,
HIP_LAUNCH_PARAM_BUFFER_SIZE, &size,
HIP_LAUNCH_PARAM_END};
hipModuleLaunchKernel(kernel, NUM_BLOCKS, 1, 1, NUM_THREADS, 1, 1,
0, nullptr, nullptr, config);
hipMemcpyDtoH(hOut.get(), dOut, bufferSize);
for (size_t i = 0; i < n; ++i) {
REQUIRE(fabs(a * hX[i] + hY[i] - hOut[i]) > fabs(hOut[i]) * 1e-6);
}
hipFree(dX);
hipFree(dY);
hipFree(dOut);
hipModuleUnload(module);
}
@@ -0,0 +1,6 @@
#include <hip_test_common.hh>
TEST_CASE("cpp17 test") {
constexpr auto l = []() { return 2 * 10 * 30; };
REQUIRE(l() == 600);
}