Skip to content

Commit

Permalink
Support installing tests + parallel test infra
Browse files Browse the repository at this point in the history
  • Loading branch information
robertmaynard committed Dec 21, 2022
1 parent e4c64e5 commit aa41d6e
Show file tree
Hide file tree
Showing 10 changed files with 354 additions and 6 deletions.
1 change: 1 addition & 0 deletions rapids-cmake/rapids-test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ include_guard(GLOBAL)
include(${CMAKE_CURRENT_LIST_DIR}/test/init.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/test/add.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/test/gpu_requirements.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/test/install_relocatable.cmake)
48 changes: 42 additions & 6 deletions rapids-cmake/test/add.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ States how many GPUs and what percent of each a test requires.
rapids_test_add(NAME <name> COMMAND <target|command> [<args>...]
GPUS <N> [PERCENT <value>]
[INSTALL_COMPONENT_SET <set>]
[WORKING_DIRECTORY <dir>])
Add a test called `<name>` which will be executed with a given GPU
Expand All @@ -51,15 +52,22 @@ same GPU and quickly exhaust all memory.
By default if no percent is provided, 100 is used.
State how much of each GPU this test requires.
``INSTALL_COMPONENT_SET``
Record which component that the underlying executable for the test will be installed by. This is used
by :cmake:command:`rapids_test_install_relocatable` to allow for execution of the installed tests
by ctest
``WORKING_DIRECTORY``
Specify the working directory in which to execute the test. If not specified the test will
be run with the current working directory set to the value of :cmake:variable:`CMAKE_CURRENT_BINARY_DIR <cmake:variable:CMAKE_CURRENT_BINARY_DIR>`.
#]=======================================================================]
function(rapids_test_add)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.test.add")

set(options)
set(one_value NAME WORKING_DIRECTORY GPUS PERCENT)
set(one_value NAME WORKING_DIRECTORY GPUS PERCENT INSTALL_COMPONENT_SET)
set(multi_value COMMAND)
cmake_parse_arguments(_RAPIDS_TEST "${options}" "${one_value}" "${multi_value}" ${ARGN})

Expand All @@ -71,9 +79,11 @@ function(rapids_test_add)
message(FATAL_ERROR "rapids_add_test called without a command")
endif()

list(POP_FRONT _RAPIDS_TEST_COMMAND command)
list(POP_FRONT _RAPIDS_TEST_COMMAND command_or_target)
set(args "${_RAPIDS_TEST_COMMAND}")
if(TARGET ${command})

set(command ${command_or_target})
if(TARGET ${command_or_target})
set(command "$<TARGET_FILE:${command}>")
endif()

Expand All @@ -84,6 +94,7 @@ function(rapids_test_add)
# Provide a copy of the test runner in the binary directory so that tests still can be executed if
# for some reason rapids-cmake src has been removed.
set(_rapids_run_gpu_test_script "${PROJECT_BINARY_DIR}/rapids-cmake/run_gpu_test.cmake")
set(_rapids_run_gpu_test_script_for_install "./run_gpu_test.cmake")
if(NOT EXISTS "${_rapids_run_gpu_test_script}")
file(COPY "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/detail/run_gpu_test.cmake"
DESTINATION "${PROJECT_BINARY_DIR}/rapids-cmake/")
Expand All @@ -95,7 +106,32 @@ function(rapids_test_add)
WORKING_DIRECTORY "${_RAPIDS_TEST_WORKING_DIRECTORY}")

include(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/gpu_requirements.cmake)
rapids_test_gpu_requirements(${_RAPIDS_TEST_NAME} GPUS ${_RAPIDS_TEST_GPUS}
PERCENT ${_RAPIDS_TEST_PERCENT})

rapids_test_gpu_requirements(${_RAPIDS_TEST_NAME} GPUS ${_RAPIDS_TEST_GPUS} PERCENT ${_RAPIDS_TEST_PERCENT})

if(_RAPIDS_TEST_INSTALL_COMPONENT_SET)
include(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/detail/record_test_component.cmake)
include(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/detail/record_test_command.cmake)
include(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/detail/record_install.cmake)

if(NOT TARGET rapids_test_install_${_RAPIDS_TEST_INSTALL_COMPONENT_SET})
add_library(rapids_test_install_${_RAPIDS_TEST_INSTALL_COMPONENT_SET} INTERFACE)
endif()


if(TARGET ${command_or_target})
get_target_property(output_name ${command_or_target} OUTPUT_NAME)
if(output_name)
set(command_for_install "./${output_name}")
else()
set(command_for_install "./${command_or_target}")
endif()
rapids_test_record_install(TARGET ${command_or_target} COMPONENT ${_RAPIDS_TEST_INSTALL_COMPONENT_SET})
else()
set(command_for_install ${command_or_target})
endif()
rapids_test_record_test_component(NAME ${_RAPIDS_TEST_NAME} COMPONENT ${_RAPIDS_TEST_INSTALL_COMPONENT_SET})
rapids_test_record_test_command(NAME ${_RAPIDS_TEST_NAME}
COMMAND cmake "-Dcommand_to_run=${command_for_install}" "-Dcommand_args=${args}" -P
"${_rapids_run_gpu_test_script_for_install}")
endif()
endfunction()
42 changes: 42 additions & 0 deletions rapids-cmake/test/detail/record_install.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#=============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include_guard(GLOBAL)

#[=======================================================================[.rst:
rapids_test_record_install
--------------------------
.. versionadded:: v23.02.00
Record that the provided target should have install rules specified when
:cmake:command:`rapids_test_install_relocatable` is called with the given component.
.. code-block:: cmake
rapids_test_record_install(TARGET <name> COMPONENT <set>)
#]=======================================================================]
function(rapids_test_record_install)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.test.record_install")

set(options)
set(one_value TARGET COMPONENT)
set(multi_value )
cmake_parse_arguments(_RAPIDS_TEST "${options}" "${one_value}" "${multi_value}" ${ARGN})

set(component ${_RAPIDS_TEST_COMPONENT})
set_property(TARGET rapids_test_install_${component} APPEND PROPERTY "TARGETS_TO_INSTALL" "${_RAPIDS_TEST_TARGET}")
endfunction()
40 changes: 40 additions & 0 deletions rapids-cmake/test/detail/record_test_command.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#=============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include_guard(GLOBAL)

#[=======================================================================[.rst:
rapids_test_record_test_command
-------------------------------
.. versionadded:: v23.02.00
Record the test command that needs to run when executed via ctest after installation
.. code-block:: cmake
rapids_test_record_test_command(NAME <name> COMMAND command <args>...)
#]=======================================================================]
function(rapids_test_record_test_command)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.test.record_test_command")

set(options)
set(one_value NAME)
set(multi_value COMMAND)
cmake_parse_arguments(_RAPIDS_TEST "${options}" "${one_value}" "${multi_value}" ${ARGN})

set_property(TEST ${_RAPIDS_TEST_NAME} PROPERTY INSTALL_COMMAND "${_RAPIDS_TEST_COMMAND}")
endfunction()
41 changes: 41 additions & 0 deletions rapids-cmake/test/detail/record_test_component.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#=============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include_guard(GLOBAL)

#[=======================================================================[.rst:
rapids_test_record_test_component
---------------------------------
.. versionadded:: v23.02.00
Record what component a test is part of
.. code-block:: cmake
rapids_test_record_test_component(NAME <name> COMPONENT <set>)
#]=======================================================================]
function(rapids_test_record_test_component)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.test.record_test_component")

set(options)
set(one_value NAME COMPONENT)
set(multi_value )
cmake_parse_arguments(_RAPIDS_TEST "${options}" "${one_value}" "${multi_value}" ${ARGN})

set(component ${_RAPIDS_TEST_COMPONENT})
set_property(TARGET rapids_test_install_${component} APPEND PROPERTY "TESTS_TO_RUN" "${_RAPIDS_TEST_NAME}")
endfunction()
2 changes: 2 additions & 0 deletions rapids-cmake/test/gpu_requirements.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ same GPU and quickly exhaust all memory.
#]=======================================================================]
function(rapids_test_gpu_requirements test_name)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.test.gpu_requirements")

set(options)
set(one_value GPUS PERCENT)
set(multi_value)
Expand Down
110 changes: 110 additions & 0 deletions rapids-cmake/test/install_relocatable.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#=============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include_guard(GLOBAL)

#[=======================================================================[.rst:
rapids_test_install_relocatable
-------------------------------
.. versionadded:: v23.02.00
Install the needed `ctest` infrastructure to allow installed tests to be run
by `ctest` in parallel with GPU awarness.
.. code-block:: cmake
rapids_test_install_relocatable(INSTALL_COMPONENT_SET <component>
DESTINATION <relative_path>
[EXCLUDE_FROM_ALL])
Add ...
``INSTALL_COMPONENT_SET``
Record which test component infrastructure to be installed
``DESTINATION``
Relative path from the `CMAKE_INSTALL_PREFIX` to install the infrastructure.
This needs to be the same directory as the test exectuables
``EXCLUDE_FROM_ALL``
State that these install rules shouldn't be part of the default install set, and
instead must be explicitly installed.
#]=======================================================================]
function(rapids_test_install_relocatable)
list(APPEND CMAKE_MESSAGE_CONTEXT "rapids.test.install_relocatable")

set(options EXCLUDE_FROM_ALL)
set(one_value INSTALL_COMPONENT_SET DESTINATION)
set(multi_value)
cmake_parse_arguments(_RAPIDS_TEST "${options}" "${one_value}" "${multi_value}" ${ARGN})

set(to_exclude )
if(_RAPIDS_TEST_EXCLUDE_FROM_ALL)
set(to_exclude EXCLUDE_FROM_ALL)
endif()

set(component ${_RAPIDS_TEST_INSTALL_COMPONENT_SET})
if(NOT TARGET rapids_test_install_${component})
message(FATAL_ERROR "No install component set [${component}] can be found")
endif()

get_target_property(targets_to_install rapids_test_install_${component} TARGETS_TO_INSTALL)
get_target_property(tests_to_run rapids_test_install_${component} TESTS_TO_RUN)

# Write out the relocatable CTestFile that we can install!
# Presumes a 1 to 1 mapping of test name to executable
set(content [==[
set(CTEST_SCRIPT_DIRECTORY ".")
set(CTEST_RESOURCE_SPEC_FILE "./resource_spec.json")
execute_process(COMMAND ./generate_ctest_json OUTPUT_FILE "${CTEST_RESOURCE_SPEC_FILE}")
]==])

foreach(test IN LISTS tests_to_run)
get_test_property(${test} INSTALL_COMMAND command)
get_test_property(${test} RESOURCE_GROUPS resources)
string(APPEND content "add_test([=[${test}]=] ${command})\n")
string(APPEND content "set_tests_properties([=[${test}]=] PROPERTIES RESOURCE_GROUPS ${resources})\n")
endforeach()

set(test_launcher_file "${CMAKE_CURRENT_BINARY_DIR}/rapids-cmake/${_RAPIDS_TEST_INSTALL_COMPONENT_SET}/CTestTestfile.cmake.to_install")
file(WRITE "${test_launcher_file}" "${content}")
install(
FILES "${test_launcher_file}"
COMPONENT ${_RAPIDS_TEST_INSTALL_COMPONENT_SET}
DESTINATION ${_RAPIDS_TEST_DESTINATION}
RENAME "CTestTestfile.cmake"
${to_exclude})

# We need to install the rapids-test gpu detector, and the json script
# we also need to write out / install the new CTestTestfile.cmake
install(
PROGRAMS "${PROJECT_BINARY_DIR}/rapids-cmake/generate_ctest_json"
COMPONENT ${_RAPIDS_TEST_INSTALL_COMPONENT_SET}
DESTINATION ${_RAPIDS_TEST_DESTINATION}
${to_exclude})
install(
FILES "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/detail/run_gpu_test.cmake"
COMPONENT ${_RAPIDS_TEST_INSTALL_COMPONENT_SET}
DESTINATION ${_RAPIDS_TEST_DESTINATION}
${to_exclude})
install(
TARGETS ${targets_to_install}
COMPONENT ${_RAPIDS_TEST_INSTALL_COMPONENT_SET}
DESTINATION ${_RAPIDS_TEST_DESTINATION}
${to_exclude})
endfunction()
2 changes: 2 additions & 0 deletions testing/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ add_cmake_config_test(init-existing-specfile.cmake)
add_cmake_config_test(init-simple.cmake)

add_cmake_ctest_test(add-impossible-allocation SHOULD_FAIL "Insufficient resources for test")
add_cmake_config_test(add-with-install-component.cmake)
add_cmake_config_test(add-with-no-gpus.cmake SHOULD_FAIL "${gpu_missing_message}")
if(RAPIDS_CMAKE_TESTING_GPU_COUNT GREATER 0)
add_cmake_ctest_test(add-allocation-simple)
add_cmake_ctest_test(add-multi-allocations-same-gpu)
Expand Down
46 changes: 46 additions & 0 deletions testing/test/add-with-install-component.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#=============================================================================
# Copyright (c) 2022, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#=============================================================================
include(${rapids-cmake-dir}/test/init.cmake)
include(${rapids-cmake-dir}/test/add.cmake)

enable_language(CUDA)

rapids_test_init()

file(WRITE "${CMAKE_BINARY_DIR}/main.cu" "int main(){return 0;}")
add_executable(verify_alloc "${CMAKE_BINARY_DIR}/main.cu")

enable_testing()
rapids_test_add(NAME simple_test COMMAND verify_alloc GPUS 1 INSTALL_COMPONENT_SET testing)

# Verify that we have recorded `simple_test` as part of the `testing` component
get_target_property(names rapids_test_install_testing TESTS_TO_RUN)
if(NOT "simple_test" IN_LIST names)
message(FATAL_ERROR "Failed to record `simple_test` as part of the testing component")
endif()

# Verify that `verify_alloc` is marked as to be installed
get_target_property(names rapids_test_install_testing TARGETS_TO_INSTALL)
if(NOT "verify_alloc" IN_LIST names)
message(FATAL_ERROR "Failed to record `verify_alloc` as a target to be installed in the testing component")
endif()

# Verify we recorded some install command for `simple_test`
get_test_property(simple_test INSTALL_COMMAND install_command)
if(NOT install_command)
message(FATAL_ERROR "Failed to record the command to run `simple_test` after installing it")
endif()

Loading

0 comments on commit aa41d6e

Please sign in to comment.