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:
committed by
Maneesh Gupta
orang tua
f753eef330
melakukan
abab64b35a
@@ -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)
|
||||
@@ -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
|
||||
- Don’t 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 Catch’s 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
|
||||
@@ -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.
|
||||
+17881
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()
|
||||
+51
@@ -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)
|
||||
+135
@@ -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}")
|
||||
+252
@@ -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()
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user