From aa41d6e9c6fa2be42c6b261f05155ebb6cf19e0e Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Tue, 20 Dec 2022 16:33:22 -0500 Subject: [PATCH] Support installing tests + parallel test infra --- rapids-cmake/rapids-test.cmake | 1 + rapids-cmake/test/add.cmake | 48 +++++++- rapids-cmake/test/detail/record_install.cmake | 42 +++++++ .../test/detail/record_test_command.cmake | 40 +++++++ .../test/detail/record_test_component.cmake | 41 +++++++ rapids-cmake/test/gpu_requirements.cmake | 2 + rapids-cmake/test/install_relocatable.cmake | 110 ++++++++++++++++++ testing/test/CMakeLists.txt | 2 + testing/test/add-with-install-component.cmake | 46 ++++++++ testing/test/add-with-no-gpus.cmake | 28 +++++ 10 files changed, 354 insertions(+), 6 deletions(-) create mode 100644 rapids-cmake/test/detail/record_install.cmake create mode 100644 rapids-cmake/test/detail/record_test_command.cmake create mode 100644 rapids-cmake/test/detail/record_test_component.cmake create mode 100644 rapids-cmake/test/install_relocatable.cmake create mode 100644 testing/test/add-with-install-component.cmake create mode 100644 testing/test/add-with-no-gpus.cmake diff --git a/rapids-cmake/rapids-test.cmake b/rapids-cmake/rapids-test.cmake index 774688185..a3801a088 100644 --- a/rapids-cmake/rapids-test.cmake +++ b/rapids-cmake/rapids-test.cmake @@ -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) diff --git a/rapids-cmake/test/add.cmake b/rapids-cmake/test/add.cmake index cfb8e0710..2e1cc27f4 100644 --- a/rapids-cmake/test/add.cmake +++ b/rapids-cmake/test/add.cmake @@ -27,6 +27,7 @@ States how many GPUs and what percent of each a test requires. rapids_test_add(NAME COMMAND [...] GPUS [PERCENT ] + [INSTALL_COMPONENT_SET ] [WORKING_DIRECTORY ]) Add a test called `` which will be executed with a given GPU @@ -51,6 +52,11 @@ 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 `. @@ -58,8 +64,10 @@ same GPU and quickly exhaust all memory. #]=======================================================================] 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}) @@ -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 "$") endif() @@ -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/") @@ -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() diff --git a/rapids-cmake/test/detail/record_install.cmake b/rapids-cmake/test/detail/record_install.cmake new file mode 100644 index 000000000..6267acfc1 --- /dev/null +++ b/rapids-cmake/test/detail/record_install.cmake @@ -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 COMPONENT ) + +#]=======================================================================] +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() diff --git a/rapids-cmake/test/detail/record_test_command.cmake b/rapids-cmake/test/detail/record_test_command.cmake new file mode 100644 index 000000000..2c03233ec --- /dev/null +++ b/rapids-cmake/test/detail/record_test_command.cmake @@ -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 COMMAND command ...) + +#]=======================================================================] +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() diff --git a/rapids-cmake/test/detail/record_test_component.cmake b/rapids-cmake/test/detail/record_test_component.cmake new file mode 100644 index 000000000..3552b8add --- /dev/null +++ b/rapids-cmake/test/detail/record_test_component.cmake @@ -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 COMPONENT ) + +#]=======================================================================] +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() diff --git a/rapids-cmake/test/gpu_requirements.cmake b/rapids-cmake/test/gpu_requirements.cmake index 6514ddb98..81f11229d 100644 --- a/rapids-cmake/test/gpu_requirements.cmake +++ b/rapids-cmake/test/gpu_requirements.cmake @@ -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) diff --git a/rapids-cmake/test/install_relocatable.cmake b/rapids-cmake/test/install_relocatable.cmake new file mode 100644 index 000000000..9b70f1a2a --- /dev/null +++ b/rapids-cmake/test/install_relocatable.cmake @@ -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 + DESTINATION + [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() diff --git a/testing/test/CMakeLists.txt b/testing/test/CMakeLists.txt index b4e7fa509..89584b73b 100644 --- a/testing/test/CMakeLists.txt +++ b/testing/test/CMakeLists.txt @@ -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) diff --git a/testing/test/add-with-install-component.cmake b/testing/test/add-with-install-component.cmake new file mode 100644 index 000000000..35f26495e --- /dev/null +++ b/testing/test/add-with-install-component.cmake @@ -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() + diff --git a/testing/test/add-with-no-gpus.cmake b/testing/test/add-with-no-gpus.cmake new file mode 100644 index 000000000..980140f4e --- /dev/null +++ b/testing/test/add-with-no-gpus.cmake @@ -0,0 +1,28 @@ +#============================================================================= +# 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 INSTALL_COMPONENT_SET testing) +