From 441dc2315bbff906aa37c6de63617d926bbc615e Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 29 Nov 2022 16:40:00 -0700 Subject: [PATCH 01/55] Remove package configs --- ...d.cmake => Configure_morpheus_utils.cmake} | 24 +- cmake/dependencies.cmake | 24 +- cmake/deps/Configure_RMM.cmake | 52 -- cmake/deps/Configure_boost.cmake | 83 -- cmake/deps/Configure_gcov.cmake | 725 ------------------ cmake/deps/Configure_glog.cmake | 40 - cmake/deps/Configure_hwloc.cmake | 161 ---- cmake/deps/Configure_libcudacxx.cmake | 38 - cmake/deps/Configure_prometheus.cmake | 50 -- cmake/deps/Configure_pybind11.cmake | 40 - cmake/deps/Configure_rxcpp.cmake | 40 - cmake/deps/Configure_taskflow.cmake | 43 -- cmake/deps/Configure_ucx.cmake | 182 ----- cmake/deps/patches/cpuaff.patch | 23 - .../deps/patches/prometheus_export_fix.patch | 17 - cmake/deps/patches/pybind11.patch | 74 -- cmake/deps/patches/ucx.patch | 35 - .../deps/templates/pkgconfig_package.cmake.in | 13 - .../rapids_cpm_package_overrides.json | 0 19 files changed, 25 insertions(+), 1639 deletions(-) rename cmake/{deps/Configure_expected.cmake => Configure_morpheus_utils.cmake} (62%) delete mode 100644 cmake/deps/Configure_RMM.cmake delete mode 100644 cmake/deps/Configure_boost.cmake delete mode 100644 cmake/deps/Configure_gcov.cmake delete mode 100644 cmake/deps/Configure_glog.cmake delete mode 100644 cmake/deps/Configure_hwloc.cmake delete mode 100644 cmake/deps/Configure_libcudacxx.cmake delete mode 100644 cmake/deps/Configure_prometheus.cmake delete mode 100644 cmake/deps/Configure_pybind11.cmake delete mode 100644 cmake/deps/Configure_rxcpp.cmake delete mode 100644 cmake/deps/Configure_taskflow.cmake delete mode 100644 cmake/deps/Configure_ucx.cmake delete mode 100644 cmake/deps/patches/cpuaff.patch delete mode 100644 cmake/deps/patches/prometheus_export_fix.patch delete mode 100644 cmake/deps/patches/pybind11.patch delete mode 100644 cmake/deps/patches/ucx.patch delete mode 100644 cmake/deps/templates/pkgconfig_package.cmake.in rename cmake/{deps => }/rapids_cpm_package_overrides.json (100%) diff --git a/cmake/deps/Configure_expected.cmake b/cmake/Configure_morpheus_utils.cmake similarity index 62% rename from cmake/deps/Configure_expected.cmake rename to cmake/Configure_morpheus_utils.cmake index 0ece0a921..ad267d13b 100644 --- a/cmake/deps/Configure_expected.cmake +++ b/cmake/Configure_morpheus_utils.cmake @@ -15,22 +15,18 @@ # limitations under the License. # ============================================================================= -function(find_and_configure_tl_expected version) - list(APPEND CMAKE_MESSAGE_CONTEXT "tl-expected") +function(find_and_configure_morpheus_utils version) + list(APPEND CMAKE_MESSAGE_CONTEXT "morpheus_utils") - rapids_cpm_find(tl-expected ${version} - GLOBAL_TARGETS - expected tl::expected - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports + rapids_cpm_find(morpheus_utils ${version} CPM_ARGS - GIT_REPOSITORY https://github.com/ryanolson/expected.git - GIT_TAG "5f4b7d2987658cc2a555ce7f4f5b81196461d953" - GIT_SHALLOW TRUE - OPTIONS "EXPECTED_BUILD_PACKAGE ON" + #GIT_REPOSITORY https://github.com/ryanolson/expected.git + GIT_REPOSITORY /home/drobison/Development/devin-morpheus-utils-public + GIT_TAG v${version} + DOWNLOAD_ONLY TRUE ) + + set(MORPHEUS_UTILS_HOME "${morpheus_utils_SOURCE_DIR}" CACHE INTERNAL "Morpheus utils home") endfunction() -find_and_configure_tl_expected(${EXPECTED_VERSION}) +find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 10fddcf59..7df0d9936 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -53,26 +53,32 @@ rapids_find_package(CUDAToolkit INSTALL_EXPORT_SET ${PROJECT_NAME}-core-exports ) +set(MORPHEUS_UTILS_VERSION "0.1" CACHE STRING "Version of morphues utils") +include(Configure_morpheus_utils) + +list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") +list(APPEND CMAKE_PREFIX_PATH "${MORPHEUS_UTILS_HOME}/cmake") + # Boost # ===== # - Use static linking to avoid issues with system-wide installations of Boost. # - Use numa=on to ensure the numa component of fiber gets built set(BOOST_VERSION "1.74.0" CACHE STRING "Version of boost to use") -include(deps/Configure_boost) +include(package_config/boost/Configure_boost) # UCX # === set(UCX_VERSION "1.13" CACHE STRING "Version of ucx to use") -include(deps/Configure_ucx) +include(package_config/ucx/Configure_ucx) # hwloc # ===== set(HWLOC_VERSION "2.5" CACHE STRING "Version of hwloc to use") -include(deps/Configure_hwloc) +include(package_config/hwloc/Configure_hwloc) # expected set(EXPECTED_VERSION "1.0.0" CACHE STRING "Version of expected to use") -include(deps/Configure_expected) +include(package_config/expected/Configure_expected) # FlatBuffers # =========== @@ -87,7 +93,7 @@ include(deps/Configure_expected) # NVIDIA RAPIDS RMM # ================= set(RMM_VERSION "\${MRC_RAPIDS_VERSION}" CACHE STRING "Version of RMM to use. Defaults to \${MRC_RAPIDS_VERSION}") -include(deps/Configure_RMM) +include(package_config/rmm/Configure_rmm) # gflags # ====== @@ -105,7 +111,7 @@ rapids_find_package(gflags REQUIRED # - link against shared # - todo: compile with -DWITH_GFLAGS=OFF and remove gflags dependency set(GLOG_VERSION "0.6" CACHE STRING "Version of glog to use") -include(deps/Configure_glog) +include(package_config/glog/Configure_glog) # nvidia cub # ========== @@ -128,7 +134,7 @@ rapids_find_package(gRPC REQUIRED # RxCpp # ===== set(RXCPP_VERSION "4.1.1.2" CACHE STRING "Version of RxCpp to use") -include(deps/Configure_rxcpp) +include(package_config/rxcpp/Configure_rxcpp) # JSON # ====== @@ -143,12 +149,12 @@ rapids_find_package(nlohmann_json REQUIRED # prometheus # ========= set(PROMETHEUS_CPP_VERSION "1.0.0" CACHE STRING "Version of Prometheus-cpp to use") -include(deps/Configure_prometheus) +include(package_config/prometheus/Configure_prometheus) # libcudacxx # ========= set(LIBCUDACXX_VERSION "1.8.0" CACHE STRING "Version of libcudacxx to use") -include(deps/Configure_libcudacxx) +include(package_config/libcudacxx/Configure_libcudacxx) if(MRC_BUILD_BENCHMARKS) # google benchmark diff --git a/cmake/deps/Configure_RMM.cmake b/cmake/deps/Configure_RMM.cmake deleted file mode 100644 index 8cde48ffd..000000000 --- a/cmake/deps/Configure_RMM.cmake +++ /dev/null @@ -1,52 +0,0 @@ -# ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -# ============================================================================= - -function(find_and_configure_rmm version) - list(APPEND CMAKE_MESSAGE_CONTEXT "rmm") - - include(cpm/rmm) - - # Does not work with cudf currently. Once updated to include rmm::Thrust to the GLOBAL_TARGETS. This should be used - # rapids_cpm_rmm( - # BUILD_EXPORT_SET ${PROJECT_NAME}-core-exports - # INSTALL_EXPORT_SET ${PROJECT_NAME}-core-exports - # ) - - # Allow setting version to a variable. If so, evaluate that here. Allows for dependent versions, i.e. RMM_VERSION=${MRC_RAPIDS_VERSION} - if("${version}" MATCHES [=[^\${(.+)}$]=]) - set(version "${${CMAKE_MATCH_1}}") - endif() - - rapids_cpm_find(rmm ${version} - GLOBAL_TARGETS - rmm::rmm rmm::Thrust - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/rapidsai/rmm.git - GIT_TAG branch-${version} - GIT_SHALLOW TRUE - OPTIONS "BUILD_TESTS OFF" - "BUILD_BENCHMARKS OFF" - "CUDA_STATIC_RUNTIME OFF" - "DISABLE_DEPRECATION_WARNING ${DISABLE_DEPRECATION_WARNINGS}" - ) -endfunction() - -find_and_configure_rmm(${RMM_VERSION}) diff --git a/cmake/deps/Configure_boost.cmake b/cmake/deps/Configure_boost.cmake deleted file mode 100644 index e618cb501..000000000 --- a/cmake/deps/Configure_boost.cmake +++ /dev/null @@ -1,83 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -# This function is for when boost fully supports CMake. As of 1.76.0 the -# functionality is not supported but is in the master branch. Check in version -# 1.77 -function(find_and_configure_boost_true_cmake version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "boost") - - cmake_policy(SET CMP0097 OLD) - set(Boost_ENABLE_CMAKE ON) - set(Boost_INCLUDE_LIBRARIES "fiber thread" CACHE STRING "") - set(Boost_EXCLUDE_LIBRARIES "leaf property_tree" CACHE STRING "") - set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs - - rapids_cpm_find(Boost ${version} - GLOBAL_TARGETS - Boost::context Boost::fiber Boost::hana Boost::filesystem Boost::system - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/boostorg/boost.git - GIT_TAG v${version} - GIT_SHALLOW TRUE - GIT_SUBMODULES "" - OPTIONS "BUILD_TESTING OFF" - FIND_PACKAGE_ARGUMENTS "COMPONENTS context fiber filesystem system" - ) -endfunction() - -# This function uses boost-cmake (https://github.com/Orphis/boost-cmake) to -# configure boost. Not always up to date. -function(find_and_configure_boost_boost_cmake version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "boost") - - set(Boost_USE_DEBUG_LIBS OFF) # ignore debug libs - - rapids_cpm_find(Boost ${version} - GLOBAL_TARGETS - Boost::context Boost::fiber Boost::hana Boost::filesystem Boost::system - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/Orphis/boost-cmake.git - GIT_TAG "7f97a08b64bd5d2e53e932ddf80c40544cf45edf" - GIT_SHALLOW TRUE - OPTIONS "BUILD_TESTING OFF" - FIND_PACKAGE_ARGUMENTS "COMPONENTS context fiber filesystem system" - ) - - if (NOT Boost_ADDED) - # Now add it to the list of packages to install - rapids_export_package(INSTALL Boost - ${PROJECT_NAME}-core-exports - GLOBAL_TARGETS Boost::context Boost::fiber Boost::hana Boost::filesystem Boost::system - ) - - # Overwrite the default package contents - file(WRITE "${CMAKE_BINARY_DIR}/rapids-cmake/${PROJECT_NAME}-core-exports/install/package_Boost.cmake" "find_dependency(Boost REQUIRED COMPONENTS context fiber filesystem system)") - endif() -endfunction() - -find_and_configure_boost_boost_cmake(${BOOST_VERSION}) diff --git a/cmake/deps/Configure_gcov.cmake b/cmake/deps/Configure_gcov.cmake deleted file mode 100644 index f13f4a01e..000000000 --- a/cmake/deps/Configure_gcov.cmake +++ /dev/null @@ -1,725 +0,0 @@ -# Copyright (c) 2012 - 2017, Lars Bilke -# 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. -# -# 3. Neither the name of the copyright holder nor the names of its contributors -# may be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# 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. -# -# CHANGES: -# -# 2012-01-31, Lars Bilke -# - Enable Code Coverage -# -# 2013-09-17, Joakim Söderberg -# - Added support for Clang. -# - Some additional usage instructions. -# -# 2016-02-03, Lars Bilke -# - Refactored functions to use named parameters -# -# 2017-06-02, Lars Bilke -# - Merged with modified version from github.com/ufz/ogs -# -# 2019-05-06, Anatolii Kurotych -# - Remove unnecessary --coverage flag -# -# 2019-12-13, FeRD (Frank Dana) -# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor -# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments. -# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY -# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list -# - Set lcov basedir with -b argument -# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be -# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().) -# - Delete output dir, .info file on 'make clean' -# - Remove Python detection, since version mismatches will break gcovr -# - Minor cleanup (lowercase function names, update examples...) -# -# 2019-12-19, FeRD (Frank Dana) -# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets -# -# 2020-01-19, Bob Apthorpe -# - Added gfortran support -# -# 2020-02-17, FeRD (Frank Dana) -# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters -# in EXCLUDEs, and remove manual escaping from gcovr targets -# -# 2021-01-19, Robin Mueller -# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run -# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional -# flags to the gcovr command -# -# 2020-05-04, Mihchael Davis -# - Add -fprofile-abs-path to make gcno files contain absolute paths -# - Fix BASE_DIRECTORY not working when defined -# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines -# -# 2021-05-10, Martin Stump -# - Check if the generator is multi-config before warning about non-Debug builds -# -# 2022-02-22, Marko Wehle -# - Change gcovr output from -o for --xml and --html output respectively. -# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt". -# -# USAGE: -# -# 1. Copy this file into your cmake modules path. -# -# 2. Add the following line to your CMakeLists.txt (best inside an if-condition -# using a CMake option() to enable it just optionally): -# include(CodeCoverage) -# -# 3. Append necessary compiler flags for all supported source files: -# append_coverage_compiler_flags() -# Or for specific target: -# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME) -# -# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og -# -# 4. If you need to exclude additional directories from the report, specify them -# using full paths in the COVERAGE_EXCLUDES variable before calling -# setup_target_for_coverage_*(). -# Example: -# set(COVERAGE_EXCLUDES -# '${PROJECT_SOURCE_DIR}/src/dir1/*' -# '/path/to/my/src/dir2/*') -# Or, use the EXCLUDE argument to setup_target_for_coverage_*(). -# Example: -# setup_target_for_coverage_lcov( -# NAME coverage -# EXECUTABLE testrunner -# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*") -# -# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set -# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR) -# Example: -# set(COVERAGE_EXCLUDES "dir1/*") -# setup_target_for_coverage_gcovr_html( -# NAME coverage -# EXECUTABLE testrunner -# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src" -# EXCLUDE "dir2/*") -# -# 5. Use the functions described below to create a custom make target which -# runs your test executable and produces a code coverage report. -# -# 6. Build a Debug build: -# cmake -DCMAKE_BUILD_TYPE=Debug .. -# make -# make my_coverage_target -# - -include(CMakeParseArguments) - -option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) - -# Check prereqs -find_program( GCOV_PATH gcov ) -find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl) -find_program( FASTCOV_PATH NAMES fastcov fastcov.py ) -find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat ) -find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) -find_program( CPPFILT_PATH NAMES c++filt ) - -if(NOT GCOV_PATH) - message(FATAL_ERROR "gcov not found! Aborting...") -endif() # NOT GCOV_PATH - -get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) -list(GET LANGUAGES 0 LANG) - -if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3) - message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") - endif() -elseif(NOT CMAKE_COMPILER_IS_GNUCXX) - if("${CMAKE_Fortran_COMPILER_ID}" MATCHES "[Ff]lang") - # Do nothing; exit conditional without error if true - elseif("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU") - # Do nothing; exit conditional without error if true - else() - message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") - endif() -endif() - -set(COVERAGE_COMPILER_FLAGS "-g" "-fprofile-arcs" "-ftest-coverage" - CACHE INTERNAL "") -if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") - include(CheckCXXCompilerFlag) - check_cxx_compiler_flag(-fprofile-abs-path HAVE_fprofile_abs_path) - if(HAVE_fprofile_abs_path) - set(COVERAGE_COMPILER_FLAGS ${COVERAGE_COMPILER_FLAGS} "-fprofile-abs-path") - endif() -endif() - -set(CMAKE_Fortran_FLAGS_COVERAGE - ${COVERAGE_COMPILER_FLAGS} - CACHE STRING "Flags used by the Fortran compiler during coverage builds." - FORCE ) -set(CMAKE_CXX_FLAGS_COVERAGE - ${COVERAGE_COMPILER_FLAGS} - CACHE STRING "Flags used by the C++ compiler during coverage builds." - FORCE ) -set(CMAKE_C_FLAGS_COVERAGE - ${COVERAGE_COMPILER_FLAGS} - CACHE STRING "Flags used by the C compiler during coverage builds." - FORCE ) -set(CMAKE_EXE_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used for linking binaries during coverage builds." - FORCE ) -set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used by the shared libraries linker during coverage builds." - FORCE ) -mark_as_advanced( - CMAKE_Fortran_FLAGS_COVERAGE - CMAKE_CXX_FLAGS_COVERAGE - CMAKE_C_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) - -get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)) - message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") -endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG) - -if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") - link_libraries(gcov) -endif() - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_lcov( -# NAME testrunner_coverage # New target name -# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES testrunner # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# NO_DEMANGLE # Don't demangle C++ symbols -# # even if c++filt is found -# ) -function(setup_target_for_coverage_lcov) - - set(options NO_DEMANGLE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT LCOV_PATH) - message(FATAL_ERROR "lcov not found! Aborting...") - endif() # NOT LCOV_PATH - - if(NOT GENHTML_PATH) - message(FATAL_ERROR "genhtml not found! Aborting...") - endif() # NOT GENHTML_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(DEFINED Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(LCOV_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND LCOV_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES LCOV_EXCLUDES) - - # Conditional arguments - if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) - set(GENHTML_EXTRA_ARGS "--demangle-cpp") - endif() - - # Setting up commands which will be run to generate coverage data. - # Cleanup lcov - set(LCOV_CLEAN_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -directory . - -b ${BASEDIR} --zerocounters - ) - # Create baseline to make sure untouched files show up in the report - set(LCOV_BASELINE_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b - ${BASEDIR} -o ${Coverage_NAME}.base - ) - # Run tests - set(LCOV_EXEC_TESTS_CMD - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - ) - # Capturing lcov counters and generating report - set(LCOV_CAPTURE_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b - ${BASEDIR} --capture --output-file ${Coverage_NAME}.capture - ) - # add baseline counters - set(LCOV_BASELINE_COUNT_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base - -a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total - ) - # filter collected data to final coverage report - set(LCOV_FILTER_CMD - ${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove - ${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info - ) - # Generate HTML output - set(LCOV_GEN_HTML_CMD - ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o - ${Coverage_NAME} ${Coverage_NAME}.info - ) - - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Executed command report") - message(STATUS "Command to clean up lcov: ") - string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}") - message(STATUS "${LCOV_CLEAN_CMD_SPACED}") - - message(STATUS "Command to create baseline: ") - string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}") - message(STATUS "${LCOV_BASELINE_CMD_SPACED}") - - message(STATUS "Command to run the tests: ") - string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}") - message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}") - - message(STATUS "Command to capture counters and generate report: ") - string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}") - message(STATUS "${LCOV_CAPTURE_CMD_SPACED}") - - message(STATUS "Command to add baseline counters: ") - string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}") - message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}") - - message(STATUS "Command to filter collected data: ") - string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}") - message(STATUS "${LCOV_FILTER_CMD_SPACED}") - - message(STATUS "Command to generate lcov HTML output: ") - string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}") - message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}") - endif() - - # Setup target - add_custom_target(${Coverage_NAME} - COMMAND ${LCOV_CLEAN_CMD} - COMMAND ${LCOV_BASELINE_CMD} - COMMAND ${LCOV_EXEC_TESTS_CMD} - COMMAND ${LCOV_CAPTURE_CMD} - COMMAND ${LCOV_BASELINE_COUNT_CMD} - COMMAND ${LCOV_FILTER_CMD} - COMMAND ${LCOV_GEN_HTML_CMD} - - # Set output files as GENERATED (will be removed on 'make clean') - BYPRODUCTS - ${Coverage_NAME}.base - ${Coverage_NAME}.capture - ${Coverage_NAME}.total - ${Coverage_NAME}.info - ${Coverage_NAME}/index.html - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." - ) - - # Show where to find the lcov info report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." - ) - -endfunction() # setup_target_for_coverage_lcov - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_gcovr_xml( -# NAME ctest_coverage # New target name -# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES executable_target # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# ) -# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the -# GCVOR command. -function(setup_target_for_coverage_gcovr_xml) - - set(options NONE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT GCOVR_PATH) - message(FATAL_ERROR "gcovr not found! Aborting...") - endif() # NOT GCOVR_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(DEFINED Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(GCOVR_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES GCOVR_EXCLUDES) - - # Combine excludes to several -e arguments - set(GCOVR_EXCLUDE_ARGS "") - foreach(EXCLUDE ${GCOVR_EXCLUDES}) - list(APPEND GCOVR_EXCLUDE_ARGS "-e") - list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") - endforeach() - - # Set up commands which will be run to generate coverage data - # Run tests - set(GCOVR_XML_EXEC_TESTS_CMD - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - ) - # Running gcovr - set(GCOVR_XML_CMD - ${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} - ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} - ) - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Executed command report") - - message(STATUS "Command to run tests: ") - string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}") - message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}") - - message(STATUS "Command to generate gcovr XML coverage data: ") - string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}") - message(STATUS "${GCOVR_XML_CMD_SPACED}") - endif() - - add_custom_target(${Coverage_NAME} - COMMAND ${GCOVR_XML_EXEC_TESTS_CMD} - COMMAND ${GCOVR_XML_CMD} - - BYPRODUCTS ${Coverage_NAME}.xml - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce Cobertura code coverage report." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." - ) -endfunction() # setup_target_for_coverage_gcovr_xml - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_gcovr_html( -# NAME ctest_coverage # New target name -# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES executable_target # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative -# # to BASE_DIRECTORY, with CMake 3.4+) -# ) -# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the -# GCVOR command. -function(setup_target_for_coverage_gcovr_html) - - set(options NONE) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT GCOVR_PATH) - message(FATAL_ERROR "gcovr not found! Aborting...") - endif() # NOT GCOVR_PATH - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(DEFINED Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (CMake 3.4+: Also compute absolute paths) - set(GCOVR_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES}) - if(CMAKE_VERSION VERSION_GREATER 3.4) - get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR}) - endif() - list(APPEND GCOVR_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES GCOVR_EXCLUDES) - - # Combine excludes to several -e arguments - set(GCOVR_EXCLUDE_ARGS "") - foreach(EXCLUDE ${GCOVR_EXCLUDES}) - list(APPEND GCOVR_EXCLUDE_ARGS "-e") - list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}") - endforeach() - - # Set up commands which will be run to generate coverage data - # Run tests - set(GCOVR_HTML_EXEC_TESTS_CMD - ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS} - ) - # Create folder - set(GCOVR_HTML_FOLDER_CMD - ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME} - ) - # Running gcovr - set(GCOVR_HTML_CMD - ${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS} - ${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR} - ) - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Executed command report") - - message(STATUS "Command to run tests: ") - string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}") - message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}") - - message(STATUS "Command to create a folder: ") - string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}") - message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}") - - message(STATUS "Command to generate gcovr HTML coverage data: ") - string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}") - message(STATUS "${GCOVR_HTML_CMD_SPACED}") - endif() - - add_custom_target(${Coverage_NAME} - COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD} - COMMAND ${GCOVR_HTML_FOLDER_CMD} - COMMAND ${GCOVR_HTML_CMD} - - BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Running gcovr to produce HTML code coverage report." - ) - - # Show info where to find the report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ; - COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report." - ) - -endfunction() # setup_target_for_coverage_gcovr_html - -# Defines a target for running and collection code coverage information -# Builds dependencies, runs the given executable and outputs reports. -# NOTE! The executable should always have a ZERO as exit code otherwise -# the coverage generation will not complete. -# -# setup_target_for_coverage_fastcov( -# NAME testrunner_coverage # New target name -# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR -# DEPENDENCIES testrunner # Dependencies to build first -# BASE_DIRECTORY "../" # Base directory for report -# # (defaults to PROJECT_SOURCE_DIR) -# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude. -# NO_DEMANGLE # Don't demangle C++ symbols -# # even if c++filt is found -# SKIP_HTML # Don't create html report -# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths -# ) -function(setup_target_for_coverage_fastcov) - - set(options NO_DEMANGLE SKIP_HTML) - set(oneValueArgs BASE_DIRECTORY NAME) - set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD) - cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(NOT FASTCOV_PATH) - message(FATAL_ERROR "fastcov not found! Aborting...") - endif() - - if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH) - message(FATAL_ERROR "genhtml not found! Aborting...") - endif() - - # Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR - if(Coverage_BASE_DIRECTORY) - get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE) - else() - set(BASEDIR ${PROJECT_SOURCE_DIR}) - endif() - - # Collect excludes (Patterns, not paths, for fastcov) - set(FASTCOV_EXCLUDES "") - foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES}) - list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}") - endforeach() - list(REMOVE_DUPLICATES FASTCOV_EXCLUDES) - - # Conditional arguments - if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE}) - set(GENHTML_EXTRA_ARGS "--demangle-cpp") - endif() - - # Set up commands which will be run to generate coverage data - set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}) - - set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} - --search-directory ${BASEDIR} - --process-gcno - --output ${Coverage_NAME}.json - --exclude ${FASTCOV_EXCLUDES} - --exclude ${FASTCOV_EXCLUDES} - ) - - set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH} - -C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info - ) - - if(Coverage_SKIP_HTML) - set(FASTCOV_HTML_CMD ";") - else() - set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} - -o ${Coverage_NAME} ${Coverage_NAME}.info - ) - endif() - - set(FASTCOV_POST_CMD ";") - if(Coverage_POST_CMD) - set(FASTCOV_POST_CMD ${Coverage_POST_CMD}) - endif() - - if(CODE_COVERAGE_VERBOSE) - message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):") - - message(" Running tests:") - string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}") - message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}") - - message(" Capturing fastcov counters and generating report:") - string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}") - message(" ${FASTCOV_CAPTURE_CMD_SPACED}") - - message(" Converting fastcov .json to lcov .info:") - string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}") - message(" ${FASTCOV_CONVERT_CMD_SPACED}") - - if(NOT Coverage_SKIP_HTML) - message(" Generating HTML report: ") - string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}") - message(" ${FASTCOV_HTML_CMD_SPACED}") - endif() - if(Coverage_POST_CMD) - message(" Running post command: ") - string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}") - message(" ${FASTCOV_POST_CMD_SPACED}") - endif() - endif() - - # Setup target - add_custom_target(${Coverage_NAME} - - # Cleanup fastcov - COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH} - --search-directory ${BASEDIR} - --zerocounters - - COMMAND ${FASTCOV_EXEC_TESTS_CMD} - COMMAND ${FASTCOV_CAPTURE_CMD} - COMMAND ${FASTCOV_CONVERT_CMD} - COMMAND ${FASTCOV_HTML_CMD} - COMMAND ${FASTCOV_POST_CMD} - - # Set output files as GENERATED (will be removed on 'make clean') - BYPRODUCTS - ${Coverage_NAME}.info - ${Coverage_NAME}.json - ${Coverage_NAME}/index.html # report directory - - WORKING_DIRECTORY ${PROJECT_BINARY_DIR} - DEPENDS ${Coverage_DEPENDENCIES} - VERBATIM # Protect arguments to commands - COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report." - ) - - set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.") - if(NOT Coverage_SKIP_HTML) - string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.") - endif() - # Show where to find the fastcov info report - add_custom_command(TARGET ${Coverage_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG} - ) - -endfunction() # setup_target_for_coverage_fastcov - -function(append_coverage_compiler_flags) - foreach(FLAG IN LISTS COVERAGE_COMPILER_FLAGS) - string(APPEND CMAKE_C_FLAGS " ${FLAG}") - string(APPEND CMAKE_CXX_FLAGS " ${FLAG}") - string(APPEND CMAKE_Fortran_FLAGS " ${FLAG}") - endforeach() - - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" PARENT_SCOPE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE) - set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS}" PARENT_SCOPE) - message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") -endfunction() # append_coverage_compiler_flags - -# Setup coverage for specific library -function(append_coverage_compiler_flags_to_target name) - target_compile_options(${name} - PRIVATE ${COVERAGE_COMPILER_FLAGS}) -endfunction() \ No newline at end of file diff --git a/cmake/deps/Configure_glog.cmake b/cmake/deps/Configure_glog.cmake deleted file mode 100644 index dad8a36ed..000000000 --- a/cmake/deps/Configure_glog.cmake +++ /dev/null @@ -1,40 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_glog version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "glog") - - rapids_cpm_find(glog ${version} - GLOBAL_TARGETS - glog glog::glog - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/google/glog.git - GIT_TAG v${version} - GIT_SHALLOW TRUE - OPTIONS "WITH_CUSTOM_PREFIX ON" - "WITH_PKGCONFIG OFF" - "BUILD_TESTING OFF" - ) - -endfunction() - -find_and_configure_glog(${GLOG_VERSION}) diff --git a/cmake/deps/Configure_hwloc.cmake b/cmake/deps/Configure_hwloc.cmake deleted file mode 100644 index bcf03956c..000000000 --- a/cmake/deps/Configure_hwloc.cmake +++ /dev/null @@ -1,161 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -find_package(CUDAToolkit) - -function(find_and_configure_hwloc version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "hwloc") - - set(oneValueArgs VERSION PINNED_TAG) - cmake_parse_arguments(PKG "${options}" "${oneValueArgs}" - "${multiValueArgs}" ${ARGN} ) - - # # Generate the find modules since hwloc doesnt do this for us - # rapids_find_generate_module(hwloc - # HEADER_NAMES - # hwloc.h - # LIBRARY_NAMES - # hwloc - # VERSION - # hwloc_VERSION - # ) - - find_package(PkgConfig) - - pkg_check_modules(hwloc IMPORTED_TARGET GLOBAL hwloc) - - if (hwloc_FOUND) - - message(STATUS "Found hwloc with pkg-config at: ${hwloc_LIBRARY_DIRS}") - - # Add an alias to the imported target - add_library(hwloc::hwloc ALIAS PkgConfig::hwloc) - - set(name "hwloc") - - # Now add it to the list of packages to install - rapids_export_package(INSTALL hwloc - ${PROJECT_NAME}-core-exports - GLOBAL_TARGETS hwloc::hwloc - ) - - # Overwrite the default package contents - configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/templates/pkgconfig_package.cmake.in" - "${CMAKE_BINARY_DIR}/rapids-cmake/${PROJECT_NAME}-core-exports/install/package_hwloc.cmake" @ONLY) - - else() - - # Try to find hwloc and download from source if not found - rapids_cpm_find(hwloc ${version} - GLOBAL_TARGETS - hwloc hwloc::hwloc - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/open-mpi/hwloc.git - GIT_TAG "hwloc-${version}" - DOWNLOAD_ONLY TRUE - FIND_PACKAGE_ARGUMENTS "EXACT" - ) - - if (hwloc_ADDED) - # If we got here, hwloc wasnt found. Add custom targets to build from source. - message(STATUS "hwloc not installed. Building from source.") - - # Location where all files will be temp installed - set(hwloc_INSTALL_DIR ${hwloc_BINARY_DIR}/install) - - # Ensure the output exists - # file(MAKE_DIRECTORY ${hwloc_INSTALL_DIR}) - file(MAKE_DIRECTORY ${hwloc_INSTALL_DIR}/include) - # file(MAKE_DIRECTORY ${hwloc_BINARY_DIR}/include) - - include(ExternalProject) - - string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE_UC) - - # Get the Compiler settings to forward onto autoconf - set(COMPILER_SETTINGS - "CXX=${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}" - "CPP=${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER} -E" - "CC=${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}" - "AR=${CMAKE_C_COMPILER_AR}" - "RANLIB=${CMAKE_C_COMPILER_RANLIB}" - "NM=${CMAKE_NM}" - "STRIP=${CMAKE_STRIP}" - "CFLAGS=${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BUILD_TYPE_UC}}" - "CPPFLAGS=${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BUILD_TYPE_UC}} -I${CUDAToolkit_INCLUDE_DIRS}" # Add CUDAToolkit here - "CXXFLAGS=${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BUILD_TYPE_UC}}" - "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_${BUILD_TYPE_UC}}" - ) - - ExternalProject_Add(hwloc - PREFIX ${hwloc_BINARY_DIR} - SOURCE_DIR ${hwloc_BINARY_DIR} - INSTALL_DIR ${hwloc_INSTALL_DIR} - # Copy from CPM cache into the build tree - DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E copy_directory ${hwloc_SOURCE_DIR} ${hwloc_BINARY_DIR} - # Note, we set SED and GREP here since they can be hard coded in the conda libtoolize - CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env SED=sed GREP=grep /autogen.sh - COMMAND /configure ${COMPILER_SETTINGS} --prefix=${CMAKE_INSTALL_PREFIX} --enable-plugins=linux,x86,nvml,pcie,xml --enable-static - BUILD_COMMAND make -j - BUILD_IN_SOURCE TRUE - BUILD_BYPRODUCTS /lib/libhwloc.a - INSTALL_COMMAND make install prefix= - LOG_CONFIGURE TRUE - LOG_BUILD TRUE - LOG_INSTALL TRUE - # Add a target for configuring to allow for style checks on source code - STEP_TARGETS install - ) - - # Install only the headers - install( - DIRECTORY ${hwloc_INSTALL_DIR}/include - TYPE INCLUDE - ) - - add_library(hwloc::hwloc STATIC IMPORTED GLOBAL) - - set_target_properties(hwloc::hwloc PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "$;$" - INTERFACE_POSITION_INDEPENDENT_CODE "ON" - ) - set_property(TARGET hwloc::hwloc APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(hwloc::hwloc PROPERTIES - IMPORTED_LOCATION_RELEASE "${hwloc_INSTALL_DIR}/lib/libhwloc.a" - IMPORTED_SONAME_RELEASE "libhwloc.a" - ) - - # # Add public dependency of xml2 - # set_target_properties(hwloc::hwloc PROPERTIES - # INTERFACE_LINK_LIBRARIES "xml2" - # ) - add_dependencies(hwloc::hwloc hwloc) - - # Finally, add this to the style check dependencies - add_dependencies(${PROJECT_NAME}_style_checks hwloc-install) - - endif() - endif() - -endfunction() - -find_and_configure_hwloc(${HWLOC_VERSION}) diff --git a/cmake/deps/Configure_libcudacxx.cmake b/cmake/deps/Configure_libcudacxx.cmake deleted file mode 100644 index 46f7d1898..000000000 --- a/cmake/deps/Configure_libcudacxx.cmake +++ /dev/null @@ -1,38 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_libcudacxx version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "libcudacxx") - - include("${rapids-cmake-dir}/cpm/libcudacxx.cmake") - - # Use rapids-cpm to load libcudacxx. This makes an interface library - # libcudacxx::libcudacxx that you can link against. If rapids_cpm_libcudaxx is - # removed, be sure to set `libcudacxx_SOURCE_DIR` since other libraries can - # depend on this variable. Set it in the parent scope to ensure its valid - # See: https://github.com/rapidsai/rapids-cmake/issues/117 - rapids_cpm_libcudacxx( - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - ) - -endfunction() - -find_and_configure_libcudacxx(${LIBCUDACXX_VERSION}) diff --git a/cmake/deps/Configure_prometheus.cmake b/cmake/deps/Configure_prometheus.cmake deleted file mode 100644 index ca65aca6c..000000000 --- a/cmake/deps/Configure_prometheus.cmake +++ /dev/null @@ -1,50 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_prometheus_cpp version) - list(APPEND CMAKE_MESSAGE_CONTEXT "prometheus_cpp") - - rapids_cpm_find(prometheus-cpp ${version} - GLOBAL_TARGETS - prometheus-cpp prometheus-cpp::core - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/jupp0r/prometheus-cpp.git - GIT_TAG "v${version}" - GIT_SHALLOW TRUE - PATCH_COMMAND git checkout -- . && git apply --whitespace=fix ${PROJECT_SOURCE_DIR}/cmake/deps/patches/prometheus_export_fix.patch - OPTIONS "BUILD_SHARED_LIBS OFF" - "ENABLE_PULL OFF" - "ENABLE_PUSH OFF" - "ENABLE_COMPRESSION OFF" - "ENABLE_TESTING OFF" - "USE_THIRDPARTY_LIBRARIES OFF" - "OVERRIDE_CXX_STANDARD_FLAGS OFF" - "THIRDPARTY_CIVETWEB_WITH_SSL OFF" - "GENERATE_PKGCONFIG OFF" - ) - -endfunction() - -find_and_configure_prometheus_cpp(${PROMETHEUS_CPP_VERSION}) -## Manually export prometheus-core. Use this if we don't want to apply the export fix patch. -#add_library(prometheus-cpp-core STATIC IMPORTED) -#set_property(TARGET prometheus-cpp-core PROPERTY -# IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/_deps/prometheus-cpp-build/lib/libprometheus-cpp-core.a") diff --git a/cmake/deps/Configure_pybind11.cmake b/cmake/deps/Configure_pybind11.cmake deleted file mode 100644 index 64919315c..000000000 --- a/cmake/deps/Configure_pybind11.cmake +++ /dev/null @@ -1,40 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_pybind11 version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "pybind11") - - # Needs a patch to change the internal tracker to use fiber specific storage instead of TSS - rapids_cpm_find(pybind11 ${version} - GLOBAL_TARGETS - pybind11 pybind11::pybind11 - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/pybind/pybind11.git - GIT_TAG "v${version}" - GIT_SHALLOW TRUE - PATCH_COMMAND git checkout -- . && git apply --whitespace=fix ${PROJECT_SOURCE_DIR}/cmake/deps/patches/pybind11.patch - OPTIONS "PYBIND11_INSTALL ON" - "PYBIND11_TEST OFF" - ) -endfunction() - -find_and_configure_pybind11(${PYBIND11_VERSION}) diff --git a/cmake/deps/Configure_rxcpp.cmake b/cmake/deps/Configure_rxcpp.cmake deleted file mode 100644 index 66de7a6e5..000000000 --- a/cmake/deps/Configure_rxcpp.cmake +++ /dev/null @@ -1,40 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_rxcpp version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "rxcpp") - - rapids_cpm_find(rxcpp ${version} - GLOBAL_TARGETS - rxcpp rxcpp::rxcpp - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/mdemoret-nv/RxCpp.git # TODO(MDD): Move RxCpp fork to nv-morpheus - GIT_TAG v${version} - GIT_SHALLOW TRUE - OPTIONS "RX_BUILD_TESTING OFF" - "RX_BUILD_EXAMPLES OFF" - "RXCPP_USE_FIBERS ON" - ) - -endfunction() - -find_and_configure_rxcpp(${RXCPP_VERSION}) diff --git a/cmake/deps/Configure_taskflow.cmake b/cmake/deps/Configure_taskflow.cmake deleted file mode 100644 index 119e92e97..000000000 --- a/cmake/deps/Configure_taskflow.cmake +++ /dev/null @@ -1,43 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_taskflow version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "taskflow") - - rapids_cpm_find(taskflow ${version} - GLOBAL_TARGETS - Taskflow Taskflow::Taskflow - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/taskflow/taskflow.git - GIT_TAG "v${version}" - GIT_SHALLOW TRUE - OPTIONS "CMAKE_BUILD_TYPE Release" - "TF_BUILD_TESTS OFF" - "TF_BUILD_EXAMPLES OFF" - ) - - # Add the alias since Taskflow does not - add_library(Taskflow::Taskflow ALIAS Taskflow) - -endfunction() - -find_and_configure_taskflow(${TASKFLOW_VERSION}) diff --git a/cmake/deps/Configure_ucx.cmake b/cmake/deps/Configure_ucx.cmake deleted file mode 100644 index 550999d30..000000000 --- a/cmake/deps/Configure_ucx.cmake +++ /dev/null @@ -1,182 +0,0 @@ -#============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -#============================================================================= - -function(find_and_configure_ucx version) - - list(APPEND CMAKE_MESSAGE_CONTEXT "ucx") - - # Try to find UCX and download from source if not found - rapids_cpm_find(ucx ${version} - GLOBAL_TARGETS - ucx ucx::ucp ucx::uct ucx_ucx ucx::ucp ucx::uct ucx::ucx - BUILD_EXPORT_SET - ${PROJECT_NAME}-core-exports - INSTALL_EXPORT_SET - ${PROJECT_NAME}-core-exports - CPM_ARGS - GIT_REPOSITORY https://github.com/openucx/ucx.git - GIT_TAG "v${version}" - DOWNLOAD_ONLY TRUE - ) - - if (ucx_ADDED) - # If we got here, UCX wasnt found. Add custom targets to build from source. - message(STATUS "UCX Not Found. Building from source.") - - # Location where all files will be temp installed - set(ucx_INSTALL_DIR ${ucx_BINARY_DIR}/install) - - # Because libtool shows an error when calling `make install - # prefix=`. We have to use DESTDIR instead. Make a symbolic - # link to prevent very long names in the include paths - set(ucx_DEST_DIR ${ucx_BINARY_DIR}/install_dest) - - # Ensure the output exists - file(MAKE_DIRECTORY ${ucx_DEST_DIR}/${CMAKE_INSTALL_PREFIX}) - file(CREATE_LINK ${ucx_DEST_DIR}/${CMAKE_INSTALL_PREFIX} ${ucx_INSTALL_DIR} SYMBOLIC) - file(MAKE_DIRECTORY ${ucx_BINARY_DIR}/install) - file(MAKE_DIRECTORY ${ucx_INSTALL_DIR}/include) - - # file(MAKE_DIRECTORY ${ucx_BINARY_DIR}/src) - - include(ExternalProject) - - string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE_UC) - - # Get the Compiler settings to forward onto autoconf - set(COMPILER_SETTINGS - "CXX=${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}" - "CPP=${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER} -E" - "CC=${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}" - "AR=${CMAKE_C_COMPILER_AR}" - "RANLIB=${CMAKE_C_COMPILER_RANLIB}" - "NM=${CMAKE_NM}" - "STRIP=${CMAKE_STRIP}" - "CFLAGS=${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BUILD_TYPE_UC}}" - "CPPFLAGS=${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BUILD_TYPE_UC}}" - "CXXFLAGS=${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BUILD_TYPE_UC}}" - "LDFLAGS=${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_${BUILD_TYPE_UC}}" - ) - - # Use BUILD_IN_SOURCE because UCX cant do out of source builds and CMake sucks at change directory - ExternalProject_Add(ucx - PREFIX ${ucx_BINARY_DIR} - SOURCE_DIR ${ucx_BINARY_DIR} - INSTALL_DIR ${ucx_INSTALL_DIR} - # Copy from CPM cache into the build tree - DOWNLOAD_COMMAND ${CMAKE_COMMAND} -E copy_directory ${ucx_SOURCE_DIR} ${ucx_BINARY_DIR} - # The io_demo fails to build in out of source builds. So remove that from - # the Makefile (wish we could just disable all test/examples/apps) as a - # part of the download command - PATCH_COMMAND git checkout -- . && git apply --whitespace=fix ${PROJECT_SOURCE_DIR}/cmake/deps/patches/ucx.patch - # Note, we set SED and GREP here since they can be hard coded in the conda libtoolize - CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env SED=sed GREP=grep /autogen.sh - COMMAND /contrib/configure-release ${COMPILER_SETTINGS} --prefix=${CMAKE_INSTALL_PREFIX} --enable-mt --without-rdmacm --disable-gtest --disable-examples - BUILD_COMMAND make -j - BUILD_IN_SOURCE TRUE - BUILD_BYPRODUCTS /lib/libuct.a - /lib/libucp.a - /lib/libucs.a - /lib/libucm.a - INSTALL_COMMAND make DESTDIR=${ucx_DEST_DIR} install - LOG_CONFIGURE TRUE - LOG_BUILD TRUE - LOG_INSTALL TRUE - # Add a target for configuring to allow for style checks on source code - STEP_TARGETS install - ) - - # Install only the headers - install( - DIRECTORY ${ucx_INSTALL_DIR}/include - TYPE INCLUDE - ) - - # TODO: We support components in the custom build branch but not when UCX is found via find_package. - # UCT Library - add_library(ucx::uct STATIC IMPORTED GLOBAL) - set_target_properties(ucx::uct PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "$;$" - INTERFACE_POSITION_INDEPENDENT_CODE "ON" - ) - set_property(TARGET ucx::uct APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(ucx::uct PROPERTIES - IMPORTED_LOCATION_RELEASE "${ucx_INSTALL_DIR}/lib/libuct.a" - IMPORTED_SONAME_RELEASE "libuct.a" - ) - add_dependencies(ucx::uct ucx) - - # UCP Library - add_library(ucx::ucp STATIC IMPORTED GLOBAL) - set_target_properties(ucx::ucp PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "$;$" - INTERFACE_POSITION_INDEPENDENT_CODE "ON" - ) - set_property(TARGET ucx::ucp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(ucx::ucp PROPERTIES - IMPORTED_LOCATION_RELEASE "${ucx_INSTALL_DIR}/lib/libucp.a" - IMPORTED_SONAME_RELEASE "libucp.a" - ) - add_dependencies(ucx::ucp ucx) - - # UCS Library - add_library(ucx::ucs STATIC IMPORTED GLOBAL) - set_target_properties(ucx::ucs PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "$;$" - INTERFACE_POSITION_INDEPENDENT_CODE "ON" - ) - set_property(TARGET ucx::ucs APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(ucx::ucs PROPERTIES - IMPORTED_LOCATION_RELEASE "${ucx_INSTALL_DIR}/lib/libucs.a" - IMPORTED_SONAME_RELEASE "libucs.a" - ) - add_dependencies(ucx::ucs ucx) - - # UCM Library - add_library(ucx::ucm STATIC IMPORTED GLOBAL) - set_target_properties(ucx::ucm PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "$;$" - INTERFACE_POSITION_INDEPENDENT_CODE "ON" - ) - set_property(TARGET ucx::ucm APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(ucx::ucm PROPERTIES - IMPORTED_LOCATION_RELEASE "${ucx_INSTALL_DIR}/lib/libucm.a" - IMPORTED_SONAME_RELEASE "libucm.a" - ) - add_dependencies(ucx::ucm ucx) - - # Combined ucx::ucx target - add_library(ucx::ucx INTERFACE IMPORTED) - set_target_properties(ucx::ucx PROPERTIES - INTERFACE_LINK_LIBRARIES "ucx::uct;ucx::ucp;ucx::ucs;ucx::ucm" - ) - - # Finally, add this to the style check dependencies - add_dependencies(${PROJECT_NAME}_style_checks ucx-install) - else() - # Found installed UCX. Make sure to call rapids_export_package without a version. - # Otherwise CMake fails with trying to add the dependency twice - rapids_export_package( - INSTALL ucx ${PROJECT_NAME}-core-exports - GLOBAL_TARGETS ucx ucx::ucp ucx::uct ucx_ucx ucx::ucp ucx::uct ucx::ucx - ) - - endif() - -endfunction() - -find_and_configure_ucx(${UCX_VERSION}) diff --git a/cmake/deps/patches/cpuaff.patch b/cmake/deps/patches/cpuaff.patch deleted file mode 100644 index e4b32c692..000000000 --- a/cmake/deps/patches/cpuaff.patch +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022,NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -diff --git a/Makefile.am b/Makefile.am -index b8051b0..25ef0e5 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -1,2 +1,2 @@ --SUBDIRS = include examples tests -+SUBDIRS = include - TESTS = tests/test diff --git a/cmake/deps/patches/prometheus_export_fix.patch b/cmake/deps/patches/prometheus_export_fix.patch deleted file mode 100644 index 8ff6db71c..000000000 --- a/cmake/deps/patches/prometheus_export_fix.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 4ee6812..3f52d0a 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -121,6 +121,12 @@ endif() - - include(CMakePackageConfigHelpers) - -+export( -+ EXPORT ${PROJECT_NAME}-targets -+ FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}-targets.cmake" -+ NAMESPACE ${PROJECT_NAME}:: -+) -+ - install( - EXPORT ${PROJECT_NAME}-targets - NAMESPACE ${PROJECT_NAME}:: diff --git a/cmake/deps/patches/pybind11.patch b/cmake/deps/patches/pybind11.patch deleted file mode 100644 index 186897119..000000000 --- a/cmake/deps/patches/pybind11.patch +++ /dev/null @@ -1,74 +0,0 @@ -/* - pybind11/detail/type_caster_base.h (originally first part of pybind11/cast.h) - Copyright (c) 2016 Wenzel Jakob - All rights reserved. Use of this source code is governed by a - BSD-style license that can be found in the - LICENSE file https://github.com/pybind/pybind11/blob/master/LICENSE. -*/ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: BSD-3-Clause -# -# 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. -# -# 3. Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# 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. - -diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h -index f804d9d..a579a7f 100644 ---- a/include/pybind11/detail/type_caster_base.h -+++ b/include/pybind11/detail/type_caster_base.h -@@ -25,6 +25,12 @@ - #include - #include - -+#define WITH_FIBERS -+ -+#ifdef WITH_FIBERS -+#include -+#endif -+ - PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) - PYBIND11_NAMESPACE_BEGIN(detail) - -@@ -35,7 +41,20 @@ private: - loader_life_support* parent = nullptr; - std::unordered_set keep_alive; - --#if defined(WITH_THREAD) -+#if defined(WITH_FIBERS) -+ // Store stack pointer in thread-local storage. -+ static boost::fibers::fiber_specific_ptr& get_stack_tls_key() { -+ static boost::fibers::fiber_specific_ptr fiber_stack([](loader_life_support* x){}); -+ return fiber_stack; -+ } -+ static loader_life_support *get_stack_top() { -+ return get_stack_tls_key().get(); -+ } -+ static void set_stack_top(loader_life_support *value) { -+ get_stack_tls_key().reset(value); -+ } -+ -+#elif defined(WITH_THREAD) - // Store stack pointer in thread-local storage. - static PYBIND11_TLS_KEY_REF get_stack_tls_key() { - # if PYBIND11_INTERNALS_VERSION == 4 diff --git a/cmake/deps/patches/ucx.patch b/cmake/deps/patches/ucx.patch deleted file mode 100644 index 2b7449629..000000000 --- a/cmake/deps/patches/ucx.patch +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022,NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -diff --git a/Makefile.am b/Makefile.am -index 073ead3..85f9d01 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -41,15 +41,6 @@ if HAVE_UCG - SUBDIRS += $(UCG_SUBDIR) - endif - --SUBDIRS += \ -- src/tools/vfs \ -- src/tools/info \ -- src/tools/perf \ -- src/tools/profile \ -- bindings/java \ -- test/apps \ -- examples -- - if HAVE_GTEST - SUBDIRS += test/gtest - endif diff --git a/cmake/deps/templates/pkgconfig_package.cmake.in b/cmake/deps/templates/pkgconfig_package.cmake.in deleted file mode 100644 index a3d2991d3..000000000 --- a/cmake/deps/templates/pkgconfig_package.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -#============================================================================= -# pkg-config Search for @name@ -# -find_package(PkgConfig) - -pkg_check_modules(@name@ IMPORTED_TARGET GLOBAL @name@) - -if(@name@_FOUND) - # Add an alias to the imported target - add_library(@name@::@name@ ALIAS PkgConfig::@name@) -endif() - -#============================================================================= diff --git a/cmake/deps/rapids_cpm_package_overrides.json b/cmake/rapids_cpm_package_overrides.json similarity index 100% rename from cmake/deps/rapids_cpm_package_overrides.json rename to cmake/rapids_cpm_package_overrides.json From 78f9ae5a823ea99f815f537578b0155830729fbb Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 29 Nov 2022 16:42:16 -0700 Subject: [PATCH 02/55] Using utils for all package configuration --- cmake/dependencies.cmake | 2 +- cmake/python_module_tools.cmake | 2 +- cmake/setup_coverage.cmake | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 7df0d9936..01f0d6ad6 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -16,7 +16,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "dep") # Initialize rapids CPM with package overrides -rapids_cpm_init(OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/deps/rapids_cpm_package_overrides.json") +rapids_cpm_init(OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") # Print CMake settings when verbose output is enabled message(VERBOSE "PROJECT_NAME: " ${PROJECT_NAME}) diff --git a/cmake/python_module_tools.cmake b/cmake/python_module_tools.cmake index 8f20aee5e..b15f0da2a 100644 --- a/cmake/python_module_tools.cmake +++ b/cmake/python_module_tools.cmake @@ -56,7 +56,7 @@ message(VERBOSE "Python3_NumPy_VERSION: " ${Python3_NumPy_VERSION}) # pybind11 # ========= set(PYBIND11_VERSION "2.8.1" CACHE STRING "Version of Pybind11 to use") -include(deps/Configure_pybind11) +include(${MORPHEUS_UTILS_HOME}/cmake/package_config/pybind11/Configure_pybind11.cmake) if (NOT EXISTS ${Python3_SITELIB}/skbuild) # In case this is messed up by `/usr/local/python/site-packages` vs `/usr/python/site-packages`, check pip itself. diff --git a/cmake/setup_coverage.cmake b/cmake/setup_coverage.cmake index 03a05dfee..46f26c87b 100644 --- a/cmake/setup_coverage.cmake +++ b/cmake/setup_coverage.cmake @@ -22,7 +22,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "coverage") # Include coverage tools if enabled if(MRC_ENABLE_CODECOV) - include(cmake/deps/Configure_gcov.cmake) + include(${MORPHEUS_UTILS_HOME}/cmake/environment_config/gcov/setup.cmake) message(STATUS "MRC_ENABLE_CODECOV is ON, configuring report exclusions and setting up coverage build targets") set(CODECOV_REPORT_EXCLUSIONS From 585b1440990f39476c1b3ad55643ef09ca71b0b3 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 29 Nov 2022 16:47:06 -0700 Subject: [PATCH 03/55] Checkpoint --- CMakeLists.txt | 6 +++--- cmake/{ => environment}/setup_cache.cmake | 0 cmake/{ => environment}/setup_compiler.cmake | 0 cmake/{ => environment}/setup_coverage.cmake | 0 cmake/{ => environment}/setup_iwyu.cmake | 0 cmake/{ => environment}/setup_package_manager.cmake | 0 6 files changed, 3 insertions(+), 3 deletions(-) rename cmake/{ => environment}/setup_cache.cmake (100%) rename cmake/{ => environment}/setup_compiler.cmake (100%) rename cmake/{ => environment}/setup_coverage.cmake (100%) rename cmake/{ => environment}/setup_iwyu.cmake (100%) rename cmake/{ => environment}/setup_package_manager.cmake (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a947a0322..cafb9848a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,12 +42,12 @@ mark_as_advanced(MRC_CACHE_DIR) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -include(cmake/setup_package_manager.cmake) +include(environment/setup_package_manager) enable_testing() # Add the RAPIDS cmake helper scripts -include(cmake/import_rapids_cmake.cmake) +include(environment/setup_rapids_cmake) # Default to using "NATIVE" for CUDA_ARCHITECTURES to build based on GPU in system if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) @@ -101,7 +101,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Setup cache before dependencies -include(cmake/setup_cache.cmake) +include(environment/setup_cache) # Configure conda if(MRC_USE_CONDA AND DEFINED ENV{CONDA_PREFIX}) diff --git a/cmake/setup_cache.cmake b/cmake/environment/setup_cache.cmake similarity index 100% rename from cmake/setup_cache.cmake rename to cmake/environment/setup_cache.cmake diff --git a/cmake/setup_compiler.cmake b/cmake/environment/setup_compiler.cmake similarity index 100% rename from cmake/setup_compiler.cmake rename to cmake/environment/setup_compiler.cmake diff --git a/cmake/setup_coverage.cmake b/cmake/environment/setup_coverage.cmake similarity index 100% rename from cmake/setup_coverage.cmake rename to cmake/environment/setup_coverage.cmake diff --git a/cmake/setup_iwyu.cmake b/cmake/environment/setup_iwyu.cmake similarity index 100% rename from cmake/setup_iwyu.cmake rename to cmake/environment/setup_iwyu.cmake diff --git a/cmake/setup_package_manager.cmake b/cmake/environment/setup_package_manager.cmake similarity index 100% rename from cmake/setup_package_manager.cmake rename to cmake/environment/setup_package_manager.cmake From 91454bbb24a45228fe6513e5b12ca4882c75b84c Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 29 Nov 2022 16:55:57 -0700 Subject: [PATCH 04/55] Start isolating template files and environment setup --- CMakeLists.txt | 6 +++--- cmake/environment/setup_cache.cmake | 6 +++--- cmake/environment/setup_iwyu.cmake | 2 +- .../setup_rapids_cmake.cmake} | 0 cmake/{ => templates}/run_ccache.sh.in | 0 cmake/{ => templates}/run_ccache_prefix.sh.in | 0 cmake/{ => templates}/run_iwyu.sh.in | 0 docs/quickstart/CMakeLists.txt | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename cmake/{import_rapids_cmake.cmake => environment/setup_rapids_cmake.cmake} (100%) rename cmake/{ => templates}/run_ccache.sh.in (100%) rename cmake/{ => templates}/run_ccache_prefix.sh.in (100%) rename cmake/{ => templates}/run_iwyu.sh.in (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index cafb9848a..6eb1388d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,13 +136,13 @@ add_subdirectory(protos) # ################################### # - Post dependencies setup -------- -include(cmake/setup_compiler.cmake) +include(environment/setup_compiler) # Setup code coverage components -include(cmake/setup_coverage.cmake) +include(environment/setup_coverage) # Setup IWYU if enabled -include(cmake/setup_iwyu.cmake) +include(environment/setup_iwyu) # ################################### # - Begin MRC Targets -------------- diff --git a/cmake/environment/setup_cache.cmake b/cmake/environment/setup_cache.cmake index d3c914a95..0e658e9ee 100644 --- a/cmake/environment/setup_cache.cmake +++ b/cmake/environment/setup_cache.cmake @@ -66,7 +66,7 @@ function(configure_ccache cache_dir_name) set(CCACHE_COMPILERTYPE "auto") endif() - configure_file("${LOCAL_MODULES_PATH}/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_c.sh" @ONLY) + configure_file("${LOCAL_MODULES_PATH}/templates/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_c.sh" @ONLY) # Configure ccache for CXX if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") @@ -77,11 +77,11 @@ function(configure_ccache cache_dir_name) set(CCACHE_COMPILERTYPE "auto") endif() - configure_file("${LOCAL_MODULES_PATH}/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cxx.sh" @ONLY) + configure_file("${LOCAL_MODULES_PATH}/templates/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cxx.sh" @ONLY) # Configure ccache for CUDA set(CCACHE_COMPILERTYPE "nvcc") - configure_file("${LOCAL_MODULES_PATH}/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cuda.sh" @ONLY) + configure_file("${LOCAL_MODULES_PATH}/templates/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cuda.sh" @ONLY) # Finally, set the compiler option set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_c.sh" PARENT_SCOPE) diff --git a/cmake/environment/setup_iwyu.cmake b/cmake/environment/setup_iwyu.cmake index bc98d3f24..a1a786bb6 100644 --- a/cmake/environment/setup_iwyu.cmake +++ b/cmake/environment/setup_iwyu.cmake @@ -40,7 +40,7 @@ function(configure_iwyu) set(IWYU_WRAPPER "${CMAKE_CURRENT_BINARY_DIR}/run_iwyu.sh") # Make a ccache runner file with the necessary settings. MRC_CCACHE_OPTIONS must be set! - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/run_iwyu.sh.in" "${IWYU_WRAPPER}") + configure_file("${LOCAL_MODULES_PATH}/templates/run_iwyu.sh.in" "${IWYU_WRAPPER}") if(MRC_USE_CCACHE) set(CMAKE_C_INCLUDE_WHAT_YOU_USE "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_prefix.sh;${IWYU_WRAPPER};${CMAKE_C_COMPILER}" PARENT_SCOPE) diff --git a/cmake/import_rapids_cmake.cmake b/cmake/environment/setup_rapids_cmake.cmake similarity index 100% rename from cmake/import_rapids_cmake.cmake rename to cmake/environment/setup_rapids_cmake.cmake diff --git a/cmake/run_ccache.sh.in b/cmake/templates/run_ccache.sh.in similarity index 100% rename from cmake/run_ccache.sh.in rename to cmake/templates/run_ccache.sh.in diff --git a/cmake/run_ccache_prefix.sh.in b/cmake/templates/run_ccache_prefix.sh.in similarity index 100% rename from cmake/run_ccache_prefix.sh.in rename to cmake/templates/run_ccache_prefix.sh.in diff --git a/cmake/run_iwyu.sh.in b/cmake/templates/run_iwyu.sh.in similarity index 100% rename from cmake/run_iwyu.sh.in rename to cmake/templates/run_iwyu.sh.in diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index 1fc479d06..52d02b0ca 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -22,7 +22,7 @@ list(PREPEND CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}") list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake") # Add the RAPIDS cmake helper scripts -include(import_rapids_cmake) +include(environment/setup_rapids_cmake) project(mrc-quickstart VERSION 22.11.00 From 6fea69306ca5296c7100be2cc0d48fa3bacc2b88 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 29 Nov 2022 17:00:23 -0700 Subject: [PATCH 05/55] Updates and remove unused files --- cmake/Configure_morpheus_utils.cmake | 3 +- cmake/FindIBVerbs.cmake | 62 -------------------- cmake/FindTensorRT.cmake | 87 ---------------------------- cmake/FindTriton.cmake | 61 ------------------- 4 files changed, 2 insertions(+), 211 deletions(-) delete mode 100644 cmake/FindIBVerbs.cmake delete mode 100644 cmake/FindTensorRT.cmake delete mode 100644 cmake/FindTriton.cmake diff --git a/cmake/Configure_morpheus_utils.cmake b/cmake/Configure_morpheus_utils.cmake index ad267d13b..93a081078 100644 --- a/cmake/Configure_morpheus_utils.cmake +++ b/cmake/Configure_morpheus_utils.cmake @@ -18,9 +18,10 @@ function(find_and_configure_morpheus_utils version) list(APPEND CMAKE_MESSAGE_CONTEXT "morpheus_utils") + # TODO(Devin): Make this an ExternalProject so we don't have any rapids/rpm deps and can pull earlier. rapids_cpm_find(morpheus_utils ${version} CPM_ARGS - #GIT_REPOSITORY https://github.com/ryanolson/expected.git + #GIT_REPOSITORY https://github.com/nv-morpheus/utilities.git GIT_REPOSITORY /home/drobison/Development/devin-morpheus-utils-public GIT_TAG v${version} DOWNLOAD_ONLY TRUE diff --git a/cmake/FindIBVerbs.cmake b/cmake/FindIBVerbs.cmake deleted file mode 100644 index 88a5a92da..000000000 --- a/cmake/FindIBVerbs.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022,NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Find the ibverbs libraries -# -# The following variables are optionally searched for defaults -# IBVERBS_ROOT_DIR: Base directory where all ibverbs components are found -# IBVERBS_INCLUDE_DIR: Directory where ibverbs headers are found -# IBVERBS_LIB_DIR: Directory where ibverbs libraries are found - -# The following are set after configuration is done: -# IBVERBS_FOUND -# IBVERBS_INCLUDE_DIRS -# IBVERBS_LIBRARIES - -# - Find rdma verbs -# Find the rdma verbs library and includes -# -# VERBS_INCLUDE_DIR - where to find ibverbs.h, etc. -# VERBS_LIBRARIES - List of libraries when using ibverbs. -# VERBS_FOUND - True if ibverbs found. -# HAVE_IBV_EXP - True if experimental verbs is enabled. - -find_path(VERBS_INCLUDE_DIR infiniband/verbs.h) -find_library(VERBS_LIBRARIES ibverbs HINTS /usr/lib) -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(verbs DEFAULT_MSG VERBS_LIBRARIES VERBS_INCLUDE_DIR) - -if(VERBS_FOUND) - include(CheckCXXSourceCompiles) - CHECK_CXX_SOURCE_COMPILES(" - #include - int main() { - struct ibv_context* ctxt; - struct ibv_exp_gid_attr gid_attr; - ibv_exp_query_gid_attr(ctxt, 1, 0, &gid_attr); - return 0; - } " HAVE_IBV_EXP) - if(NOT TARGET IBVerbs::verbs) - add_library(IBVerbs::verbs UNKNOWN IMPORTED) - endif() - set_target_properties(IBVerbs::verbs PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${VERBS_INCLUDE_DIR}" - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${VERBS_LIBRARIES}") -endif() - -mark_as_advanced( - VERBS_LIBRARIES -) diff --git a/cmake/FindTensorRT.cmake b/cmake/FindTensorRT.cmake deleted file mode 100644 index 2cbfd6071..000000000 --- a/cmake/FindTensorRT.cmake +++ /dev/null @@ -1,87 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2018-2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# This module defines the following variables: -# -# :: -# -# TensorRT_INCLUDE_DIRS -# TensorRT_LIBRARIES -# TensorRT_FOUND -# -# :: -# -# TensorRT_VERSION_STRING - version (x.y.z) -# TensorRT_VERSION_MAJOR - major version (x) -# TensorRT_VERSION_MINOR - minor version (y) -# TensorRT_VERSION_PATCH - patch version (z) -# -# Hints -# ^^^^^ -# A user may set ``TensorRT_ROOT`` to an installation root to tell this module where to look. -# -set(_TensorRT_SEARCHES) - -if(TensorRT_ROOT) - set(_TensorRT_SEARCH_ROOT PATHS ${TensorRT_ROOT} NO_DEFAULT_PATH) - list(APPEND _TensorRT_SEARCHES _TensorRT_SEARCH_ROOT) -endif() - -# appends some common paths -set(_TensorRT_SEARCH_NORMAL - PATHS "/usr" -) -list(APPEND _TensorRT_SEARCHES _TensorRT_SEARCH_NORMAL) - -# Include dir -foreach(search ${_TensorRT_SEARCHES}) - find_path(TensorRT_INCLUDE_DIR NAMES NvInfer.h ${${search}} PATH_SUFFIXES include) -endforeach() - -if(NOT TensorRT_LIBRARY) - foreach(search ${_TensorRT_SEARCHES}) - find_library(TensorRT_LIBRARY NAMES nvinfer ${${search}} PATH_SUFFIXES lib) - endforeach() -endif() - -mark_as_advanced(TensorRT_INCLUDE_DIR) - -if(TensorRT_INCLUDE_DIR AND EXISTS "${TensorRT_INCLUDE_DIR}/NvInfer.h") - file(STRINGS "${TensorRT_INCLUDE_DIR}/NvInfer.h" TensorRT_MAJOR REGEX "^#define NV_TENSORRT_MAJOR [0-9]+.*$") - file(STRINGS "${TensorRT_INCLUDE_DIR}/NvInfer.h" TensorRT_MINOR REGEX "^#define NV_TENSORRT_MINOR [0-9]+.*$") - file(STRINGS "${TensorRT_INCLUDE_DIR}/NvInfer.h" TensorRT_PATCH REGEX "^#define NV_TENSORRT_PATCH [0-9]+.*$") - - string(REGEX REPLACE "^#define NV_TENSORRT_MAJOR ([0-9]+).*$" "\\1" TensorRT_VERSION_MAJOR "${TensorRT_MAJOR}") - string(REGEX REPLACE "^#define NV_TENSORRT_MINOR ([0-9]+).*$" "\\1" TensorRT_VERSION_MINOR "${TensorRT_MINOR}") - string(REGEX REPLACE "^#define NV_TENSORRT_PATCH ([0-9]+).*$" "\\1" TensorRT_VERSION_PATCH "${TensorRT_PATCH}") - set(TensorRT_VERSION_STRING "${TensorRT_VERSION_MAJOR}.${TensorRT_VERSION_MINOR}.${TensorRT_VERSION_PATCH}") -endif() - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(TensorRT REQUIRED_VARS TensorRT_LIBRARY TensorRT_INCLUDE_DIR VERSION_VAR TensorRT_VERSION_STRING) - -if(TensorRT_FOUND) - set(TensorRT_INCLUDE_DIRS ${TensorRT_INCLUDE_DIR}) - - if(NOT TensorRT_LIBRARIES) - set(TensorRT_LIBRARIES ${TensorRT_LIBRARY}) - endif() - - if(NOT TARGET TensorRT::TensorRT) - add_library(TensorRT::TensorRT UNKNOWN IMPORTED) - set_target_properties(TensorRT::TensorRT PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${TensorRT_INCLUDE_DIRS}") - set_property(TARGET TensorRT::TensorRT APPEND PROPERTY IMPORTED_LOCATION "${TensorRT_LIBRARY}") - endif() -endif() diff --git a/cmake/FindTriton.cmake b/cmake/FindTriton.cmake deleted file mode 100644 index 21dd4009d..000000000 --- a/cmake/FindTriton.cmake +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022,NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Find Triton libraries -# -# The following variables are optionally searched for defaults -# TRITON_ROOT_DIR: Base directory where all ibverbs components are found -# TRITON_INCLUDE_DIR: Directory where ibverbs headers are found -# TRITON_LIB_DIR: Directory where ibverbs libraries are found - -# The following are set after configuration is done: -# TRITON_FOUND -# TRITON_INCLUDE_DIRS -# TRITON_LIBRARIES - -# - Find Triton -# Find the Triton library and includes -# -# TRITON_INCLUDE_DIR - where to find headers -# TRITON_LIBRARIES - List of libraries when using triton. -# TRITON_FOUND - True if libtritonserver.so found. - -find_path(TRITON_INCLUDE_DIR triton/core/tritonserver.h HINTS /opt/tritonserver/include) -find_library(TRITON_LIBRARIES libtritonserver.so HINTS /opt/tritonserver/lib) -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Triton DEFAULT_MSG TRITON_LIBRARIES TRITON_INCLUDE_DIR) - -if(TRITON_FOUND) -# include(CheckCXXSourceCompiles) -# CHECK_CXX_SOURCE_COMPILES(" -# #include -# int main() { -# struct ibv_context* ctxt; -# struct ibv_exp_gid_attr gid_attr; -# ibv_exp_query_gid_attr(ctxt, 1, 0, &gid_attr); -# return 0; -# } " HAVE_IBV_EXP) - if(NOT TARGET Triton::libtriton) - add_library(Triton::libtriton UNKNOWN IMPORTED) - endif() - set_target_properties(Triton::libtriton PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${TRITON_INCLUDE_DIR}" - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${TRITON_LIBRARIES}") -endif() - -mark_as_advanced( - TRITON_LIBRARIES -) From 2ee3dca059cfbcfc7538f246851dc3575e1c73a1 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 29 Nov 2022 17:03:10 -0700 Subject: [PATCH 06/55] Path changes --- cmake/environment/setup_coverage.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/environment/setup_coverage.cmake b/cmake/environment/setup_coverage.cmake index 46f26c87b..c0e39123e 100644 --- a/cmake/environment/setup_coverage.cmake +++ b/cmake/environment/setup_coverage.cmake @@ -22,7 +22,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "coverage") # Include coverage tools if enabled if(MRC_ENABLE_CODECOV) - include(${MORPHEUS_UTILS_HOME}/cmake/environment_config/gcov/setup.cmake) + include(${MORPHEUS_UTILS_HOME}/cmake/source/utils/code_coverage/setup.cmake) message(STATUS "MRC_ENABLE_CODECOV is ON, configuring report exclusions and setting up coverage build targets") set(CODECOV_REPORT_EXCLUSIONS From af70c8ddd7bd9cd421a97e7f68c58a30520fc7bf Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Wed, 30 Nov 2022 15:48:44 -0700 Subject: [PATCH 07/55] Checkpoint --- CMakeLists.txt | 32 ++++-- cmake/Configure_morpheus_utils.cmake | 34 +++++- cmake/dependencies.cmake | 40 +++---- cmake/environment/setup_cache.cmake | 1 + cmake/environment/setup_coverage.cmake | 2 +- cmake/environment/setup_package_manager.cmake | 101 ------------------ cmake/environment/setup_rapids_cmake.cmake | 38 ------- cmake/python_module_tools.cmake | 3 +- cmake/{ => templates}/ccache.conf.in | 0 docs/quickstart/CMakeLists.txt | 3 +- 10 files changed, 71 insertions(+), 183 deletions(-) delete mode 100644 cmake/environment/setup_package_manager.cmake delete mode 100644 cmake/environment/setup_rapids_cmake.cmake rename cmake/{ => templates}/ccache.conf.in (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eb1388d1..7d92d492d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,12 +42,30 @@ mark_as_advanced(MRC_CACHE_DIR) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -include(environment/setup_package_manager) enable_testing() -# Add the RAPIDS cmake helper scripts -include(environment/setup_rapids_cmake) +# Load morpheus utils and update CMake paths +set(MORPHEUS_UTILS_VERSION "0.1" CACHE STRING "Version of Morpheus utils") +include(Configure_morpheus_utils) +find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) +list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") + +# Conda vs Vcpkg configuration helpers +include(morpheus_utils/environment_config/package_manager/setup) +# RAPIDS CMake helpers +include(morpheus_utils/environment_config/rapids_cmake/setup) + + +# Configure rapids CMake +morpheus_utils_configure_rapids_cmake(MRC_RAPIDS_VERSION) + +# Configure project package manager +morpheus_utils_configure_package_manager( + MRC_USE_CONDA + MRC_VCPKG_TOOLCHAIN + MRC_VCPKG_DEFAULT_BINARY_CACHE + ) # Default to using "NATIVE" for CUDA_ARCHITECTURES to build based on GPU in system if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) @@ -58,9 +76,9 @@ endif() rapids_cuda_init_architectures(mrc) project(mrc - VERSION 22.11.00 - LANGUAGES C CXX -) + VERSION 22.11.00 + LANGUAGES C CXX + ) rapids_cmake_write_version_file(${CMAKE_BINARY_DIR}/autogenerated/include/mrc/version.hpp) @@ -101,7 +119,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Setup cache before dependencies -include(environment/setup_cache) +include(morpheus_utils/environment_config/ccache/setup) # Configure conda if(MRC_USE_CONDA AND DEFINED ENV{CONDA_PREFIX}) diff --git a/cmake/Configure_morpheus_utils.cmake b/cmake/Configure_morpheus_utils.cmake index 93a081078..505be66cd 100644 --- a/cmake/Configure_morpheus_utils.cmake +++ b/cmake/Configure_morpheus_utils.cmake @@ -15,19 +15,43 @@ # limitations under the License. # ============================================================================= +include_guard() +include(FetchContent) + +function(setup_package_tests TEST_VAR_NAME) + set(TEST_VAR_VALUE ${${TEST_VAR_NAME}}) + if (TEST_VAR_VALUE) + message(STATUS "++++++++++++++ TEST_VAR IS ON '${TEST_VAR_VALUE}'") + else() + message(STATUS "++++++++++++++ TEST_VAR IS OFF '${TEST_VAR_VALUE}'") + endif() + message(STATUS "====================> CALLED '${TEST_VAR_NAME}'") + set(test_thing "a b c") + message(STATUS ${test_thing}) +endfunction() + +# Fetch morpheus utilities -- don't use CPM, RAPIDS_CPM, or other external libraries here so +# we are only relying on CMake to get our core utilities. function(find_and_configure_morpheus_utils version) list(APPEND CMAKE_MESSAGE_CONTEXT "morpheus_utils") - # TODO(Devin): Make this an ExternalProject so we don't have any rapids/rpm deps and can pull earlier. - rapids_cpm_find(morpheus_utils ${version} - CPM_ARGS - #GIT_REPOSITORY https://github.com/nv-morpheus/utilities.git + set(fetchcontent_tmp "${FETCHCONTENT_BASE_DIR}") + set(FETCHCONTENT_BASE_DIR "${CMAKE_SOURCE_DIR}/.cache") # default location + if (${CPM_SOURCE_CACHE}) + set(FETCHCONTENT_BASE_DIR "${CPM_SOURCE_CACHE}") + endif() + + FetchContent_Declare( + morpheus_utils GIT_REPOSITORY /home/drobison/Development/devin-morpheus-utils-public GIT_TAG v${version} - DOWNLOAD_ONLY TRUE + GIT_SHALLOW TRUE ) + FetchContent_MakeAvailable(morpheus_utils) + set(FETCHCONTENT_BASE_DIR "${fetchcontent_tmp}") set(MORPHEUS_UTILS_HOME "${morpheus_utils_SOURCE_DIR}" CACHE INTERNAL "Morpheus utils home") + list(POP_BACK CMAKE_MESSAGE_CONTEXT) endfunction() find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 01f0d6ad6..278c13b4c 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -53,47 +53,34 @@ rapids_find_package(CUDAToolkit INSTALL_EXPORT_SET ${PROJECT_NAME}-core-exports ) -set(MORPHEUS_UTILS_VERSION "0.1" CACHE STRING "Version of morphues utils") -include(Configure_morpheus_utils) - -list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") -list(APPEND CMAKE_PREFIX_PATH "${MORPHEUS_UTILS_HOME}/cmake") +# Import morpheus_utils package configuration API +include(morpheus_utils/package_config/api) # Boost # ===== # - Use static linking to avoid issues with system-wide installations of Boost. # - Use numa=on to ensure the numa component of fiber gets built set(BOOST_VERSION "1.74.0" CACHE STRING "Version of boost to use") -include(package_config/boost/Configure_boost) +morpheus_utils_configure_boost_boost_cmake(${BOOST_VERSION}) # UCX # === set(UCX_VERSION "1.13" CACHE STRING "Version of ucx to use") -include(package_config/ucx/Configure_ucx) +morpheus_utils_configure_ucx(${UCX_VERSION}) # hwloc # ===== set(HWLOC_VERSION "2.5" CACHE STRING "Version of hwloc to use") -include(package_config/hwloc/Configure_hwloc) +morpheus_utils_configure_hwloc(${HWLOC_VERSION}) # expected set(EXPECTED_VERSION "1.0.0" CACHE STRING "Version of expected to use") -include(package_config/expected/Configure_expected) - -# FlatBuffers -# =========== -# rapids_find_package(Flatbuffers REQUIRED -# GLOBAL_TARGETS Flatbuffers -# BUILD_EXPORT_SET ${PROJECT_NAME}-core-exports -# INSTALL_EXPORT_SET ${PROJECT_NAME}-core-exports -# FIND_ARGS -# CONFIG -# ) +morpheus_utils_configure_tl_expected(${EXPECTED_VERSION}) # NVIDIA RAPIDS RMM # ================= -set(RMM_VERSION "\${MRC_RAPIDS_VERSION}" CACHE STRING "Version of RMM to use. Defaults to \${MRC_RAPIDS_VERSION}") -include(package_config/rmm/Configure_rmm) +set(RMM_VERSION "${MRC_RAPIDS_VERSION}" CACHE STRING "Version of RMM to use. Defaults to \${MRC_RAPIDS_VERSION}") +morpheus_utils_configure_rmm(${RMM_VERSION}) # gflags # ====== @@ -101,9 +88,6 @@ rapids_find_package(gflags REQUIRED GLOBAL_TARGETS gflags BUILD_EXPORT_SET ${PROJECT_NAME}-core-exports INSTALL_EXPORT_SET ${PROJECT_NAME}-core-exports - - # FIND_ARGS - # CONFIG ) # glog @@ -111,7 +95,7 @@ rapids_find_package(gflags REQUIRED # - link against shared # - todo: compile with -DWITH_GFLAGS=OFF and remove gflags dependency set(GLOG_VERSION "0.6" CACHE STRING "Version of glog to use") -include(package_config/glog/Configure_glog) +morpheus_utils_configure_glog(${GLOG_VERSION}) # nvidia cub # ========== @@ -134,7 +118,7 @@ rapids_find_package(gRPC REQUIRED # RxCpp # ===== set(RXCPP_VERSION "4.1.1.2" CACHE STRING "Version of RxCpp to use") -include(package_config/rxcpp/Configure_rxcpp) +morpheus_utils_configure_rxcpp(${RXCPP_VERSION}) # JSON # ====== @@ -149,12 +133,12 @@ rapids_find_package(nlohmann_json REQUIRED # prometheus # ========= set(PROMETHEUS_CPP_VERSION "1.0.0" CACHE STRING "Version of Prometheus-cpp to use") -include(package_config/prometheus/Configure_prometheus) +morpheus_utils_configure_prometheus_cpp(${PROMETHEUS_CPP_VERSION}) # libcudacxx # ========= set(LIBCUDACXX_VERSION "1.8.0" CACHE STRING "Version of libcudacxx to use") -include(package_config/libcudacxx/Configure_libcudacxx) +morpheus_utils_configure_libcudacxx(${LIBCUDACXX_VERSION}) if(MRC_BUILD_BENCHMARKS) # google benchmark diff --git a/cmake/environment/setup_cache.cmake b/cmake/environment/setup_cache.cmake index 0e658e9ee..b21365f92 100644 --- a/cmake/environment/setup_cache.cmake +++ b/cmake/environment/setup_cache.cmake @@ -18,6 +18,7 @@ # ###################################################################################################################### # * CMake properties ------------------------------------------------------------------------------ +include_guard() list(APPEND CMAKE_MESSAGE_CONTEXT "cache") function(configure_ccache cache_dir_name) diff --git a/cmake/environment/setup_coverage.cmake b/cmake/environment/setup_coverage.cmake index c0e39123e..14ac68b8e 100644 --- a/cmake/environment/setup_coverage.cmake +++ b/cmake/environment/setup_coverage.cmake @@ -22,7 +22,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "coverage") # Include coverage tools if enabled if(MRC_ENABLE_CODECOV) - include(${MORPHEUS_UTILS_HOME}/cmake/source/utils/code_coverage/setup.cmake) + include(morpheus_utils/source/utils/code_coverage/setup) message(STATUS "MRC_ENABLE_CODECOV is ON, configuring report exclusions and setting up coverage build targets") set(CODECOV_REPORT_EXCLUSIONS diff --git a/cmake/environment/setup_package_manager.cmake b/cmake/environment/setup_package_manager.cmake deleted file mode 100644 index 01ef4fdad..000000000 --- a/cmake/environment/setup_package_manager.cmake +++ /dev/null @@ -1,101 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Determine if we should use Vcpkg or Conda for dependencies -if(MRC_USE_CONDA) - # Using conda path. Check for conda environment - if(NOT DEFINED ENV{CONDA_PREFIX}) - message(WARNING "Option 'MRC_USE_CONDA' is set to ON but no conda environment detected! Ensure you have called `conda activate` before configuring. Third party dependencies are likely to not be found.") - else() - message(STATUS "Conda environment detected at '$ENV{CONDA_PREFIX}'. Skipping Vcpkg") - endif() - - # # Strip any CUDA includes in the CXX_FLAGS and rely on find_package(CUDAToolkit). The conda package nvcc_linux-64 sets - # # this which causes compilation errors/warnings due to the order of includes being incorrect - # string(REPLACE "/" "\\/" match_cuda_home "-(I|isystem) *$ENV{CUDA_HOME}/include") - - # message(VERBOSE "match_cuda_home: ${match_cuda_home}") - - # if(CMAKE_C_FLAGS AND "${CMAKE_C_FLAGS}" MATCHES "${match_cuda_home}") - # string(REGEX REPLACE "${match_cuda_home}" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) - # message(VERBOSE "Removing CUDA path from $CMAKE_C_FLAGS") - # endif() - - # if(CMAKE_CXX_FLAGS AND "${CMAKE_CXX_FLAGS}" MATCHES "${match_cuda_home}") - # string(REGEX REPLACE "${match_cuda_home}" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) - # message(VERBOSE "Removing CUDA path from $CMAKE_CXX_FLAGS") - # endif() - - # if(CMAKE_CUDA_FLAGS AND "${CMAKE_CUDA_FLAGS}" MATCHES "${match_cuda_home}") - # string(REGEX REPLACE "${match_cuda_home}" "" CMAKE_CUDA_FLAGS ${CMAKE_CUDA_FLAGS}) - # message(VERBOSE "Removing CUDA path from $CMAKE_CUDA_FLAGS") - # endif() - - # Disable vcpkg toolchain option (in case the user has switched between the two) - unset(MRC_VCPKG_TOOLCHAIN CACHE) -else() - # Use Vcpkg if variable is set. Must be done before first call to project()! - # This will automatically install all dependencies in vcpkg.json - if(NOT DEFINED CACHE{MRC_VCPKG_TOOLCHAIN}) - # First run, set this to prevent entering this on a second run - set(MRC_VCPKG_TOOLCHAIN "" CACHE INTERNAL "Vcpkg Toolchain file to load at startup") - - # Check firs to see if Vcpkg is defined/configured - if(DEFINED ENV{VCPKG_ROOT}) - if(NOT EXISTS "$ENV{VCPKG_ROOT}") - message(FATAL_ERROR "Vcpkg env 'VCPKG_ROOT' set to '$ENV{VCPKG_ROOT}' but file does not exist! Exiting...") - return() - endif() - - # Set the toolchain file to run - set(MRC_VCPKG_TOOLCHAIN "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE INTERNAL "") - - # Default Vcpkg cache to - set(MRC_VCPKG_DEFAULT_BINARY_CACHE "${MRC_CACHE_DIR}/vcpkg" CACHE PATH "The location to use for storing Vcpkg binaries between builds. Defaults to environment variable \$VCPKG_DEFAULT_BINARY_CACHE") - mark_as_advanced(MRC_VCPKG_DEFAULT_BINARY_CACHE) - - # If using shared libs (the default) use a custom triplet file to use dynamic linking - if(BUILD_SHARED_LIBS) - set(VCPKG_OVERLAY_TRIPLETS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/vcpkg_triplets") - set(VCPKG_TARGET_TRIPLET "x64-linux-dynamic") - endif() - else() - # No Vcpkg. Still continue, but show warning - message(WARNING "Option 'MRC_USE_CONDA' is set to OFF but no 'VCPKG_ROOT' environment set has been detected. When using Vcpkg, either the environment variable 'VCPKG_ROOT' should be set, or 'CMAKE_TOOLCHAIN_FILE' should be specified. Third party dependencies are likely to not be found.") - endif() - endif() - - # Check if we have a toolchain file to apply - if(EXISTS "${MRC_VCPKG_TOOLCHAIN}") - # Make sure we keep any value set by the user environment - if(DEFINED ENV{VCPKG_DEFAULT_BINARY_CACHE}) - set(MRC_VCPKG_DEFAULT_BINARY_CACHE "$ENV{VCPKG_DEFAULT_BINARY_CACHE}" CACHE INTERNAL "The location to use for storing Vcpkg binaries between builds") - endif() - - # Now set the environment variable before loading the vcpkg stuff - set(ENV{VCPKG_DEFAULT_BINARY_CACHE} "${MRC_VCPKG_DEFAULT_BINARY_CACHE}") - - # Ensure the cache exists - if(DEFINED ENV{VCPKG_DEFAULT_BINARY_CACHE} AND NOT EXISTS "$ENV{VCPKG_DEFAULT_BINARY_CACHE}") - message(STATUS "Vcpkg binary cache missing. Creating directory. Cache location: $ENV{VCPKG_DEFAULT_BINARY_CACHE}") - file(MAKE_DIRECTORY "$ENV{VCPKG_DEFAULT_BINARY_CACHE}") - else() - message(STATUS "Vcpkg binary cache found. Cache location: $ENV{VCPKG_DEFAULT_BINARY_CACHE}") - endif() - - # Load the toolchain - include("${MRC_VCPKG_TOOLCHAIN}") - endif() -endif() diff --git a/cmake/environment/setup_rapids_cmake.cmake b/cmake/environment/setup_rapids_cmake.cmake deleted file mode 100644 index f6a5b8ed8..000000000 --- a/cmake/environment/setup_rapids_cmake.cmake +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Ensure this is only run once -include_guard(GLOBAL) - -set(RAPIDS_CMAKE_VERSION "${MRC_RAPIDS_VERSION}" CACHE STRING "Version of rapids-cmake to use") - -# Download and load the repo according to the rapids-cmake instructions if it does not exist -if(NOT EXISTS ${CMAKE_BINARY_DIR}/RAPIDS_CMAKE.cmake) - message(STATUS "Downloading RAPIDS CMake Version: ${RAPIDS_CMAKE_VERSION}") - file( - DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-${RAPIDS_CMAKE_VERSION}/RAPIDS.cmake - ${CMAKE_BINARY_DIR}/RAPIDS_CMAKE.cmake - ) -endif() - -# Now load the file -include(${CMAKE_BINARY_DIR}/RAPIDS_CMAKE.cmake) - -# Load Rapids Cmake packages -include(rapids-cmake) -include(rapids-cpm) -include(rapids-cuda) -include(rapids-export) -include(rapids-find) diff --git a/cmake/python_module_tools.cmake b/cmake/python_module_tools.cmake index b15f0da2a..838372e44 100644 --- a/cmake/python_module_tools.cmake +++ b/cmake/python_module_tools.cmake @@ -56,7 +56,7 @@ message(VERBOSE "Python3_NumPy_VERSION: " ${Python3_NumPy_VERSION}) # pybind11 # ========= set(PYBIND11_VERSION "2.8.1" CACHE STRING "Version of Pybind11 to use") -include(${MORPHEUS_UTILS_HOME}/cmake/package_config/pybind11/Configure_pybind11.cmake) +morpheus_utils_configure_pybind11(${PYBIND11_VERSION}) if (NOT EXISTS ${Python3_SITELIB}/skbuild) # In case this is messed up by `/usr/local/python/site-packages` vs `/usr/python/site-packages`, check pip itself. @@ -81,7 +81,6 @@ set(CYTHON_FLAGS "--directive binding=True,boundscheck=False,wraparound=False,em find_package(pybind11 REQUIRED) find_package(Cython REQUIRED) - function(create_python_package PACKAGE_NAME) list(APPEND CMAKE_MESSAGE_CONTEXT "${PACKAGE_NAME}") diff --git a/cmake/ccache.conf.in b/cmake/templates/ccache.conf.in similarity index 100% rename from cmake/ccache.conf.in rename to cmake/templates/ccache.conf.in diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index 52d02b0ca..474a6cbba 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -22,7 +22,8 @@ list(PREPEND CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}") list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake") # Add the RAPIDS cmake helper scripts -include(environment/setup_rapids_cmake) +# TODO: Shouldn't be required since we do it at source scope +# include(morpheus_utils/environment_config/rapids_cmake/setup) project(mrc-quickstart VERSION 22.11.00 From 250fdd608ec667d56573915b5b70b2b8a3f6b572 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Wed, 30 Nov 2022 15:55:32 -0700 Subject: [PATCH 08/55] Checkpoint --- cmake/Configure_ccache.cmake | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cmake/Configure_ccache.cmake diff --git a/cmake/Configure_ccache.cmake b/cmake/Configure_ccache.cmake new file mode 100644 index 000000000..e69de29bb From 253d6ee1d57df38f04346a2f158a5dd81775c603 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Wed, 30 Nov 2022 17:16:21 -0700 Subject: [PATCH 09/55] Remove more common config items --- CMakeLists.txt | 35 +- cmake/Configure_ccache.cmake | 0 cmake/GRPCGenerateCPPLikeBazel.cmake | 106 --- cmake/LibFindMacros.cmake | 266 -------- cmake/ProtobufGenerateCPPLikeBazel.cmake | 115 ---- cmake/debug_utils.cmake | 72 -- cmake/dependencies.cmake | 3 - cmake/environment/setup_cache.cmake | 145 ---- .../setup_ccache.cmake} | 23 +- cmake/environment/setup_iwyu.cmake | 51 +- ..._utils.cmake => load_morpheus_utils.cmake} | 0 cmake/python_module_tools.cmake | 628 ------------------ cmake/templates/run_ccache.sh.in | 41 -- cmake/templates/run_ccache_prefix.sh.in | 23 - docs/quickstart/CMakeLists.txt | 2 +- python/CMakeLists.txt | 2 +- 16 files changed, 39 insertions(+), 1473 deletions(-) delete mode 100644 cmake/Configure_ccache.cmake delete mode 100644 cmake/GRPCGenerateCPPLikeBazel.cmake delete mode 100644 cmake/LibFindMacros.cmake delete mode 100644 cmake/ProtobufGenerateCPPLikeBazel.cmake delete mode 100644 cmake/debug_utils.cmake delete mode 100644 cmake/environment/setup_cache.cmake rename cmake/{templates/ccache.conf.in => environment/setup_ccache.cmake} (63%) rename cmake/{Configure_morpheus_utils.cmake => load_morpheus_utils.cmake} (100%) delete mode 100644 cmake/python_module_tools.cmake delete mode 100755 cmake/templates/run_ccache.sh.in delete mode 100755 cmake/templates/run_ccache_prefix.sh.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d92d492d..3470a5076 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,24 +38,26 @@ set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build fo set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) +project(mrc + VERSION 22.11.00 + LANGUAGES C CXX + ) + +enable_testing() + # CMake path list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - -enable_testing() - # Load morpheus utils and update CMake paths set(MORPHEUS_UTILS_VERSION "0.1" CACHE STRING "Version of Morpheus utils") -include(Configure_morpheus_utils) +include(load_morpheus_utils) find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") -# Conda vs Vcpkg configuration helpers -include(morpheus_utils/environment_config/package_manager/setup) -# RAPIDS CMake helpers -include(morpheus_utils/environment_config/rapids_cmake/setup) - +# Import morpheus_utils APIs +include(morpheus_utils/environment_config/api) +include(morpheus_utils/package_config/api) # Configure rapids CMake morpheus_utils_configure_rapids_cmake(MRC_RAPIDS_VERSION) @@ -74,12 +76,6 @@ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) endif() rapids_cuda_init_architectures(mrc) - -project(mrc - VERSION 22.11.00 - LANGUAGES C CXX - ) - rapids_cmake_write_version_file(${CMAKE_BINARY_DIR}/autogenerated/include/mrc/version.hpp) # Delay enabling CUDA until after we have determined our CXX compiler @@ -119,7 +115,8 @@ set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Setup cache before dependencies -include(morpheus_utils/environment_config/ccache/setup) +# Configure CCache if requested +include(environment/setup_ccache) # Configure conda if(MRC_USE_CONDA AND DEFINED ENV{CONDA_PREFIX}) @@ -140,7 +137,7 @@ add_custom_target(${PROJECT_NAME}_style_checks ) # Configure all dependencies -include(cmake/dependencies.cmake) +include(dependencies) # Enable for all first party code set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -433,6 +430,6 @@ endif() add_subdirectory(src/tools) # Uncomment the following to print all available targets -# include(debug_utils) -# print_all_targets() +#include(morpheus_utils/source/utils/debug) +#morpheus_utils_print_all_targets() list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/cmake/Configure_ccache.cmake b/cmake/Configure_ccache.cmake deleted file mode 100644 index e69de29bb..000000000 diff --git a/cmake/GRPCGenerateCPPLikeBazel.cmake b/cmake/GRPCGenerateCPPLikeBazel.cmake deleted file mode 100644 index 2a63386f1..000000000 --- a/cmake/GRPCGenerateCPPLikeBazel.cmake +++ /dev/null @@ -1,106 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2018-2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin) # Get full path to plugin - -function(PROTOBUF_GENERATE_GRPC_CPP_LIKE_BAZEL SRCS HDRS) - cmake_parse_arguments(protobuf "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN}) - - set(PROTO_FILES "${protobuf_UNPARSED_ARGUMENTS}") - if(NOT PROTO_FILES) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_GRPC_CPP() called without any proto files") - return() - endif() - - if(protobuf_EXPORT_MACRO) - set(DLL_EXPORT_DECL "dllexport_decl=${protobuf_EXPORT_MACRO}:") - endif() - - get_filename_component(ABS_PROTO_PATH ${CMAKE_SOURCE_DIR} ABSOLUTE) - set(EXTRA_ARGS "--proto_path=${ABS_PROTO_PATH}") - file(RELATIVE_PATH Protobuf_PRE_IMPORT_DIRS ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) - - if(PROTOBUF_GENERATE_CPP_APPEND_PATH) # This variable is common for all types of output. - # Create an include path for each file specified - foreach(FIL ${PROTO_FILES}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(ABS_PATH ${ABS_FIL} PATH) - list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${ABS_PATH}) - endif() - endforeach() - else() - set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - - if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) - set(Protobuf_IMPORT_DIR "${PROTOBUF_IMPORT_DIRS") - endif() - - if(DEFINED Protobuf_IMPORT_DIRS) - foreach(DIR ${Protobuf_IMPORT_DIRS}) - get_filename_component(ABS_PATH ${DIR} ABSOLUTE) - list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${ABS_PATH}) - endif() - endforeach() - endif() - - set(${SRCS}) - set(${HDRS}) - foreach(FIL ${PROTO_FILES}) - message(STATUS "grpc_cpp_proto: ${FIL}") - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(FIL_WE ${FIL} NAME_WE) - message(STATUS "grpc_cpp_proto_abs: ${ABS_FIL}") - - if(NOT PROTOBUF_GENERATE_CPP_APPEND_PATH) - get_filename_component(FIL_DIR ${FIL} DIRECTORY) - if(FIL_DIR) - set(FIL_WE "${FIL_DIR}/${FIL_WE}") - endif() - endif() - - if(Protobuf_PRE_IMPORT_DIRS) - set(_protobuf_protoc_src "${CMAKE_CURRENT_BINARY_DIR}/${Protobuf_PRE_IMPORT_DIRS}/${FIL_WE}.grpc.pb.cc") - set(_protobuf_protoc_hdr "${CMAKE_CURRENT_BINARY_DIR}/${Protobuf_PRE_IMPORT_DIRS}/${FIL_WE}.grpc.pb.h") - else() - set(_protobuf_protoc_src "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.cc") - set(_protobuf_protoc_hdr "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.grpc.pb.h") - endif() - message(STATUS "grpc_cpp_src: ${_protobuf_protoc_src}") - list(APPEND ${SRCS} "${_protobuf_protoc_src}") - list(APPEND ${HDRS} "${_protobuf_protoc_hdr}") - - add_custom_command( - OUTPUT "${_protobuf_protoc_src}" - "${_protobuf_protoc_hdr}" - COMMAND ${Protobuf_PROTOC_EXECUTABLE} - ${EXTRA_ARGS} - "--grpc_out=${CMAKE_CURRENT_BINARY_DIR}" - "--plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}" - ${_protobuf_protoc_flags} - ${_protobuf_include_path} ${ABS_FIL} - DEPENDS ${ABS_FIL} ${Protobuf_PROTOC_EXECUTABLE} - COMMENT "Running gRPC C++ protocol buffer compiler on ${FIL}" - VERBATIM) - endforeach() - - set_source_files_properties(${${SRCS}} ${${HDRS}} PROPERTIES GENERATED TRUE) - set(${SRCS} ${${SRCS}} PARENT_SCOPE) - set(${HDRS} ${${HDRS}} PARENT_SCOPE) -endfunction() diff --git a/cmake/LibFindMacros.cmake b/cmake/LibFindMacros.cmake deleted file mode 100644 index 3ef5844dd..000000000 --- a/cmake/LibFindMacros.cmake +++ /dev/null @@ -1,266 +0,0 @@ -# Version 2.2 -# Public Domain, originally written by Lasse Kärkkäinen -# Maintained at https://github.com/Tronic/cmake-modules -# Please send your improvements as pull requests on Github. - -# Find another package and make it a dependency of the current package. -# This also automatically forwards the "REQUIRED" argument. -# Usage: libfind_package( [extra args to find_package]) -macro (libfind_package PREFIX PKG) - set(${PREFIX}_args ${PKG} ${ARGN}) - if (${PREFIX}_FIND_REQUIRED) - set(${PREFIX}_args ${${PREFIX}_args} REQUIRED) - endif() - find_package(${${PREFIX}_args}) - set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG}) - unset(${PREFIX}_args) -endmacro() - -# A simple wrapper to make pkg-config searches a bit easier. -# Works the same as CMake's internal pkg_check_modules but is always quiet. -macro (libfind_pkg_check_modules) - find_package(PkgConfig QUIET) - if (PKG_CONFIG_FOUND) - pkg_check_modules(${ARGN} QUIET) - endif() -endmacro() - -# Avoid useless copy&pasta by doing what most simple libraries do anyway: -# pkg-config, find headers, find library. -# Usage: libfind_pkg_detect( FIND_PATH [other args] FIND_LIBRARY [other args]) -# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2) -function (libfind_pkg_detect PREFIX) - # Parse arguments - set(argname pkgargs) - foreach (i ${ARGN}) - if ("${i}" STREQUAL "FIND_PATH") - set(argname pathargs) - elseif ("${i}" STREQUAL "FIND_LIBRARY") - set(argname libraryargs) - else() - set(${argname} ${${argname}} ${i}) - endif() - endforeach() - if (NOT pkgargs) - message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.") - endif() - # Find library - libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs}) - if (pathargs) - find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS}) - endif() - if (libraryargs) - find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS}) - endif() -endfunction() - -# Extracts a version #define from a version.h file, output stored to _VERSION. -# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR) -# Fourth argument "QUIET" may be used for silently testing different define names. -# This function does nothing if the version variable is already defined. -function (libfind_version_header PREFIX VERSION_H DEFINE_NAME) - # Skip processing if we already have a version or if the include dir was not found - if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR) - return() - endif() - set(quiet ${${PREFIX}_FIND_QUIETLY}) - # Process optional arguments - foreach(arg ${ARGN}) - if (arg STREQUAL "QUIET") - set(quiet TRUE) - else() - message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.") - endif() - endforeach() - # Read the header and parse for version number - set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") - if (NOT EXISTS ${filename}) - if (NOT quiet) - message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") - endif() - return() - endif() - file(READ "${filename}" header) - string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}") - # No regex match? - if (match STREQUAL header) - if (NOT quiet) - message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}") - endif() - return() - endif() - # Export the version string - set(${PREFIX}_VERSION "${match}" PARENT_SCOPE) -endfunction() - -# Do the final processing once the paths have been detected. -# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain -# all the variables, each of which contain one include directory. -# Ditto for ${PREFIX}_PROCESS_LIBS and library files. -# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES. -# Also handles errors in case library detection was required, etc. -function (libfind_process PREFIX) - # Skip processing if already processed during this configuration run - if (${PREFIX}_FOUND) - return() - endif() - - set(found TRUE) # Start with the assumption that the package was found - - # Did we find any files? Did we miss includes? These are for formatting better error messages. - set(some_files FALSE) - set(missing_headers FALSE) - - # Shorthands for some variables that we need often - set(quiet ${${PREFIX}_FIND_QUIETLY}) - set(required ${${PREFIX}_FIND_REQUIRED}) - set(exactver ${${PREFIX}_FIND_VERSION_EXACT}) - set(findver "${${PREFIX}_FIND_VERSION}") - set(version "${${PREFIX}_VERSION}") - - # Lists of config option names (all, includes, libs) - unset(configopts) - set(includeopts ${${PREFIX}_PROCESS_INCLUDES}) - set(libraryopts ${${PREFIX}_PROCESS_LIBS}) - - # Process deps to add to - foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES}) - if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS) - # The package seems to export option lists that we can use, woohoo! - list(APPEND includeopts ${${i}_INCLUDE_OPTS}) - list(APPEND libraryopts ${${i}_LIBRARY_OPTS}) - else() - # If plural forms don't exist or they equal singular forms - if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR - ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES)) - # Singular forms can be used - if (DEFINED ${i}_INCLUDE_DIR) - list(APPEND includeopts ${i}_INCLUDE_DIR) - endif() - if (DEFINED ${i}_LIBRARY) - list(APPEND libraryopts ${i}_LIBRARY) - endif() - else() - # Oh no, we don't know the option names - message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!") - endif() - endif() - endforeach() - - if (includeopts) - list(REMOVE_DUPLICATES includeopts) - endif() - - if (libraryopts) - list(REMOVE_DUPLICATES libraryopts) - endif() - - string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}") - if (NOT tmp STREQUAL "${includeopts} ${libraryopts}") - message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).") - endif() - - # Include/library names separated by spaces (notice: not CMake lists) - unset(includes) - unset(libs) - - # Process all includes and set found false if any are missing - foreach (i ${includeopts}) - list(APPEND configopts ${i}) - if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") - list(APPEND includes "${${i}}") - else() - set(found FALSE) - set(missing_headers TRUE) - endif() - endforeach() - - # Process all libraries and set found false if any are missing - foreach (i ${libraryopts}) - list(APPEND configopts ${i}) - if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND") - list(APPEND libs "${${i}}") - else() - set (found FALSE) - endif() - endforeach() - - # Version checks - if (found AND findver) - if (NOT version) - message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.") - elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver)) - set(found FALSE) - set(version_unsuitable TRUE) - endif() - endif() - - # If all-OK, hide all config options, export variables, print status and exit - if (found) - foreach (i ${configopts}) - mark_as_advanced(${i}) - endforeach() - if (NOT quiet) - message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}") - if (LIBFIND_DEBUG) - message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}") - message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}") - message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}") - message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}") - message(STATUS " ${PREFIX}_LIBRARIES=${libs}") - endif() - set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE) - set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE) - set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE) - set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE) - set (${PREFIX}_FOUND TRUE PARENT_SCOPE) - endif() - return() - endif() - - # Format messages for debug info and the type of error - set(vars "Relevant CMake configuration variables:\n") - foreach (i ${configopts}) - mark_as_advanced(CLEAR ${i}) - set(val ${${i}}) - if ("${val}" STREQUAL "${i}-NOTFOUND") - set (val "") - elseif (val AND NOT EXISTS ${val}) - set (val "${val} (does not exist)") - else() - set(some_files TRUE) - endif() - set(vars "${vars} ${i}=${val}\n") - endforeach() - set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n") - if (version_unsuitable) - set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but") - if (exactver) - set(msg "${msg} only version ${findver} is acceptable.") - else() - set(msg "${msg} version ${findver} is the minimum requirement.") - endif() - else() - if (missing_headers) - set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?") - elseif (some_files) - set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?") - if(findver) - set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).") - endif() - else() - set(msg "We were unable to find package ${PREFIX}.") - endif() - endif() - - # Fatal error out if REQUIRED - if (required) - set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.") - message(FATAL_ERROR "${msg}\n${vars}") - endif() - # Otherwise just print a nasty warning - if (NOT quiet) - message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}") - endif() -endfunction() - diff --git a/cmake/ProtobufGenerateCPPLikeBazel.cmake b/cmake/ProtobufGenerateCPPLikeBazel.cmake deleted file mode 100644 index 51de730dc..000000000 --- a/cmake/ProtobufGenerateCPPLikeBazel.cmake +++ /dev/null @@ -1,115 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2020-2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -function(PROTOBUF_GENERATE_CPP_LIKE_BAZEL SRCS HDRS) - cmake_parse_arguments(protobuf "" "EXPORT_MACRO;DESCRIPTORS" "" ${ARGN}) - - set(PROTO_FILES "${protobuf_UNPARSED_ARGUMENTS}") - if(NOT PROTO_FILES) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_CPP() called without any proto files") - return() - endif() - - if(protobuf_EXPORT_MACRO) - set(DLL_EXPORT_DECL "dllexport_decl=${protobuf_EXPORT_MACRO}:") - endif() - - get_filename_component(ABS_PROTO_PATH ${CMAKE_SOURCE_DIR} ABSOLUTE) - set(EXTRA_ARGS "--proto_path=${ABS_PROTO_PATH}") - file(RELATIVE_PATH Protobuf_PRE_IMPORT_DIRS ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) - - if(PROTOBUF_GENERATE_CPP_APPEND_PATH) - # Create an include path for each file specified - foreach(FIL ${PROTO_FILES}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(ABS_PATH ${ABS_FIL} PATH) - list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${ABS_PATH}) - endif() - endforeach() - else() - set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - - if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) - set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") - endif() - - if(DEFINED Protobuf_IMPORT_DIRS) - foreach(DIR ${Protobuf_IMPORT_DIRS}) - get_filename_component(ABS_PATH ${DIR} ABSOLUTE) - list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${ABS_PATH}) - endif() - endforeach() - endif() - - set(${SRCS}) - set(${HDRS}) - if (protobuf_DESCRIPTORS) - set(${protobuf_DESCRIPTORS}) - endif() - - foreach(FIL ${PROTO_FILES}) - get_filename_component(ABS_FIL ${FIL} ABSOLUTE) - get_filename_component(FIL_WE ${FIL} NAME_WE) - if(NOT PROTOBUF_GENERATE_CPP_APPEND_PATH) - get_filename_component(FIL_DIR ${FIL} DIRECTORY) - if(FIL_DIR) - set(FIL_WE "${FIL_DIR}/${FIL_WE}") - endif() - endif() - - if(Protobuf_PRE_IMPORT_DIRS) - set(_protobuf_protoc_src "${CMAKE_CURRENT_BINARY_DIR}/${Protobuf_PRE_IMPORT_DIRS}/${FIL_WE}.pb.cc") - set(_protobuf_protoc_hdr "${CMAKE_CURRENT_BINARY_DIR}/${Protobuf_PRE_IMPORT_DIRS}/${FIL_WE}.pb.h") - else() - set(_protobuf_protoc_src "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.cc") - set(_protobuf_protoc_hdr "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h") - endif() - list(APPEND ${SRCS} "${_protobuf_protoc_src}") - list(APPEND ${HDRS} "${_protobuf_protoc_hdr}") - - if(protobuf_DESCRIPTORS) - set(_protobuf_protoc_desc "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.desc") - set(_protobuf_protoc_flags "--descriptor_set_out=${_protobuf_protoc_desc}") - list(APPEND ${protobuf_DESCRIPTORS} "${_protobuf_protoc_desc}") - else() - set(_protobuf_protoc_desc "") - set(_protobuf_protoc_flags "") - endif() - - add_custom_command( - OUTPUT "${_protobuf_protoc_src}" - "${_protobuf_protoc_hdr}" - ${_protobuf_protoc_desc} - COMMAND protobuf::protoc - ${EXTRA_ARGS} - "--cpp_out=${DLL_EXPORT_DECL}${CMAKE_CURRENT_BINARY_DIR}" - ${_protobuf_protoc_flags} - ${_protobuf_include_path} ${ABS_FIL} - DEPENDS ${ABS_FIL} protobuf::protoc - COMMENT "Running C++ protocol buffer compiler on ${FIL}" - VERBATIM ) - endforeach() - - set(${SRCS} "${${SRCS}}" PARENT_SCOPE) - set(${HDRS} "${${HDRS}}" PARENT_SCOPE) - if(protobuf_DESCRIPTORS) - set(${protobuf_DESCRIPTORS} "${${protobuf_DESCRIPTORS}}" PARENT_SCOPE) - endif() -endfunction() diff --git a/cmake/debug_utils.cmake b/cmake/debug_utils.cmake deleted file mode 100644 index b1c7d9331..000000000 --- a/cmake/debug_utils.cmake +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022,NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Get all propreties that cmake supports -if(NOT CMAKE_PROPERTY_LIST) - execute_process(COMMAND cmake --help-property-list OUTPUT_VARIABLE CMAKE_PROPERTY_LIST) - - # Convert command output into a CMake list - string(REGEX REPLACE ";" "\\\\;" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}") - string(REGEX REPLACE "\n" ";" CMAKE_PROPERTY_LIST "${CMAKE_PROPERTY_LIST}") -endif() - -function(print_properties) - message("CMAKE_PROPERTY_LIST = ${CMAKE_PROPERTY_LIST}") -endfunction() - -function(print_target_properties target) - if(NOT TARGET ${target}) - message(STATUS "There is no target named '${target}'") - return() - endif() - - foreach(property ${CMAKE_PROPERTY_LIST}) - string(REPLACE "" "${CMAKE_BUILD_TYPE}" property ${property}) - - # Fix https://stackoverflow.com/questions/32197663/how-can-i-remove-the-the-location-property-may-not-be-read-from-target-error-i - if(property STREQUAL "LOCATION" OR property MATCHES "^LOCATION_" OR property MATCHES "_LOCATION$") - continue() - endif() - - get_property(was_set TARGET ${target} PROPERTY ${property} SET) - if(was_set) - get_target_property(value ${target} ${property}) - message("${target} ${property} = ${value}") - endif() - endforeach() -endfunction() - - - -macro(get_all_targets_recursive targets dir) - get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES) - foreach(subdir ${subdirectories}) - get_all_targets_recursive(${targets} ${subdir}) - endforeach() - - get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS) - list(APPEND ${targets} ${current_targets}) -endmacro() - -function(get_all_targets var) - set(targets) - get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR}) - set(${var} ${targets} PARENT_SCOPE) -endfunction() - -function(print_all_targets) - get_all_targets(all_targets) - message("All targets: ${all_targets}") -endfunction() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 278c13b4c..2abe4394c 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -53,9 +53,6 @@ rapids_find_package(CUDAToolkit INSTALL_EXPORT_SET ${PROJECT_NAME}-core-exports ) -# Import morpheus_utils package configuration API -include(morpheus_utils/package_config/api) - # Boost # ===== # - Use static linking to avoid issues with system-wide installations of Boost. diff --git a/cmake/environment/setup_cache.cmake b/cmake/environment/setup_cache.cmake deleted file mode 100644 index b21365f92..000000000 --- a/cmake/environment/setup_cache.cmake +++ /dev/null @@ -1,145 +0,0 @@ -# ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -# ============================================================================= - -# ###################################################################################################################### -# * CMake properties ------------------------------------------------------------------------------ - -include_guard() -list(APPEND CMAKE_MESSAGE_CONTEXT "cache") - -function(configure_ccache cache_dir_name) - list(APPEND CMAKE_MESSAGE_CONTEXT "ccache") - - find_program(CCACHE_PROGRAM_PATH ccache DOC "Location of ccache executable") - - if(NOT CCACHE_PROGRAM_PATH) - message(WARNING "CCache option, ${cache_dir_name}, is enabled but ccache was not found. Check ccache installation.") - return() - endif() - - message(STATUS "Using ccache: ${CCACHE_PROGRAM_PATH}") - - set(LOCAL_MODULES_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") - set(CCACHE_DIR "${${cache_dir_name}}/ccache") - - message(STATUS "Using ccache directory: ${CCACHE_DIR}") - - # Write or update the ccache configuration file - configure_file("${LOCAL_MODULES_PATH}/ccache.conf.in" "${CCACHE_DIR}/ccache.conf") - - # Set the ccache options we need - set(CCACHE_CONFIGPATH "${CCACHE_DIR}/ccache.conf") - - # Because CMake doesnt allow settings variables `CCACHE_COMPILERTYPE=gcc - # ccache` in CMAKE_C_COMPILER_LAUNCHER, we need to put everything into a - # single script and use that for CMAKE_C_COMPILER_LAUNCHER. Also, since - # gxx_linux-64 sets the compiler to c++ instead of g++, we need to set the - # value of CCACHE_COMPILERTYPE otherwise caching doesnt work correctly. So - # we need to make separate runners for each language with specific ccache - # settings for each - if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CCACHE_REMOVE_ARGS "^--driver-mode=.*") - endif() - - # Set the base dir for relative ccache - set(CCACHE_BASEDIR "${PROJECT_SOURCE_DIR}") - - # Configure ccache for C - if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") - set(CCACHE_COMPILERTYPE "gcc") - elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") - set(CCACHE_COMPILERTYPE "clang") - else() - set(CCACHE_COMPILERTYPE "auto") - endif() - - configure_file("${LOCAL_MODULES_PATH}/templates/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_c.sh" @ONLY) - - # Configure ccache for CXX - if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - set(CCACHE_COMPILERTYPE "gcc") - elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CCACHE_COMPILERTYPE "clang") - else() - set(CCACHE_COMPILERTYPE "auto") - endif() - - configure_file("${LOCAL_MODULES_PATH}/templates/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cxx.sh" @ONLY) - - # Configure ccache for CUDA - set(CCACHE_COMPILERTYPE "nvcc") - configure_file("${LOCAL_MODULES_PATH}/templates/run_ccache.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cuda.sh" @ONLY) - - # Finally, set the compiler option - set(CMAKE_C_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_c.sh" PARENT_SCOPE) - set(CMAKE_CXX_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cxx.sh" PARENT_SCOPE) - set(CMAKE_CUDA_COMPILER_LAUNCHER "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_cuda.sh" PARENT_SCOPE) - - # PARENT_SCOPE here so others can use this value - set(CCACHE_DIR "${CCACHE_DIR}" PARENT_SCOPE) -endfunction() - -function(configure_cpm cache_dir_name) - list(APPEND CMAKE_MESSAGE_CONTEXT "cpm") - - # Set the CPM cache variable - set(ENV{CPM_SOURCE_CACHE} "${${cache_dir_name}}/cpm") - - message(STATUS "Using CPM source cache: $ENV{CPM_SOURCE_CACHE}") - - # # Set the FetchContent default download folder to be the same as CPM - # set(FETCHCONTENT_BASE_DIR "${${cache_dir_name}}/fetch" CACHE STRING "" FORCE) -endfunction() - -function(check_cache_path cache_dir_name) - # First, ensure that the current cache dir can be found by find_package/find_path/etc - if((NOT "${CMAKE_FIND_ROOT_PATH}" STREQUAL "") AND("${CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}" STREQUAL "ONLY")) - set(is_contained FALSE) - - # Now check if ${cache_dir_name} is under anything in CMAKE_FIND_ROOT_PATH - foreach(path_to_search ${CMAKE_FIND_ROOT_PATH}) - # Check if we are contained by the find path - cmake_path(IS_PREFIX path_to_search ${${cache_dir_name}} is_relative) - - if(is_relative) - set(is_contained TRUE) - break() - endif() - endforeach() - - if(NOT is_contained) - message(WARNING "The value for ${cache_dir_name} (${${cache_dir_name}}) is not contained in any CMAKE_FIND_ROOT_PATH (${CMAKE_FIND_ROOT_PATH}). " - "This will result in cmake being unable to find any downloaded packages. The cache path has been appended to the back " - "of CMAKE_FIND_ROOT_PATH") - - list(APPEND CMAKE_FIND_ROOT_PATH ${${cache_dir_name}}) - - set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} PARENT_SCOPE) - endif() - endif() -endfunction() - -check_cache_path(MRC_CACHE_DIR) - -# Configure CCache if requested -if(MRC_USE_CCACHE) - configure_ccache(MRC_CACHE_DIR) -endif() - -configure_cpm(MRC_CACHE_DIR) - -list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/cmake/templates/ccache.conf.in b/cmake/environment/setup_ccache.cmake similarity index 63% rename from cmake/templates/ccache.conf.in rename to cmake/environment/setup_ccache.cmake index 5330647b0..09167617e 100644 --- a/cmake/templates/ccache.conf.in +++ b/cmake/environment/setup_ccache.cmake @@ -13,14 +13,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -max_size = 10G -# hash_dir = false -# let ccache preserve C++ comments, because some of them may be meaningful to the compiler -keep_comments_cpp = true -cache_dir = @CCACHE_DIR@ -compiler_check = %compiler% --version -# Uncomment to debug ccache preprocessor errors/cache misses -log_file = @CCACHE_DIR@/ccache.log +include_guard(GLOBAL) -# Force absolute paths in error output for IDEs -absolute_paths_in_stderr = true +list(APPEND CMAKE_MESSAGE_CONTEXT "cache") + +morpheus_utils_check_cache_path(MRC_CACHE_DIR) + +# Configure CCache if requested +if(MRC_USE_CCACHE) + morpheus_utils_configure_ccache(MRC_CACHE_DIR) +endif() + +morpheus_utils_configure_cpm(MRC_CACHE_DIR) + +list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/cmake/environment/setup_iwyu.cmake b/cmake/environment/setup_iwyu.cmake index a1a786bb6..ef2b2c55d 100644 --- a/cmake/environment/setup_iwyu.cmake +++ b/cmake/environment/setup_iwyu.cmake @@ -1,5 +1,5 @@ # ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,47 +15,12 @@ # limitations under the License. # ============================================================================= -function(configure_iwyu) - list(APPEND CMAKE_MESSAGE_CONTEXT "iwyu") - - set(MRC_IWYU_VERBOSITY "1" CACHE STRING "Set verbosity level for include-what-you-use, 1 is default, 1 only shows recomendations and 11+ prints everything") - - find_program(MRC_IWYU_PROGRAM "include-what-you-use") - - if(MRC_IWYU_PROGRAM) - set(MRC_IWYU_OPTIONS - -Xiwyu; --mapping_file=${PROJECT_SOURCE_DIR}/ci/iwyu/mappings.imp; - -Xiwyu; --max_line_length=120; - -Xiwyu; --verbose=${MRC_IWYU_VERBOSITY}; - -Xiwyu; --no_fwd_decls; - -Xiwyu; --quoted_includes_first; - -Xiwyu; --cxx17ns; - -Xiwyu --no_comments) - - # Convert these to space separated arguments - string(REPLACE ";" " " MRC_IWYU_OPTIONS "${MRC_IWYU_OPTIONS}") - - message(STATUS "Enabling include-what-you-use for MRC targets") - - set(IWYU_WRAPPER "${CMAKE_CURRENT_BINARY_DIR}/run_iwyu.sh") - - # Make a ccache runner file with the necessary settings. MRC_CCACHE_OPTIONS must be set! - configure_file("${LOCAL_MODULES_PATH}/templates/run_iwyu.sh.in" "${IWYU_WRAPPER}") - - if(MRC_USE_CCACHE) - set(CMAKE_C_INCLUDE_WHAT_YOU_USE "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_prefix.sh;${IWYU_WRAPPER};${CMAKE_C_COMPILER}" PARENT_SCOPE) - set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${CMAKE_CURRENT_BINARY_DIR}/run_ccache_prefix.sh;${IWYU_WRAPPER};${CMAKE_CXX_COMPILER}" PARENT_SCOPE) - else() - set(CMAKE_C_INCLUDE_WHAT_YOU_USE "${IWYU_WRAPPER}" PARENT_SCOPE) - set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_WRAPPER}" PARENT_SCOPE) - endif() - - else() - message(WARNING "IWYU option MRC_USE_IWYU is enabled but the include-what-you-use was not found. Check iwyu installation and add the iwyu bin dir to your PATH variable.") - endif(MRC_IWYU_PROGRAM) -endfunction() - -# Configure IWYU if requested if(MRC_USE_IWYU) - configure_iwyu() + morpheus_utils_configure_iwyu( + MRC_USE_IWYU + MRC_IWYU_VERBOSITY + MRC_IWYU_PROGRAM + MRC_IWYU_OPTIONS + MRC_USE_CCACHE + ) endif(MRC_USE_IWYU) diff --git a/cmake/Configure_morpheus_utils.cmake b/cmake/load_morpheus_utils.cmake similarity index 100% rename from cmake/Configure_morpheus_utils.cmake rename to cmake/load_morpheus_utils.cmake diff --git a/cmake/python_module_tools.cmake b/cmake/python_module_tools.cmake deleted file mode 100644 index 838372e44..000000000 --- a/cmake/python_module_tools.cmake +++ /dev/null @@ -1,628 +0,0 @@ -# ============================================================================= -# Copyright (c) 2020-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. -# ============================================================================= - -## TODO: these need to be extracted to a cmake utilities repo - -# Ensure we only include this once -include_guard(DIRECTORY) - -# Get the project name in uppercase if OPTION_PREFIX is not defined -if(NOT DEFINED OPTION_PREFIX) - string(TOUPPER "${PROJECT_NAME}" OPTION_PREFIX) -endif() - -option(${OPTION_PREFIX}_PYTHON_INPLACE_BUILD "Whether or not to copy built python modules back to the source tree for debug purposes." OFF) -option(${OPTION_PREFIX}_PYTHON_PERFORM_INSTALL "Whether or not to automatically `pip install` any built python library. WARNING: This may overwrite any existing installation of the same name." OFF) -option(${OPTION_PREFIX}_PYTHON_BUILD_STUBS "Whether or not to generated .pyi stub files for C++ Python modules. Disable to avoid requiring loading the NVIDIA GPU Driver during build" ON) - -set(Python3_FIND_VIRTUALENV "FIRST") -set(Python3_FIND_STRATEGY "LOCATION") - -message(VERBOSE "Python3_EXECUTABLE (before find_package): ${Python3_EXECUTABLE}") -message(VERBOSE "Python3_ROOT_DIR (before find_package): ${Python3_ROOT_DIR}") -message(VERBOSE "FIND_PYTHON_STRATEGY (before find_package): ${FIND_PYTHON_STRATEGY}") - -find_package(Python3 REQUIRED COMPONENTS Development Interpreter) - -message(VERBOSE "Python3_FOUND: " ${Python3_FOUND}) -message(VERBOSE "Python3_EXECUTABLE: ${Python3_EXECUTABLE}") -message(VERBOSE "Python3_INTERPRETER_ID: " ${Python3_INTERPRETER_ID}) -message(VERBOSE "Python3_STDLIB: " ${Python3_STDLIB}) -message(VERBOSE "Python3_STDARCH: " ${Python3_STDARCH}) -message(VERBOSE "Python3_SITELIB: " ${Python3_SITELIB}) -message(VERBOSE "Python3_SITEARCH: " ${Python3_SITEARCH}) -message(VERBOSE "Python3_SOABI: " ${Python3_SOABI}) -message(VERBOSE "Python3_INCLUDE_DIRS: " ${Python3_INCLUDE_DIRS}) -message(VERBOSE "Python3_LIBRARIES: " ${Python3_LIBRARIES}) -message(VERBOSE "Python3_LIBRARY_DIRS: " ${Python3_LIBRARY_DIRS}) -message(VERBOSE "Python3_VERSION: " ${Python3_VERSION}) -message(VERBOSE "Python3_NumPy_FOUND: " ${Python3_NumPy_FOUND}) -message(VERBOSE "Python3_NumPy_INCLUDE_DIRS: " ${Python3_NumPy_INCLUDE_DIRS}) -message(VERBOSE "Python3_NumPy_VERSION: " ${Python3_NumPy_VERSION}) - -# After finding python, now find pybind11 - -# pybind11 -# ========= -set(PYBIND11_VERSION "2.8.1" CACHE STRING "Version of Pybind11 to use") -morpheus_utils_configure_pybind11(${PYBIND11_VERSION}) - -if (NOT EXISTS ${Python3_SITELIB}/skbuild) - # In case this is messed up by `/usr/local/python/site-packages` vs `/usr/python/site-packages`, check pip itself. - execute_process( - COMMAND bash "-c" "${Python3_EXECUTABLE} -m pip show scikit-build | sed -n -e 's/Location: //p'" - OUTPUT_VARIABLE PYTHON_SITE_PACKAGES - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if (NOT EXISTS ${PYTHON_SITE_PACKAGES}/skbuild) - message(SEND_ERROR "Scikit-build is not installed. CMake may not be able to find Cython. Install scikit-build with `pip install scikit-build`") - else() - list(APPEND CMAKE_MODULE_PATH "${PYTHON_SITE_PACKAGES}/skbuild/resources/cmake") - endif() -else () - list(APPEND CMAKE_MODULE_PATH "${Python3_SITELIB}/skbuild/resources/cmake") -endif () - -set(CYTHON_FLAGS "--directive binding=True,boundscheck=False,wraparound=False,embedsignature=True,always_allow_keywords=True" CACHE STRING "The directives for Cython compilation.") - -# Now we can find pybind11 -find_package(pybind11 REQUIRED) -find_package(Cython REQUIRED) - -function(create_python_package PACKAGE_NAME) - - list(APPEND CMAKE_MESSAGE_CONTEXT "${PACKAGE_NAME}") - set(CMAKE_MESSAGE_CONTEXT ${CMAKE_MESSAGE_CONTEXT} PARENT_SCOPE) - - if(PYTHON_ACTIVE_PACKAGE_NAME) - message(FATAL_ERROR "An active wheel has already been created. Must call create_python_package/build_python_package in pairs") - endif() - - message(STATUS "Creating python package '${PACKAGE_NAME}'") - - # Set the active wheel in the parent scipe - set(PYTHON_ACTIVE_PACKAGE_NAME ${PACKAGE_NAME}-package) - - # Create a dummy source that holds all of the source files as resources - add_custom_target(${PYTHON_ACTIVE_PACKAGE_NAME}-sources ALL) - - # Make it depend on the sources - add_custom_target(${PYTHON_ACTIVE_PACKAGE_NAME}-modules ALL - DEPENDS ${PYTHON_ACTIVE_PACKAGE_NAME}-sources - ) - - # Outputs target depends on all sources, generated files, and modules - add_custom_target(${PYTHON_ACTIVE_PACKAGE_NAME}-outputs ALL - DEPENDS ${PYTHON_ACTIVE_PACKAGE_NAME}-modules - ) - - # Now setup some simple globbing for common files to move to the build directory - file(GLOB_RECURSE wheel_python_files - LIST_DIRECTORIES FALSE - CONFIGURE_DEPENDS - "*.py" - "py.typed" - "pyproject.toml" - "setup.cfg" - "MANIFEST.in" - ) - - add_python_sources(${wheel_python_files}) - - # Set the active wheel in the parent scope so it will appear in any subdirectories - set(PYTHON_ACTIVE_PACKAGE_NAME ${PYTHON_ACTIVE_PACKAGE_NAME} PARENT_SCOPE) - -endfunction() - -function(add_target_resources) - - set(flags "") - set(singleValues TARGET_NAME) - set(multiValues "") - - include(CMakeParseArguments) - cmake_parse_arguments(_ARGS - "${flags}" - "${singleValues}" - "${multiValues}" - ${ARGN} - ) - - # Get the current target resources - get_target_property(target_resources ${_ARGS_TARGET_NAME} RESOURCE) - - set(args_absolute_paths) - - foreach(resource ${_ARGS_UNPARSED_ARGUMENTS}) - - cmake_path(ABSOLUTE_PATH resource NORMALIZE OUTPUT_VARIABLE resource_absolute) - - list(APPEND args_absolute_paths "${resource_absolute}") - - endforeach() - - if(target_resources) - # Append the list of supplied resources - list(APPEND target_resources "${args_absolute_paths}") - else() - set(target_resources "${args_absolute_paths}") - endif() - - set_target_properties(${_ARGS_TARGET_NAME} PROPERTIES RESOURCE "${target_resources}") - -endfunction() - -function(add_python_sources) - - if(NOT PYTHON_ACTIVE_PACKAGE_NAME) - message(FATAL_ERROR "Must call create_python_wheel() before calling add_python_sources") - endif() - - # Append any arguments to the python_sources_target - add_target_resources(TARGET_NAME ${PYTHON_ACTIVE_PACKAGE_NAME}-sources ${ARGN}) - -endfunction() - -function(copy_target_resources TARGET_NAME COPY_DIRECTORY) - - # See if there are any resources associated with this target - get_target_property(target_resources ${TARGET_NAME} RESOURCE) - - if(target_resources) - - # Get the build and src locations - get_target_property(target_source_dir ${TARGET_NAME} SOURCE_DIR) - get_target_property(target_binary_dir ${TARGET_NAME} BINARY_DIR) - - set(resource_outputs "") - - # Create the copy command for each resource - foreach(resource ${target_resources}) - - # Get the absolute path of the resource in case its relative. - cmake_path(ABSOLUTE_PATH resource NORMALIZE) - - cmake_path(IS_PREFIX target_source_dir "${resource}" NORMALIZE is_source_relative) - cmake_path(IS_PREFIX target_binary_dir "${resource}" NORMALIZE is_binary_relative) - - # Get the relative path to the source or binary directories - if(is_binary_relative) - # This must come first because build is relative to source - cmake_path(RELATIVE_PATH resource BASE_DIRECTORY "${target_binary_dir}" OUTPUT_VARIABLE resource_relative) - elseif(is_source_relative) - cmake_path(RELATIVE_PATH resource BASE_DIRECTORY "${target_source_dir}" OUTPUT_VARIABLE resource_relative) - else() - message(SEND_ERROR "Target resource is not relative to the source or binary directory. Target: ${TARGET_NAME}, Resource: ${resource}") - endif() - - # Get the final copied location - cmake_path(APPEND COPY_DIRECTORY "${resource_relative}" OUTPUT_VARIABLE resource_output) - - message(VERBOSE "Copying ${resource} to ${resource_output}") - - # Pretty up the output message - set(top_level_source_dir ${${CMAKE_PROJECT_NAME}_SOURCE_DIR}) - cmake_path(RELATIVE_PATH resource BASE_DIRECTORY "${top_level_source_dir}" OUTPUT_VARIABLE resource_source_relative) - cmake_path(RELATIVE_PATH resource_output BASE_DIRECTORY "${top_level_source_dir}" OUTPUT_VARIABLE resource_output_source_relative) - - add_custom_command( - OUTPUT ${resource_output} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${resource} ${resource_output} - DEPENDS ${resource} - COMMENT "Copying \${SOURCE_DIR}/${resource_source_relative} to \${SOURCE_DIR}/${resource_output_source_relative}" - ) - - list(APPEND resource_outputs ${resource_output}) - endforeach() - - # Final target to depend on the copied files - add_custom_target(${TARGET_NAME}-copy-resources ALL - DEPENDS ${resource_outputs} - ) - endif() - -endfunction() - -function(inplace_build_copy TARGET_NAME INPLACE_DIR) - message(VERBOSE "Inplace build: (${TARGET_NAME}) ${INPLACE_DIR}") - - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy $ ${INPLACE_DIR} - COMMENT "Moving target ${TARGET_NAME} to ${INPLACE_DIR} for inplace build" - ) - - copy_target_resources(${TARGET_NAME} ${INPLACE_DIR}) - -endfunction() - -function(build_python_package PACKAGE_NAME) - - if(NOT PYTHON_ACTIVE_PACKAGE_NAME) - message(FATAL_ERROR "Must call create_python_package() before calling add_python_sources") - endif() - - if(NOT "${PACKAGE_NAME}-package" STREQUAL "${PYTHON_ACTIVE_PACKAGE_NAME}") - message(FATAL_ERROR "Mismatched package name supplied to create_python_package/build_python_package") - endif() - - set(flags BUILD_WHEEL INSTALL_WHEEL IS_INPLACE) - set(singleValues "") - set(multiValues PYTHON_DEPENDENCIES) - - include(CMakeParseArguments) - cmake_parse_arguments(_ARGS - "${flags}" - "${singleValues}" - "${multiValues}" - ${ARGN} - ) - - message(STATUS "Finalizing python package '${PACKAGE_NAME}'") - - get_target_property(sources_source_dir ${PYTHON_ACTIVE_PACKAGE_NAME}-sources SOURCE_DIR) - get_target_property(sources_binary_dir ${PYTHON_ACTIVE_PACKAGE_NAME}-sources BINARY_DIR) - - # First copy the source files - copy_target_resources(${PYTHON_ACTIVE_PACKAGE_NAME}-sources ${sources_binary_dir}) - - set(module_dependencies ${PYTHON_ACTIVE_PACKAGE_NAME}-sources-copy-resources) - - if(_ARGS_PYTHON_DEPENDENCIES) - list(APPEND module_dependencies ${_ARGS_PYTHON_DEPENDENCIES}) - endif() - - # Now ensure that the targets only get built after the files have been copied - add_dependencies(${PYTHON_ACTIVE_PACKAGE_NAME}-modules ${module_dependencies}) - - # Next step is to build the wheel file - if(_ARGS_BUILD_WHEEL) - set(wheel_stamp ${sources_binary_dir}/${PYTHON_ACTIVE_PACKAGE_NAME}-wheel.stamp) - - # The command to actually generate the wheel - add_custom_command( - OUTPUT ${wheel_stamp} - COMMAND python setup.py bdist_wheel - COMMAND ${CMAKE_COMMAND} -E touch ${wheel_stamp} - WORKING_DIRECTORY ${sources_binary_dir} - # Depend on any of the output python files - DEPENDS ${PYTHON_ACTIVE_PACKAGE_NAME}-outputs - COMMENT "Building ${PACKAGE_NAME} wheel" - ) - - # Create a dummy target to ensure the above custom command is always run - add_custom_target(${PYTHON_ACTIVE_PACKAGE_NAME}-wheel ALL - DEPENDS ${install_stamp} - ) - - message(STATUS "Creating python wheel for library '${PACKAGE_NAME}'") - endif() - - # Now build up the pip arguments to either install the package or print a message with the install command - set(_pip_command) - - list(APPEND _pip_command "${Python3_EXECUTABLE}" "-m" "pip" "install") - - # detect virtualenv and set Pip args accordingly - if(NOT DEFINED ENV{VIRTUAL_ENV} AND NOT DEFINED ENV{CONDA_PREFIX}) - list(APPEND _pip_command "--user") - endif() - - if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - list(APPEND _pip_command "-e") - endif() - - # Change which setup we use if we are using inplace - if(_ARGS_IS_INPLACE) - list(APPEND _pip_command "${sources_source_dir}") - else() - list(APPEND _pip_command "${sources_binary_dir}") - endif() - - if(_ARGS_INSTALL_WHEEL) - message(STATUS "Automatically installing Python package '${PACKAGE_NAME}' into current python environment. This may overwrite any existing library with the same name") - - # Now actually install the package - set(install_stamp ${sources_binary_dir}/${PYTHON_ACTIVE_PACKAGE_NAME}-install.stamp) - - add_custom_command( - OUTPUT ${install_stamp} - COMMAND ${_pip_command} - COMMAND ${CMAKE_COMMAND} -E touch ${install_stamp} - DEPENDS ${PYTHON_ACTIVE_PACKAGE_NAME}-outputs - COMMENT "Installing ${PACKAGE_NAME} python package" - ) - - add_custom_target(${PYTHON_ACTIVE_PACKAGE_NAME}-install ALL - DEPENDS ${install_stamp} - ) - else() - list(JOIN _pip_command " " _pip_command_str) - message(STATUS "Python package '${PACKAGE_NAME}' has been built but has not been installed. Use `${_pip_command_str}` to install the library manually") - endif() - - # Finally, unset the active package - unset(PYTHON_ACTIVE_PACKAGE_NAME PARENT_SCOPE) - - list(POP_BACK CMAKE_MESSAGE_CONTEXT) - set(CMAKE_MESSAGE_CONTEXT ${CMAKE_MESSAGE_CONTEXT} PARENT_SCOPE) - -endfunction() - - -#[=======================================================================[ -@brief : given a module name, and potentially a root path, resolves the -fully qualified python module path. If MODULE_ROOT is not provided, it -will default to ${CMAKE_CURRENT_SOURCE_DIR} -- the context of -the caller. - -ex. resolve_python_module_name(my_module MODULE_ROOT morpheus/_lib) -results -- - MODULE_TARGET_NAME: morpheus._lib.my_module - OUTPUT_MODULE_NAME: my_module - OUTPUT_RELATIVE_PATH: morpheus/_lib - -resolve_python_module_name - [MODULE_ROOT] - [OUTPUT_TARGET_NAME] - [OUTPUT_MODULE_NAME] - [OUTPUT_RELATIVE_PATH] -#]=======================================================================] - -function(resolve_python_module_name MODULE_NAME) - set(prefix _ARGS) # Prefix parsed args - set(flags "") - set(singleValues - MODULE_ROOT - OUTPUT_TARGET_NAME - OUTPUT_MODULE_NAME - OUTPUT_RELATIVE_PATH) - set(multiValues "") - - include(CMakeParseArguments) - cmake_parse_arguments(${prefix} - "${flags}" - "${singleValues}" - "${multiValues}" - ${ARGN}) - - set(py_module_name ${MODULE_NAME}) - set(py_module_namespace "") - set(py_module_path "") - - if(_ARGS_MODULE_ROOT) - file(RELATIVE_PATH py_module_path ${_ARGS_MODULE_ROOT} ${CMAKE_CURRENT_SOURCE_DIR}) - - if(NOT ${py_module_path} STREQUAL "") - # Convert the relative path to a namespace. i.e. `cuml/package/module` -> `cuml::package::module - # Always add a trailing / to ensure we end with a . - string(REPLACE "/" "." py_module_namespace "${py_module_path}/") - endif() - endif() - - if (_ARGS_OUTPUT_TARGET_NAME) - set(${_ARGS_OUTPUT_TARGET_NAME} "${py_module_namespace}${py_module_name}" PARENT_SCOPE) - endif() - if (_ARGS_OUTPUT_MODULE_NAME) - set(${_ARGS_OUTPUT_MODULE_NAME} "${py_module_name}" PARENT_SCOPE) - endif() - if (_ARGS_OUTPUT_RELATIVE_PATH) - set(${_ARGS_OUTPUT_RELATIVE_PATH} "${py_module_path}" PARENT_SCOPE) - endif() -endfunction() - -#[=======================================================================[ -@brief : TODO -ex. add_python_module -results -- - -add_python_module - -#]=======================================================================] -macro(_create_python_library MODULE_NAME) - - list(APPEND CMAKE_MESSAGE_CONTEXT "${MODULE_NAME}") - - if(NOT PYTHON_ACTIVE_PACKAGE_NAME) - message(FATAL_ERROR "Must call create_python_wheel() before calling add_python_sources") - endif() - - set(prefix _ARGS) - set(flags IS_PYBIND11 IS_CYTHON IS_MODULE COPY_INPLACE BUILD_STUBS) - set(singleValues INSTALL_DEST OUTPUT_TARGET MODULE_ROOT PYX_FILE) - set(multiValues INCLUDE_DIRS LINK_TARGETS SOURCE_FILES) - - include(CMakeParseArguments) - cmake_parse_arguments(${prefix} - "${flags}" - "${singleValues}" - "${multiValues}" - ${ARGN}) - - if(NOT _ARGS_MODULE_ROOT) - get_target_property(_ARGS_MODULE_ROOT ${PYTHON_ACTIVE_PACKAGE_NAME}-modules SOURCE_DIR) - endif() - - # Normalize the module root - cmake_path(SET _ARGS_MODULE_ROOT "${_ARGS_MODULE_ROOT}") - - resolve_python_module_name(${MODULE_NAME} - MODULE_ROOT ${_ARGS_MODULE_ROOT} - OUTPUT_TARGET_NAME TARGET_NAME - OUTPUT_MODULE_NAME MODULE_NAME - OUTPUT_RELATIVE_PATH SOURCE_RELATIVE_PATH - ) - - set(lib_type SHARED) - - if(_ARGS_IS_MODULE) - set(lib_type MODULE) - endif() - - # Create the module target - if(_ARGS_IS_PYBIND11) - message(VERBOSE "Adding Pybind11 Module: ${TARGET_NAME}") - pybind11_add_module(${TARGET_NAME} ${lib_type} ${_ARGS_SOURCE_FILES}) - elseif(_ARGS_IS_CYTHON) - message(VERBOSE "Adding Cython Module: ${TARGET_NAME}") - add_cython_target(${MODULE_NAME} "${_ARGS_PYX_FILE}" CXX PY3) - add_library(${TARGET_NAME} ${lib_type} ${${MODULE_NAME}} ${_ARGS_SOURCE_FILES}) - - # Need to set -fvisibility=hidden for cython according to https://pybind11.readthedocs.io/en/stable/faq.html - # set_target_properties(${TARGET_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden) - else() - message(FATAL_ERROR "Must specify either IS_PYBIND11 or IS_CYTHON") - endif() - - set_target_properties(${TARGET_NAME} PROPERTIES PREFIX "") - set_target_properties(${TARGET_NAME} PROPERTIES OUTPUT_NAME "${MODULE_NAME}") - - set(_link_libs "") - if(_ARGS_LINK_TARGETS) - foreach(target IN LISTS _ARGS_LINK_TARGETS) - list(APPEND _link_libs ${target}) - endforeach() - endif() - - target_link_libraries(${TARGET_NAME} - PUBLIC - ${_link_libs} - ) - - # Tell CMake to use relative paths in the build directory. This is necessary for relocatable packages - set_target_properties(${TARGET_NAME} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib:\$ORIGIN") - - if(_ARGS_INCLUDE_DIRS) - target_include_directories(${TARGET_NAME} - PRIVATE - "${_ARGS_INCLUDE_DIRS}" - ) - endif() - - # Cython targets need the current dir for generated files - if(_ARGS_IS_CYTHON) - target_include_directories(${TARGET_NAME} - PUBLIC - "${CMAKE_CURRENT_BINARY_DIR}" - ) - endif() - - # Set all_python_targets to depend on this module. This ensures that all python targets have been built before any - # post build actions are taken. This is often necessary to allow post build actions that load the python modules to - # succeed - add_dependencies(${PYTHON_ACTIVE_PACKAGE_NAME}-modules ${TARGET_NAME}) - - if(_ARGS_BUILD_STUBS) - # Get the relative path from the project source to the module root - cmake_path(RELATIVE_PATH _ARGS_MODULE_ROOT BASE_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE module_root_relative) - - cmake_path(APPEND PROJECT_BINARY_DIR ${module_root_relative} OUTPUT_VARIABLE module_root_binary_dir) - cmake_path(APPEND module_root_binary_dir ${SOURCE_RELATIVE_PATH} ${MODULE_NAME} "__init__.pyi" OUTPUT_VARIABLE module_binary_stub_file) - - # Before installing, create the custom command to generate the stubs - add_custom_command( - OUTPUT ${module_binary_stub_file} - COMMAND ${Python3_EXECUTABLE} -m pybind11_stubgen ${TARGET_NAME} --no-setup-py --log-level WARN -o ./ --root-module-suffix \"\" - DEPENDS ${PYTHON_ACTIVE_PACKAGE_NAME}-modules - COMMENT "Building stub for python module ${TARGET_NAME}..." - WORKING_DIRECTORY ${module_root_binary_dir} - ) - - # Add a custom target to ensure the stub generation runs - add_custom_target(${TARGET_NAME}-stubs ALL - DEPENDS ${module_binary_stub_file} - ) - - # Make the outputs depend on the stub - add_dependencies(${PYTHON_ACTIVE_PACKAGE_NAME}-outputs ${TARGET_NAME}-stubs) - - # Save the output as a target property - add_target_resources(TARGET_NAME ${TARGET_NAME} "${module_binary_stub_file}") - endif() - - if(_ARGS_INSTALL_DEST) - message(VERBOSE "Install dest: (${TARGET_NAME}) ${_ARGS_INSTALL_DEST}") - install( - TARGETS - ${TARGET_NAME} - EXPORT - ${PROJECT_NAME}-exports - LIBRARY - DESTINATION - "${_ARGS_INSTALL_DEST}" - COMPONENT Wheel - RESOURCE - DESTINATION - "${_ARGS_INSTALL_DEST}/${MODULE_NAME}" - COMPONENT Wheel - ) - endif() - - # Set the output target - if(_ARGS_OUTPUT_TARGET) - set(${_ARGS_OUTPUT_TARGET} "${TARGET_NAME}" PARENT_SCOPE) - endif() - - if(_ARGS_COPY_INPLACE) - # Copy the target inplace - inplace_build_copy(${TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - - list(POP_BACK CMAKE_MESSAGE_CONTEXT) - -endmacro() - -#[=======================================================================[ -@brief : TODO -ex. add_cython_library -results -- - -add_cython_library - -#]=======================================================================] -function(add_cython_library MODULE_NAME) - - _create_python_library(${MODULE_NAME} IS_CYTHON ${ARGN}) - -endfunction() - -#[=======================================================================[ -@brief : TODO -ex. add_pybind11_module -results -- - -add_pybind11_module - -#]=======================================================================] -function(add_pybind11_module MODULE_NAME) - - # Add IS_MODULE to make a MODULE instead of a SHARED - _create_python_library(${MODULE_NAME} IS_PYBIND11 IS_MODULE ${ARGN}) - -endfunction() - -#[=======================================================================[ -@brief : TODO -ex. add_pybind11_library -results -- - -add_pybind11_library - -#]=======================================================================] -function(add_pybind11_library MODULE_NAME) - - _create_python_library(${MODULE_NAME} IS_PYBIND11 ${ARGN}) - -endfunction() diff --git a/cmake/templates/run_ccache.sh.in b/cmake/templates/run_ccache.sh.in deleted file mode 100755 index 8577075bc..000000000 --- a/cmake/templates/run_ccache.sh.in +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Optionally, remove some arguments. For example, when using IWYU and ccache -# together, CMake passes `--driver-mode` which breaks gcc -ARGS_TO_REMOVE="@CCACHE_REMOVE_ARGS@" - -if [[ -n "$ARGS_TO_REMOVE" ]]; then - for arg in "$@"; do - shift - [[ "$arg" =~ $ARGS_TO_REMOVE ]] && continue - set -- "$@" "$arg" - done -fi - -# Set a default for CCACHE_BASEDIR. Allows overriding during build phase -export CCACHE_BASEDIR=${CCACHE_BASEDIR:-"@CCACHE_BASEDIR@"} -export CCACHE_CONFIGPATH=${CCACHE_CONFIGPATH:-"@CCACHE_CONFIGPATH@"} -export CCACHE_SLOPPINESS="system_headers" -export CCACHE_COMPILERTYPE="@CCACHE_COMPILERTYPE@" - -# Uncomment the following to enable debug logs -# export CCACHE_DEBUG=1 -# export CCACHE_DEBUGDIR="@CMAKE_CURRENT_BINARY_DIR@/ccache_debug" - -# Allows running ccache with options inside of CMake. CMake does not work well -# with setting variables before calling a command -@CCACHE_PROGRAM_PATH@ "$@" diff --git a/cmake/templates/run_ccache_prefix.sh.in b/cmake/templates/run_ccache_prefix.sh.in deleted file mode 100755 index f1c223502..000000000 --- a/cmake/templates/run_ccache_prefix.sh.in +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# The first argument is treated as the prefix command to run -export CCACHE_PREFIX="$1" - -shift - -# Pass all remaining arguments to ccache -${MRC_CCACHE_WRAPPER} "$@" diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index 474a6cbba..b9ce82a3e 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -35,7 +35,7 @@ rapids_cpm_init() # Set the option prefix to match the outer project before including. Must be before find_package(mrc) set(OPTION_PREFIX "MRC") -include(python_module_tools) +include(morpheus_utils/python/module_tools) rapids_find_package(mrc REQUIRED) rapids_find_package(CUDAToolkit REQUIRED) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index faac1b284..59616a5d7 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -17,7 +17,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "python") find_package(CUDAToolkit REQUIRED) -include(python_module_tools) +include(morpheus_utils/python/module_tools) # Create the mrc python package create_python_package(mrc) From e1491256c3d55125995c71ab0e40473062661fdb Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 1 Dec 2022 11:38:32 -0700 Subject: [PATCH 10/55] Checkpoint --- CMakeLists.txt | 26 +++++++++++-------- .../{setup_ccache.cmake => init_ccache.cmake} | 4 +-- ...tup_compiler.cmake => init_compiler.cmake} | 0 ...tup_coverage.cmake => init_coverage.cmake} | 2 +- .../{setup_iwyu.cmake => init_iwyu.cmake} | 2 +- cmake/templates/run_iwyu.sh.in | 19 -------------- cmake/vcpkg_triplets/x64-linux-dynamic.cmake | 23 ---------------- 7 files changed, 19 insertions(+), 57 deletions(-) rename cmake/environment/{setup_ccache.cmake => init_ccache.cmake} (90%) rename cmake/environment/{setup_compiler.cmake => init_compiler.cmake} (100%) rename cmake/environment/{setup_coverage.cmake => init_coverage.cmake} (97%) rename cmake/environment/{setup_iwyu.cmake => init_iwyu.cmake} (96%) delete mode 100755 cmake/templates/run_iwyu.sh.in delete mode 100644 cmake/vcpkg_triplets/x64-linux-dynamic.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3470a5076..e5fbd2b6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,11 +27,12 @@ option(MRC_BUILD_DOCS "Enable building of API documentation" OFF) option(MRC_BUILD_LIBRARY "Whether the entire MRC library should be built. If set to OFF, only the pieces needed for a target will be built. Set to ON if installing the library" ON) option(MRC_BUILD_PYTHON "Enable building the python bindings for MRC" ON) option(MRC_BUILD_TESTS "Whether or not to build MRC tests" ON) +option(MRC_ENABLE_CODECOV "Enable gcov code coverage" OFF) +option(MRC_ENABLE_DEBUG_INFO "Enable printing debug information" OFF) option(MRC_USE_CCACHE "Enable caching compilation results with ccache" OFF) option(MRC_USE_CLANG_TIDY "Enable running clang-tidy as part of the build process" OFF) option(MRC_USE_CONDA "Enables finding dependencies via conda instead of vcpkg. Note: This will disable vcpkg. All dependencies must be installed first in the conda environment" ON) option(MRC_USE_IWYU "Enable running include-what-you-use as part of the build process" OFF) -option(MRC_ENABLE_CODECOV "Enable gcov code coverage" OFF) set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build for. Sets default versions for RAPIDS CMake and RMM.") @@ -56,14 +57,14 @@ find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") # Import morpheus_utils APIs -include(morpheus_utils/environment_config/api) -include(morpheus_utils/package_config/api) +include(morpheus_utils/environment_config/register_api) +include(morpheus_utils/package_config/register_api) # Configure rapids CMake -morpheus_utils_configure_rapids_cmake(MRC_RAPIDS_VERSION) +morpheus_utils_initialize_rapids_cmake(MRC_RAPIDS_VERSION) # Configure project package manager -morpheus_utils_configure_package_manager( +morpheus_utils_initialize_package_manager( MRC_USE_CONDA MRC_VCPKG_TOOLCHAIN MRC_VCPKG_DEFAULT_BINARY_CACHE @@ -116,7 +117,7 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Setup cache before dependencies # Configure CCache if requested -include(environment/setup_ccache) +include(environment/init_ccache) # Configure conda if(MRC_USE_CONDA AND DEFINED ENV{CONDA_PREFIX}) @@ -151,13 +152,13 @@ add_subdirectory(protos) # ################################### # - Post dependencies setup -------- -include(environment/setup_compiler) +include(environment/init_compiler) # Setup code coverage components -include(environment/setup_coverage) +include(environment/init_coverage) # Setup IWYU if enabled -include(environment/setup_iwyu) +include(environment/init_iwyu) # ################################### # - Begin MRC Targets -------------- @@ -430,6 +431,9 @@ endif() add_subdirectory(src/tools) # Uncomment the following to print all available targets -#include(morpheus_utils/source/utils/debug) -#morpheus_utils_print_all_targets() +if (MRC_ENABLE_DEBUG_INFO) + include(morpheus_utils/general/cmake_project_debug_utils) + morpheus_utils_print_all_targets() +endif() + list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/cmake/environment/setup_ccache.cmake b/cmake/environment/init_ccache.cmake similarity index 90% rename from cmake/environment/setup_ccache.cmake rename to cmake/environment/init_ccache.cmake index 09167617e..2e84c6476 100644 --- a/cmake/environment/setup_ccache.cmake +++ b/cmake/environment/init_ccache.cmake @@ -21,9 +21,9 @@ morpheus_utils_check_cache_path(MRC_CACHE_DIR) # Configure CCache if requested if(MRC_USE_CCACHE) - morpheus_utils_configure_ccache(MRC_CACHE_DIR) + morpheus_utils_initialize_ccache(MRC_CACHE_DIR) endif() -morpheus_utils_configure_cpm(MRC_CACHE_DIR) +morpheus_utils_initialize_cpm(MRC_CACHE_DIR) list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/cmake/environment/setup_compiler.cmake b/cmake/environment/init_compiler.cmake similarity index 100% rename from cmake/environment/setup_compiler.cmake rename to cmake/environment/init_compiler.cmake diff --git a/cmake/environment/setup_coverage.cmake b/cmake/environment/init_coverage.cmake similarity index 97% rename from cmake/environment/setup_coverage.cmake rename to cmake/environment/init_coverage.cmake index 14ac68b8e..ca1e10d80 100644 --- a/cmake/environment/setup_coverage.cmake +++ b/cmake/environment/init_coverage.cmake @@ -22,7 +22,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "coverage") # Include coverage tools if enabled if(MRC_ENABLE_CODECOV) - include(morpheus_utils/source/utils/code_coverage/setup) + include(morpheus_utils/environment_config/code_coverage/init_coverage) message(STATUS "MRC_ENABLE_CODECOV is ON, configuring report exclusions and setting up coverage build targets") set(CODECOV_REPORT_EXCLUSIONS diff --git a/cmake/environment/setup_iwyu.cmake b/cmake/environment/init_iwyu.cmake similarity index 96% rename from cmake/environment/setup_iwyu.cmake rename to cmake/environment/init_iwyu.cmake index ef2b2c55d..c2f93241f 100644 --- a/cmake/environment/setup_iwyu.cmake +++ b/cmake/environment/init_iwyu.cmake @@ -16,7 +16,7 @@ # ============================================================================= if(MRC_USE_IWYU) - morpheus_utils_configure_iwyu( + morpheus_utils_initialize_iwyu( MRC_USE_IWYU MRC_IWYU_VERBOSITY MRC_IWYU_PROGRAM diff --git a/cmake/templates/run_iwyu.sh.in b/cmake/templates/run_iwyu.sh.in deleted file mode 100755 index 0c7762bc4..000000000 --- a/cmake/templates/run_iwyu.sh.in +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -# Allows running ccache with options inside of CMake. CMake does not work well -# with setting variables before calling a command -${MRC_IWYU_PROGRAM} ${MRC_IWYU_OPTIONS} "$@" diff --git a/cmake/vcpkg_triplets/x64-linux-dynamic.cmake b/cmake/vcpkg_triplets/x64-linux-dynamic.cmake deleted file mode 100644 index b2a029000..000000000 --- a/cmake/vcpkg_triplets/x64-linux-dynamic.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022,NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -set(VCPKG_TARGET_ARCHITECTURE x64) -set(VCPKG_CRT_LINKAGE dynamic) -set(VCPKG_LIBRARY_LINKAGE dynamic) - -set(VCPKG_CMAKE_SYSTEM_NAME Linux) - -# Set the RPATH to allow finding other libraries in the same folder -set(VCPKG_LINKER_FLAGS "-Wl,-rpath,'$ORIGIN':'$ORIGIN/../lib'") From 5fc22b2923bba5c7fc64e631d1157c5bc57275af Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 1 Dec 2022 13:37:15 -0700 Subject: [PATCH 11/55] Cleanup and modularize loader scripts --- CMakeLists.txt | 12 ++--------- cmake/environment/init_coverage.cmake | 2 -- cmake/load_morpheus_utils.cmake | 15 +++---------- docs/quickstart/hybrid/CMakeLists.txt | 4 ++-- .../mrc_qs_hybrid/common/CMakeLists.txt | 8 +++---- .../ex00_wrap_data_objects/CMakeLists.txt | 4 ++-- .../ex01_wrap_nodes/CMakeLists.txt | 4 ++-- docs/quickstart/python/CMakeLists.txt | 4 ++-- python/CMakeLists.txt | 21 +++++++++++++++---- python/mrc/tests/CMakeLists.txt | 5 +---- 10 files changed, 35 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5fbd2b6b..46ef6c4a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,16 +52,9 @@ list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Load morpheus utils and update CMake paths set(MORPHEUS_UTILS_VERSION "0.1" CACHE STRING "Version of Morpheus utils") +set(MORPHEUS_UTILS_RAPIDS_CMAKE_VERSION ${MRC_RAPIDS_VERSION}) +set(MORPHEUS_UTILS_RAPIDS_CPM_INIT_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") include(load_morpheus_utils) -find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) -list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") - -# Import morpheus_utils APIs -include(morpheus_utils/environment_config/register_api) -include(morpheus_utils/package_config/register_api) - -# Configure rapids CMake -morpheus_utils_initialize_rapids_cmake(MRC_RAPIDS_VERSION) # Configure project package manager morpheus_utils_initialize_package_manager( @@ -432,7 +425,6 @@ add_subdirectory(src/tools) # Uncomment the following to print all available targets if (MRC_ENABLE_DEBUG_INFO) - include(morpheus_utils/general/cmake_project_debug_utils) morpheus_utils_print_all_targets() endif() diff --git a/cmake/environment/init_coverage.cmake b/cmake/environment/init_coverage.cmake index ca1e10d80..5092ccc3c 100644 --- a/cmake/environment/init_coverage.cmake +++ b/cmake/environment/init_coverage.cmake @@ -22,8 +22,6 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "coverage") # Include coverage tools if enabled if(MRC_ENABLE_CODECOV) - include(morpheus_utils/environment_config/code_coverage/init_coverage) - message(STATUS "MRC_ENABLE_CODECOV is ON, configuring report exclusions and setting up coverage build targets") set(CODECOV_REPORT_EXCLUSIONS "${CMAKE_BINARY_DIR}/protos/*" # Remove this if/when we get protobuf code unit tested. diff --git a/cmake/load_morpheus_utils.cmake b/cmake/load_morpheus_utils.cmake index 505be66cd..266e5c4a6 100644 --- a/cmake/load_morpheus_utils.cmake +++ b/cmake/load_morpheus_utils.cmake @@ -18,18 +18,6 @@ include_guard() include(FetchContent) -function(setup_package_tests TEST_VAR_NAME) - set(TEST_VAR_VALUE ${${TEST_VAR_NAME}}) - if (TEST_VAR_VALUE) - message(STATUS "++++++++++++++ TEST_VAR IS ON '${TEST_VAR_VALUE}'") - else() - message(STATUS "++++++++++++++ TEST_VAR IS OFF '${TEST_VAR_VALUE}'") - endif() - message(STATUS "====================> CALLED '${TEST_VAR_NAME}'") - set(test_thing "a b c") - message(STATUS ${test_thing}) -endfunction() - # Fetch morpheus utilities -- don't use CPM, RAPIDS_CPM, or other external libraries here so # we are only relying on CMake to get our core utilities. function(find_and_configure_morpheus_utils version) @@ -55,3 +43,6 @@ function(find_and_configure_morpheus_utils version) endfunction() find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) + +list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") +include(morpheus_utils/load) diff --git a/docs/quickstart/hybrid/CMakeLists.txt b/docs/quickstart/hybrid/CMakeLists.txt index 1da80a33f..2a105988d 100644 --- a/docs/quickstart/hybrid/CMakeLists.txt +++ b/docs/quickstart/hybrid/CMakeLists.txt @@ -17,7 +17,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "hybrid") set(QUICKSTART_HYBRID_HOME "${CMAKE_CURRENT_SOURCE_DIR}") -create_python_package(mrc_qs_hybrid) +morpheus_utils_create_python_package(mrc_qs_hybrid) add_subdirectory(mrc_qs_hybrid/common) @@ -34,6 +34,6 @@ if(TARGET mrc-package-install) list(APPEND extra_args "PYTHON_DEPENDENCIES" "mrc-package-install") endif() -build_python_package(mrc_qs_hybrid ${extra_args}) +morpheus_utils_build_python_package(mrc_qs_hybrid ${extra_args}) list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt index c65401258..5d4453fe6 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_pybind11_library( +morpheus_utils_add_pybind11_library( data # MODULE_ROOT # ${QUICKSTART_HYBRID_HOME} @@ -30,9 +30,9 @@ target_include_directories(${common_data_target} ./include ) -inplace_build_copy(${common_data_target} ${CMAKE_CURRENT_SOURCE_DIR}) +morpheus_utils_inplace_build_copy(${common_data_target} ${CMAKE_CURRENT_SOURCE_DIR}) -add_pybind11_library( +morpheus_utils_add_pybind11_library( nodes SOURCE_FILES nodes.cpp @@ -42,7 +42,7 @@ add_pybind11_library( nodes_data_target ) -inplace_build_copy(${nodes_data_target} ${CMAKE_CURRENT_SOURCE_DIR}) +morpheus_utils_inplace_build_copy(${nodes_data_target} ${CMAKE_CURRENT_SOURCE_DIR}) # Set this variable in the parent scope so other examples can link to it set(common_data_target ${common_data_target} PARENT_SCOPE) diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt index 18723f68c..12b24787c 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_pybind11_module( +morpheus_utils_add_pybind11_module( data MODULE_ROOT ${QUICKSTART_HYBRID_HOME} @@ -25,4 +25,4 @@ add_pybind11_module( data_target ) -inplace_build_copy(${data_target} ${CMAKE_CURRENT_SOURCE_DIR}) +morpheus_utils_inplace_build_copy(${data_target} ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt index 9a1633f0a..0f42b7c21 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_pybind11_module( +morpheus_utils_add_pybind11_module( nodes MODULE_ROOT ${QUICKSTART_HYBRID_HOME} @@ -25,4 +25,4 @@ add_pybind11_module( nodes_target ) -inplace_build_copy(${nodes_target} ${CMAKE_CURRENT_SOURCE_DIR}) +morpheus_utils_inplace_build_copy(${nodes_target} ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/docs/quickstart/python/CMakeLists.txt b/docs/quickstart/python/CMakeLists.txt index b703cadb7..c08024524 100644 --- a/docs/quickstart/python/CMakeLists.txt +++ b/docs/quickstart/python/CMakeLists.txt @@ -17,7 +17,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "python") set(QUICKSTART_PYTHON_HOME "${CMAKE_CURRENT_SOURCE_DIR}") -create_python_package(mrc_qs_python) +morpheus_utils_create_python_package(mrc_qs_python) set(extra_args "IS_INPLACE") @@ -29,6 +29,6 @@ if(TARGET mrc-package-install) list(APPEND extra_args "PYTHON_DEPENDENCIES" "mrc-package-install") endif() -build_python_package(mrc_qs_python ${extra_args}) +morpheus_utils_build_python_package(mrc_qs_python ${extra_args}) list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 59616a5d7..5b1ce3728 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -17,13 +17,26 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "python") find_package(CUDAToolkit REQUIRED) +# Get the project name in uppercase if OPTION_PREFIX is not defined +if(NOT DEFINED OPTION_PREFIX) + string(TOUPPER "${PROJECT_NAME}" OPTION_PREFIX) +endif() + +option(${OPTION_PREFIX}_PYTHON_INPLACE_BUILD "Whether or not to copy built python modules back to the source tree for debug purposes." OFF) +option(${OPTION_PREFIX}_PYTHON_PERFORM_INSTALL "Whether or not to automatically `pip install` any built python library. WARNING: This may overwrite any existing installation of the same name." OFF) +option(${OPTION_PREFIX}_PYTHON_BUILD_STUBS "Whether or not to generated .pyi stub files for C++ Python modules. Disable to avoid requiring loading the NVIDIA GPU Driver during build" ON) + +set(Python3_FIND_VIRTUALENV "FIRST") +set(Python3_FIND_STRATEGY "LOCATION") + include(morpheus_utils/python/module_tools) +morpheus_utils_print_python_info() # Create the mrc python package -create_python_package(mrc) +morpheus_utils_create_python_package(mrc) # Add a few additional files to be copied -add_python_sources("pytest.ini" "tests/string_reader_input.txt") +morpheus_utils_add_python_sources("pytest.ini" "tests/string_reader_input.txt") # Save the root of the python for relative paths set(MRC_PY_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) @@ -43,7 +56,7 @@ macro(mrc_add_pybind11_module) endif() # Forward all common arguments plus any arguments passed in - add_pybind11_module(${ARGN} ${_common_args}) + morpheus_utils_add_pybind11_module(${ARGN} ${_common_args}) endmacro() add_subdirectory(mrc/_pymrc) @@ -67,6 +80,6 @@ if(MRC_PYTHON_PERFORM_INSTALL) list(APPEND extra_args "INSTALL_WHEEL") endif() -build_python_package(mrc ${extra_args}) +morpheus_utils_build_python_package(mrc ${extra_args}) list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/python/mrc/tests/CMakeLists.txt b/python/mrc/tests/CMakeLists.txt index 071f4bae6..b712a888e 100644 --- a/python/mrc/tests/CMakeLists.txt +++ b/python/mrc/tests/CMakeLists.txt @@ -17,9 +17,6 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "tests") mrc_add_pybind11_module(test_edges_cpp SOURCE_FILES test_edges.cpp) mrc_add_pybind11_module(sample_modules SOURCE_FILES sample_modules.cpp) - -mrc_add_pybind11_module(utils - SOURCE_FILES utils.cpp -) +mrc_add_pybind11_module(utils SOURCE_FILES utils.cpp) list(POP_BACK CMAKE_MESSAGE_CONTEXT) From 838dd647456bf8d91f51fe282321e942d7d0831d Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 1 Dec 2022 13:54:24 -0700 Subject: [PATCH 12/55] Shift to github pull -- in a good POC state --- CMakeLists.txt | 3 +-- cmake/load_morpheus_utils.cmake | 3 ++- docs/quickstart/CMakeLists.txt | 2 +- python/CMakeLists.txt | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 46ef6c4a5..333ac0cbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,6 @@ option(MRC_USE_CONDA "Enables finding dependencies via conda instead of vcpkg. N option(MRC_USE_IWYU "Enable running include-what-you-use as part of the build process" OFF) set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build for. Sets default versions for RAPIDS CMake and RMM.") - set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) @@ -51,7 +50,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Load morpheus utils and update CMake paths -set(MORPHEUS_UTILS_VERSION "0.1" CACHE STRING "Version of Morpheus utils") +set(MORPHEUS_UTILS_VERSION "23.01.00-alpha" CACHE STRING "Version of Morpheus utils") set(MORPHEUS_UTILS_RAPIDS_CMAKE_VERSION ${MRC_RAPIDS_VERSION}) set(MORPHEUS_UTILS_RAPIDS_CPM_INIT_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") include(load_morpheus_utils) diff --git a/cmake/load_morpheus_utils.cmake b/cmake/load_morpheus_utils.cmake index 266e5c4a6..2995964cd 100644 --- a/cmake/load_morpheus_utils.cmake +++ b/cmake/load_morpheus_utils.cmake @@ -31,7 +31,8 @@ function(find_and_configure_morpheus_utils version) FetchContent_Declare( morpheus_utils - GIT_REPOSITORY /home/drobison/Development/devin-morpheus-utils-public + # TODO(Devin): Change to https once utilities is public. + GIT_REPOSITORY git@github.com:nv-morpheus/utilities.git GIT_TAG v${version} GIT_SHALLOW TRUE ) diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index b9ce82a3e..d212c92f4 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -35,7 +35,7 @@ rapids_cpm_init() # Set the option prefix to match the outer project before including. Must be before find_package(mrc) set(OPTION_PREFIX "MRC") -include(morpheus_utils/python/module_tools) +include(morpheus_utils/python/register_api) rapids_find_package(mrc REQUIRED) rapids_find_package(CUDAToolkit REQUIRED) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 5b1ce3728..31b063418 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -29,7 +29,7 @@ option(${OPTION_PREFIX}_PYTHON_BUILD_STUBS "Whether or not to generated .pyi stu set(Python3_FIND_VIRTUALENV "FIRST") set(Python3_FIND_STRATEGY "LOCATION") -include(morpheus_utils/python/module_tools) +include(morpheus_utils/python/register_api) morpheus_utils_print_python_info() # Create the mrc python package From 693fda2c9a8df4ceaf1a8b518464b36b31041c24 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 2 Dec 2022 12:02:30 -0700 Subject: [PATCH 13/55] Baseline conversion to utilities library works --- CMakeLists.txt | 42 ++++++++++++--------------------- cmake/load_morpheus_utils.cmake | 2 +- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 333ac0cbc..a988d41fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,11 +38,7 @@ set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build fo set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) -project(mrc - VERSION 22.11.00 - LANGUAGES C CXX - ) - +enable_language(C CXX) # TODO(Devin): temp work around enable_testing() # CMake path @@ -50,25 +46,27 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Load morpheus utils and update CMake paths -set(MORPHEUS_UTILS_VERSION "23.01.00-alpha" CACHE STRING "Version of Morpheus utils") +set(MORPHEUS_UTILS_VERSION "23.01.01-alpha" CACHE STRING "Version of Morpheus utils") set(MORPHEUS_UTILS_RAPIDS_CMAKE_VERSION ${MRC_RAPIDS_VERSION}) set(MORPHEUS_UTILS_RAPIDS_CPM_INIT_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") include(load_morpheus_utils) # Configure project package manager -morpheus_utils_initialize_package_manager( +morpheus_utils_initialize_package_manager_2( MRC_USE_CONDA + BUILD_SHARED_LIBS MRC_VCPKG_TOOLCHAIN MRC_VCPKG_DEFAULT_BINARY_CACHE ) -# Default to using "NATIVE" for CUDA_ARCHITECTURES to build based on GPU in system -if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES) - set(CMAKE_CUDA_ARCHITECTURES "NATIVE") - message(STATUS "CMAKE_CUDA_ARCHITECTURES was not defined. Defaulting to '${CMAKE_CUDA_ARCHITECTURES}' to build only for local architecture. Specify -DCMAKE_CUDA_ARCHITECTURES='ALL' to build for all archs.") -endif() +# Configure CUDA architecture +# NOTE: This MUST occur before any 'project' calls because of rapids_cmake requirements. +morpheus_utils_initialize_cuda_arch(mrc) -rapids_cuda_init_architectures(mrc) +project(mrc + VERSION 22.11.00 + LANGUAGES C CXX + ) rapids_cmake_write_version_file(${CMAKE_BINARY_DIR}/autogenerated/include/mrc/version.hpp) # Delay enabling CUDA until after we have determined our CXX compiler @@ -111,16 +109,6 @@ set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # Configure CCache if requested include(environment/init_ccache) -# Configure conda -if(MRC_USE_CONDA AND DEFINED ENV{CONDA_PREFIX}) - rapids_cmake_support_conda_env(conda_env MODIFY_PREFIX_PATH) - - if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND DEFINED ENV{CONDA_PREFIX}) - message(STATUS "No CMAKE_INSTALL_PREFIX argument detected, setting to: $ENV{CONDA_PREFIX}") - set(CMAKE_INSTALL_PREFIX "$ENV{CONDA_PREFIX}" CACHE STRING "" FORCE) - endif() -endif() - # Disable exporting compile commands for dependencies set(CMAKE_EXPORT_COMPILE_COMMANDS OFF) @@ -330,11 +318,11 @@ target_link_libraries(libmrc target_include_directories(libmrc PUBLIC - $ - $ - $ + $ + $ + $ PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/src ) target_compile_definitions(libmrc diff --git a/cmake/load_morpheus_utils.cmake b/cmake/load_morpheus_utils.cmake index 2995964cd..307b8692d 100644 --- a/cmake/load_morpheus_utils.cmake +++ b/cmake/load_morpheus_utils.cmake @@ -32,7 +32,7 @@ function(find_and_configure_morpheus_utils version) FetchContent_Declare( morpheus_utils # TODO(Devin): Change to https once utilities is public. - GIT_REPOSITORY git@github.com:nv-morpheus/utilities.git + GIT_REPOSITORY /home/drobison/Development/devin-morpheus-utils-public GIT_TAG v${version} GIT_SHALLOW TRUE ) From 5077eff26051c864b4f4f5f3ffbe0035c43bbc3c Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 2 Dec 2022 14:11:46 -0700 Subject: [PATCH 14/55] More consolidation updates --- cmake/dependencies.cmake | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 2abe4394c..90d9cac46 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -15,9 +15,6 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "dep") -# Initialize rapids CPM with package overrides -rapids_cpm_init(OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") - # Print CMake settings when verbose output is enabled message(VERBOSE "PROJECT_NAME: " ${PROJECT_NAME}) message(VERBOSE "CMAKE_HOST_SYSTEM: ${CMAKE_HOST_SYSTEM}") From 63a02c3e806305ee9c3caadf5c3ed0de197455fd Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 2 Dec 2022 15:01:28 -0700 Subject: [PATCH 15/55] Switch package manager calls and manualy code coverage intialization --- CMakeLists.txt | 3 +-- cmake/environment/init_coverage.cmake | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a988d41fc..565bf93ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,6 @@ set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build fo set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) -enable_language(C CXX) # TODO(Devin): temp work around enable_testing() # CMake path @@ -52,7 +51,7 @@ set(MORPHEUS_UTILS_RAPIDS_CPM_INIT_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/r include(load_morpheus_utils) # Configure project package manager -morpheus_utils_initialize_package_manager_2( +morpheus_utils_initialize_package_manager( MRC_USE_CONDA BUILD_SHARED_LIBS MRC_VCPKG_TOOLCHAIN diff --git a/cmake/environment/init_coverage.cmake b/cmake/environment/init_coverage.cmake index 5092ccc3c..67fa440bd 100644 --- a/cmake/environment/init_coverage.cmake +++ b/cmake/environment/init_coverage.cmake @@ -23,6 +23,8 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "coverage") # Include coverage tools if enabled if(MRC_ENABLE_CODECOV) message(STATUS "MRC_ENABLE_CODECOV is ON, configuring report exclusions and setting up coverage build targets") + morpheus_utils_initialize_code_coverage() + set(CODECOV_REPORT_EXCLUSIONS "${CMAKE_BINARY_DIR}/protos/*" # Remove this if/when we get protobuf code unit tested. "benchmarks/*" # Remove this if/when we get protobuf code unit tested. From f07f126083dcacae256dcaf5a6cef6fce482a4d7 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 5 Dec 2022 13:45:38 -0700 Subject: [PATCH 16/55] Remove VCPKG references --- .dockerignore | 1 - .gitignore | 1 - CMakeLists.txt | 20 ++++++-------------- vcpkg.json | 19 ------------------- 4 files changed, 6 insertions(+), 35 deletions(-) delete mode 100644 vcpkg.json diff --git a/.dockerignore b/.dockerignore index d1a0b73ca..0305b35ad 100755 --- a/.dockerignore +++ b/.dockerignore @@ -5,4 +5,3 @@ models @eaDir __pycache__ bazel-* -./vcpkg_installed diff --git a/.gitignore b/.gitignore index c7926ffc4..1a20325a2 100755 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ *.engine .Dockerfile .gitignore -/vcpkg_installed /*conda-bld*/ # Ignore generated pyi files for pybind and cython modules diff --git a/CMakeLists.txt b/CMakeLists.txt index 565bf93ab..604eb6056 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,17 +24,20 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "mrc") option(BUILD_SHARED_LIBS "Default value for whether or not to build shared or static libraries" ON) option(MRC_BUILD_BENCHMARKS "Whether or not to build MRC benchmarks" OFF) option(MRC_BUILD_DOCS "Enable building of API documentation" OFF) -option(MRC_BUILD_LIBRARY "Whether the entire MRC library should be built. If set to OFF, only the pieces needed for a target will be built. Set to ON if installing the library" ON) +option(MRC_BUILD_LIBRARY "Whether the entire MRC library should be built. + If set to OFF, only the pieces needed for a target will be built. Set to ON if installing the library" ON) option(MRC_BUILD_PYTHON "Enable building the python bindings for MRC" ON) option(MRC_BUILD_TESTS "Whether or not to build MRC tests" ON) option(MRC_ENABLE_CODECOV "Enable gcov code coverage" OFF) option(MRC_ENABLE_DEBUG_INFO "Enable printing debug information" OFF) option(MRC_USE_CCACHE "Enable caching compilation results with ccache" OFF) option(MRC_USE_CLANG_TIDY "Enable running clang-tidy as part of the build process" OFF) -option(MRC_USE_CONDA "Enables finding dependencies via conda instead of vcpkg. Note: This will disable vcpkg. All dependencies must be installed first in the conda environment" ON) +option(MRC_USE_CONDA "Enables finding dependencies via conda. All dependencies must be installed first in the conda + environment" ON) option(MRC_USE_IWYU "Enable running include-what-you-use as part of the build process" OFF) -set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build for. Sets default versions for RAPIDS CMake and RMM.") +set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build for. + Sets default versions for RAPIDS CMake and RMM.") set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) @@ -54,8 +57,6 @@ include(load_morpheus_utils) morpheus_utils_initialize_package_manager( MRC_USE_CONDA BUILD_SHARED_LIBS - MRC_VCPKG_TOOLCHAIN - MRC_VCPKG_DEFAULT_BINARY_CACHE ) # Configure CUDA architecture @@ -89,15 +90,6 @@ set(MRC_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) # Set a default build type if none was specified rapids_cmake_build_type(Release) -# Once the build type is set, remove any dumb vcpkg debug folders from the -# search paths. Without this FindBoost fails since it defaults to the debug -# binaries -if(DEFINED CACHE{MRC_VCPKG_TOOLCHAIN} AND DEFINED CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$") - message(STATUS "Release Build: Removing debug Vcpkg paths from CMAKE_PREFIX_PATH and CMAKE_FIND_ROOT_PATH") - list(REMOVE_ITEM CMAKE_PREFIX_PATH "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug") - list(REMOVE_ITEM CMAKE_FIND_ROOT_PATH "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug") -endif() - set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) diff --git a/vcpkg.json b/vcpkg.json deleted file mode 100644 index 921f0ab5a..000000000 --- a/vcpkg.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", - "name": "mrc", - "version": "0.1.0", - "description": "NVIDIA Morpheus Runtime Core", - "dependencies": [ - "benchmark", - "boost-fiber", - "boost-filesystem", - "boost-hana", - "boost-histogram", - "gflags", - "glog", - "grpc", - "gtest", - "nlohmann-json" - ], - "builtin-baseline": "bedae7b82046b49c33b49ba57b5b9dc1df811247" -} From f1d60e8fc5278d91a535ab70a71e6f150a447be7 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 5 Dec 2022 15:19:11 -0700 Subject: [PATCH 17/55] Switch to utilities as a submodule and updated package configuration API --- .gitmodules | 4 + CMakeLists.txt | 4 +- cmake/GRPCGenerateCPP.cmake | 131 -------------------------------- cmake/dependencies.cmake | 23 ++---- cmake/load_morpheus_utils.cmake | 49 ------------ protos/CMakeLists.txt | 3 +- utilities | 1 + 7 files changed, 17 insertions(+), 198 deletions(-) create mode 100644 .gitmodules delete mode 100644 cmake/GRPCGenerateCPP.cmake delete mode 100644 cmake/load_morpheus_utils.cmake create mode 160000 utilities diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..385ab00e4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "utilities"] + path = utilities + url = git@github.com:nv-morpheus/utilities.git + branch = devin-issue-225-87 diff --git a/CMakeLists.txt b/CMakeLists.txt index 604eb6056..28b4424b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,17 +41,19 @@ set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build fo set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) +enable_language(C CXX) enable_testing() # CMake path list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/utilities/cmake") list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") # Load morpheus utils and update CMake paths set(MORPHEUS_UTILS_VERSION "23.01.01-alpha" CACHE STRING "Version of Morpheus utils") set(MORPHEUS_UTILS_RAPIDS_CMAKE_VERSION ${MRC_RAPIDS_VERSION}) set(MORPHEUS_UTILS_RAPIDS_CPM_INIT_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") -include(load_morpheus_utils) +include(morpheus_utils/load) # Configure project package manager morpheus_utils_initialize_package_manager( diff --git a/cmake/GRPCGenerateCPP.cmake b/cmake/GRPCGenerateCPP.cmake deleted file mode 100644 index 7e864321e..000000000 --- a/cmake/GRPCGenerateCPP.cmake +++ /dev/null @@ -1,131 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2018-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - - -# Separate the output files from protobuf_generate into src, headers and descriptors. Taken from PROTOBUF_GENERATE_CPP -function(protobuf_separate_output output_files) - - cmake_parse_arguments(protobuf_separate_output "" "HDRS;SRCS;DESCRIPTORS" "" "${ARGN}") - - set(SRCS "") - set(HDRS "") - set(DESCRIPTORS "") - - foreach(_file ${output_files}) - if(_file MATCHES "cc$") - list(APPEND SRCS ${_file}) - elseif(_file MATCHES "desc$") - list(APPEND DESCRIPTORS ${_file}) - else() - list(APPEND HDRS ${_file}) - endif() - endforeach() - - if (protobuf_separate_output_HDRS) - list(APPEND ${protobuf_separate_output_HDRS} ${HDRS}) - list(REMOVE_DUPLICATES ${protobuf_separate_output_HDRS}) - set(${protobuf_separate_output_HDRS} ${${protobuf_separate_output_HDRS}} PARENT_SCOPE) - endif() - if (protobuf_separate_output_SRCS) - list(APPEND ${protobuf_separate_output_SRCS} ${SRCS}) - list(REMOVE_DUPLICATES ${protobuf_separate_output_SRCS}) - set(${protobuf_separate_output_SRCS} ${${protobuf_separate_output_SRCS}} PARENT_SCOPE) - endif() - if (protobuf_separate_output_DESCRIPTORS) - list(APPEND ${protobuf_separate_output_DESCRIPTORS} ${DESCRIPTORS}) - list(REMOVE_DUPLICATES ${protobuf_separate_output_DESCRIPTORS}) - set(${protobuf_separate_output_DESCRIPTORS} ${${protobuf_separate_output_DESCRIPTORS}} PARENT_SCOPE) - endif() - -endfunction() - -# Generates CPP gRPC services. Use GEN_GRPC to indicate whether or not to use the gRPC extension -function(protobuf_generate_grpc_cpp target) - - cmake_parse_arguments(protobuf_generate_grpc_cpp "GEN_GRPC" "HDRS;SRCS;DESCRIPTORS" "PROTOS" ${ARGN}) - - set(out_files) - - # Generate the cpp files - protobuf_generate( - LANGUAGE cpp - OUT_VAR out_files - IMPORT_DIRS ${Protobuf_IMPORT_DIRS} - TARGET ${target} - PROTOS ${protobuf_generate_grpc_cpp_PROTOS} - ${protobuf_generate_grpc_cpp_UNPARSED_ARGUMENTS} - ) - - protobuf_separate_output( - "${out_files}" - HDRS ${protobuf_generate_grpc_cpp_HDRS} - SRCS ${protobuf_generate_grpc_cpp_SRCS} - DESCRIPTORS ${protobuf_generate_grpc_cpp_DESCRIPTORS} - ) - - if (protobuf_generate_grpc_cpp_GEN_GRPC) - set(out_files "") - - # Generate the grpc files - protobuf_generate( - LANGUAGE grpc - OUT_VAR out_files - GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc - PLUGIN "protoc-gen-grpc=$" - IMPORT_DIRS ${Protobuf_IMPORT_DIRS} - TARGET ${target} - PROTOS ${protobuf_generate_grpc_cpp_PROTOS} - ${protobuf_generate_grpc_cpp_UNPARSED_ARGUMENTS} - ) - - protobuf_separate_output( - "${out_files}" - HDRS ${protobuf_generate_grpc_cpp_HDRS} - SRCS ${protobuf_generate_grpc_cpp_SRCS} - DESCRIPTORS ${protobuf_generate_grpc_cpp_DESCRIPTORS} - ) - endif() - - # Now configure the target common for all proto targets - target_link_libraries(${target} - PUBLIC - protobuf::libprotobuf - ) - - target_include_directories(${target} - PUBLIC - $ - ) - - # We must always compile protobufs with `NDEBUG` defined due to an issue with - # libprotobuf>=3.20. Their header files can change between Debug/Release which - # causes undefined symbol errors when building and running in Debug. Setting - # this definition gets around this issue by ensuring a consistent value for - # `NDEBUG`. See this issue for more info: - # https://github.com/protocolbuffers/protobuf/issues/9947 - target_compile_definitions(${target} - PRIVATE NDEBUG - ) - - if (protobuf_generate_grpc_cpp_HDRS) - set(${protobuf_generate_grpc_cpp_HDRS} ${${protobuf_generate_grpc_cpp_HDRS}} PARENT_SCOPE) - set_target_properties(${target} PROPERTIES PUBLIC_HEADER "${${protobuf_generate_grpc_cpp_HDRS}}") - endif() - - if (protobuf_generate_grpc_cpp_SRCS) - set(${protobuf_generate_grpc_cpp_SRCS} ${${protobuf_generate_grpc_cpp_SRCS}} PARENT_SCOPE) - endif() - -endfunction() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 90d9cac46..2a051a2b6 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -54,27 +54,22 @@ rapids_find_package(CUDAToolkit # ===== # - Use static linking to avoid issues with system-wide installations of Boost. # - Use numa=on to ensure the numa component of fiber gets built -set(BOOST_VERSION "1.74.0" CACHE STRING "Version of boost to use") -morpheus_utils_configure_boost_boost_cmake(${BOOST_VERSION}) +morpheus_utils_configure_boost_boost_cmake() # UCX # === -set(UCX_VERSION "1.13" CACHE STRING "Version of ucx to use") -morpheus_utils_configure_ucx(${UCX_VERSION}) +morpheus_utils_configure_ucx() # hwloc # ===== -set(HWLOC_VERSION "2.5" CACHE STRING "Version of hwloc to use") -morpheus_utils_configure_hwloc(${HWLOC_VERSION}) +morpheus_utils_configure_hwloc() # expected -set(EXPECTED_VERSION "1.0.0" CACHE STRING "Version of expected to use") -morpheus_utils_configure_tl_expected(${EXPECTED_VERSION}) +morpheus_utils_configure_tl_expected() # NVIDIA RAPIDS RMM # ================= -set(RMM_VERSION "${MRC_RAPIDS_VERSION}" CACHE STRING "Version of RMM to use. Defaults to \${MRC_RAPIDS_VERSION}") -morpheus_utils_configure_rmm(${RMM_VERSION}) +morpheus_utils_configure_rmm() # gflags # ====== @@ -88,8 +83,7 @@ rapids_find_package(gflags REQUIRED # ==== # - link against shared # - todo: compile with -DWITH_GFLAGS=OFF and remove gflags dependency -set(GLOG_VERSION "0.6" CACHE STRING "Version of glog to use") -morpheus_utils_configure_glog(${GLOG_VERSION}) +morpheus_utils_configure_glog() # nvidia cub # ========== @@ -111,8 +105,7 @@ rapids_find_package(gRPC REQUIRED # RxCpp # ===== -set(RXCPP_VERSION "4.1.1.2" CACHE STRING "Version of RxCpp to use") -morpheus_utils_configure_rxcpp(${RXCPP_VERSION}) +morpheus_utils_configure_rxcpp() # JSON # ====== @@ -126,12 +119,10 @@ rapids_find_package(nlohmann_json REQUIRED # prometheus # ========= -set(PROMETHEUS_CPP_VERSION "1.0.0" CACHE STRING "Version of Prometheus-cpp to use") morpheus_utils_configure_prometheus_cpp(${PROMETHEUS_CPP_VERSION}) # libcudacxx # ========= -set(LIBCUDACXX_VERSION "1.8.0" CACHE STRING "Version of libcudacxx to use") morpheus_utils_configure_libcudacxx(${LIBCUDACXX_VERSION}) if(MRC_BUILD_BENCHMARKS) diff --git a/cmake/load_morpheus_utils.cmake b/cmake/load_morpheus_utils.cmake deleted file mode 100644 index 307b8692d..000000000 --- a/cmake/load_morpheus_utils.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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() -include(FetchContent) - -# Fetch morpheus utilities -- don't use CPM, RAPIDS_CPM, or other external libraries here so -# we are only relying on CMake to get our core utilities. -function(find_and_configure_morpheus_utils version) - list(APPEND CMAKE_MESSAGE_CONTEXT "morpheus_utils") - - set(fetchcontent_tmp "${FETCHCONTENT_BASE_DIR}") - set(FETCHCONTENT_BASE_DIR "${CMAKE_SOURCE_DIR}/.cache") # default location - if (${CPM_SOURCE_CACHE}) - set(FETCHCONTENT_BASE_DIR "${CPM_SOURCE_CACHE}") - endif() - - FetchContent_Declare( - morpheus_utils - # TODO(Devin): Change to https once utilities is public. - GIT_REPOSITORY /home/drobison/Development/devin-morpheus-utils-public - GIT_TAG v${version} - GIT_SHALLOW TRUE - ) - FetchContent_MakeAvailable(morpheus_utils) - set(FETCHCONTENT_BASE_DIR "${fetchcontent_tmp}") - - set(MORPHEUS_UTILS_HOME "${morpheus_utils_SOURCE_DIR}" CACHE INTERNAL "Morpheus utils home") - list(POP_BACK CMAKE_MESSAGE_CONTEXT) -endfunction() - -find_and_configure_morpheus_utils(${MORPHEUS_UTILS_VERSION}) - -list(APPEND CMAKE_MODULE_PATH "${MORPHEUS_UTILS_HOME}/cmake") -include(morpheus_utils/load) diff --git a/protos/CMakeLists.txt b/protos/CMakeLists.txt index 139d168d2..a4d6f7b6f 100644 --- a/protos/CMakeLists.txt +++ b/protos/CMakeLists.txt @@ -13,7 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -include(GRPCGenerateCPP) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/utilities/cmake") +include(morpheus_utils/grpc/GRPCGenerateCPP) add_library(mrc_protos) diff --git a/utilities b/utilities new file mode 160000 index 000000000..8cf6c40f5 --- /dev/null +++ b/utilities @@ -0,0 +1 @@ +Subproject commit 8cf6c40f5ebd4674531ff61cd4b45dabe35d8b31 From 92a56a69f7b0341bca0104b16d201abbccab1205 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 6 Dec 2022 15:46:33 -0700 Subject: [PATCH 18/55] Resolve some noisy clang tidy issues --- CMakeLists.txt | 38 ++++++++++++++++---------------- include/mrc/runnable/types.hpp | 2 +- include/mrc/utils/type_utils.hpp | 24 ++++++++++---------- python/mrc/_pymrc/CMakeLists.txt | 14 ++++++------ src/public/utils/type_utils.cpp | 2 +- 5 files changed, 40 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28b4424b2..c6620ec86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,26 +287,26 @@ add_library(${PROJECT_NAME}::libmrc ALIAS libmrc) target_link_libraries(libmrc PUBLIC - mrc_protos - mrc_architect_protos - rmm::rmm - CUDA::nvml - CUDA::cudart - rxcpp::rxcpp - glog::glog - libcudacxx::libcudacxx - Boost::fiber - Boost::context - glog::glog - gRPC::grpc++ - gRPC::grpc - gRPC::gpr + mrc_protos + mrc_architect_protos + rmm::rmm + CUDA::nvml + CUDA::cudart + rxcpp::rxcpp + glog::glog + libcudacxx::libcudacxx + Boost::fiber + Boost::context + glog::glog + gRPC::grpc++ + gRPC::grpc + gRPC::gpr PRIVATE - hwloc::hwloc - prometheus-cpp::core # private in MR !199 - ucx::ucs - ucx::ucp - tl::expected + hwloc::hwloc + prometheus-cpp::core # private in MR !199 + ucx::ucs + ucx::ucp + tl::expected ) target_include_directories(libmrc diff --git a/include/mrc/runnable/types.hpp b/include/mrc/runnable/types.hpp index 483380480..a817fd3aa 100644 --- a/include/mrc/runnable/types.hpp +++ b/include/mrc/runnable/types.hpp @@ -37,7 +37,7 @@ std::string engine_type_string(const EngineType& engine_type); */ inline std::string default_engine_factory_name() { - return std::string("default"); + return {"default"}; } } // namespace mrc::runnable diff --git a/include/mrc/utils/type_utils.hpp b/include/mrc/utils/type_utils.hpp index 69c4b7bf3..bb3950160 100644 --- a/include/mrc/utils/type_utils.hpp +++ b/include/mrc/utils/type_utils.hpp @@ -108,47 +108,47 @@ struct DataType { if constexpr (std::is_integral_v && std::is_signed_v && size_in_bits() == 8) { - return DataType(TypeId::INT8); + return {TypeId::INT8}; } else if constexpr (std::is_integral_v && std::is_signed_v && size_in_bits() == 16) { - return DataType(TypeId::INT16); + return {TypeId::INT16}; } else if constexpr (std::is_integral_v && std::is_signed_v && size_in_bits() == 32) { - return DataType(TypeId::INT32); + return {TypeId::INT32}; } else if constexpr (std::is_integral_v && std::is_signed_v && size_in_bits() == 64) { - return DataType(TypeId::INT64); + return {TypeId::INT64}; } else if constexpr (std::is_integral_v && std::is_unsigned_v && size_in_bits() == 8) { - return DataType(TypeId::UINT8); + return {TypeId::UINT8}; } else if constexpr (std::is_integral_v && std::is_unsigned_v && size_in_bits() == 16) { - return DataType(TypeId::UINT16); + return {TypeId::UINT16}; } else if constexpr (std::is_integral_v && std::is_unsigned_v && size_in_bits() == 32) { - return DataType(TypeId::UINT32); + return {TypeId::UINT32}; } else if constexpr (std::is_integral_v && std::is_unsigned_v && size_in_bits() == 64) { - return DataType(TypeId::UINT64); + return {TypeId::UINT64}; } else if constexpr (std::is_floating_point_v && size_in_bits() == 32) { - return DataType(TypeId::FLOAT32); + return {TypeId::FLOAT32}; } else if constexpr (std::is_floating_point_v && size_in_bits() == 64) { - return DataType(TypeId::FLOAT64); + return {TypeId::FLOAT64}; } else if constexpr (std::is_same_v) { - return DataType(TypeId::BOOL8); + return {TypeId::BOOL8}; } else { @@ -156,7 +156,7 @@ struct DataType } // To hide compiler warnings - return DataType(TypeId::EMPTY); + return {TypeId::EMPTY}; } // From numpy diff --git a/python/mrc/_pymrc/CMakeLists.txt b/python/mrc/_pymrc/CMakeLists.txt index 8213aefb3..a1078d5fe 100644 --- a/python/mrc/_pymrc/CMakeLists.txt +++ b/python/mrc/_pymrc/CMakeLists.txt @@ -45,18 +45,18 @@ add_library(${PROJECT_NAME}::pymrc ALIAS pymrc) target_link_libraries(pymrc PUBLIC - ${PROJECT_NAME}::libmrc - ${Python_LIBRARIES} - prometheus-cpp::core - pybind11::pybind11 + ${PROJECT_NAME}::libmrc + ${Python_LIBRARIES} + prometheus-cpp::core + pybind11::pybind11 ) target_include_directories(pymrc PUBLIC - $ - $ + $ + $ PRIVATE - ${Python_INCLUDE_DIR} + ${Python_INCLUDE_DIR} ) set_target_properties(pymrc PROPERTIES OUTPUT_NAME ${PROJECT_NAME}_pymrc) diff --git a/src/public/utils/type_utils.cpp b/src/public/utils/type_utils.cpp index 457331595..abdc5a945 100644 --- a/src/public/utils/type_utils.cpp +++ b/src/public/utils/type_utils.cpp @@ -127,7 +127,7 @@ DataType DataType::from_numpy(const std::string& numpy_str) CHECK(found_enum != found_type->second.end()) << "Type str '" << type_char << dtype_size << "' not supported"; - return DataType(found_enum->second); + return {found_enum->second}; } char DataType::type_char() const From 891f9bdfd87cd2f0dd3be1dfeabac43f1aedd250 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Wed, 7 Dec 2022 11:17:53 -0700 Subject: [PATCH 19/55] Cleanup module paths at scope exit --- CMakeLists.txt | 21 ++++++++++++++++----- protos/CMakeLists.txt | 10 +++++++++- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6620ec86..7005663cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,13 +44,20 @@ mark_as_advanced(MRC_CACHE_DIR) enable_language(C CXX) enable_testing() -# CMake path -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") -list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/utilities/cmake") -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +# MRC CMake path and module extensions +set(MRC_CMAKE_MODULE_PATH_EXTENSIONS + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/utilities/cmake") + +set(MRC_CMAKE_PREFIX_PATH_EXTENSIONS + "${CMAKE_CURRENT_SOURCE_DIR}/cmake" + ) + +# Prepend path and prefix updates so they take priority in this scope. +list(PREPEND CMAKE_MODULE_PATH "${MRC_CMAKE_MODULE_PATH_EXTENSIONS}") +list(PREPEND CMAKE_PREFIX_PATH "${MRC_CMAKE_PREFIX_PATH_EXTENSIONS}") # Load morpheus utils and update CMake paths -set(MORPHEUS_UTILS_VERSION "23.01.01-alpha" CACHE STRING "Version of Morpheus utils") set(MORPHEUS_UTILS_RAPIDS_CMAKE_VERSION ${MRC_RAPIDS_VERSION}) set(MORPHEUS_UTILS_RAPIDS_CPM_INIT_OVERRIDE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/rapids_cpm_package_overrides.json") include(morpheus_utils/load) @@ -408,4 +415,8 @@ if (MRC_ENABLE_DEBUG_INFO) morpheus_utils_print_all_targets() endif() +# Cleanup the environment after we exit this scope +list(REMOVE_ITEM CMAKE_PREFIX_PATH "${MRC_CMAKE_PREFIX_PATH_EXTENSIONS}") +list(REMOVE_ITEM CMAKE_MODULE_PATH "${MRC_CMAKE_MODULE_PATH_EXTENSIONS}") + list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/protos/CMakeLists.txt b/protos/CMakeLists.txt index a4d6f7b6f..06c2afd1f 100644 --- a/protos/CMakeLists.txt +++ b/protos/CMakeLists.txt @@ -13,7 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/utilities/cmake") +set(MRC_PROTO_MODULE_PATH_EXTENSIONS + "${CMAKE_SOURCE_DIR}/utilities/cmake" + ) + +# Prepend path updates so they take priority in this scope. +list(PREPEND CMAKE_MODULE_PATH ${MRC_PROTO_MODULE_PATH_EXTENSIONS}) + include(morpheus_utils/grpc/GRPCGenerateCPP) add_library(mrc_protos) @@ -91,3 +97,5 @@ install( PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/protos" ) + +list(REMOVE_ITEM CMAKE_MODULE_PATH ${MRC_PROTO_MODULE_PATH_EXTENSIONS}) From 84a2f147f78f027607cb4d5510e703045eb847e5 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 8 Dec 2022 12:22:14 -0700 Subject: [PATCH 20/55] Submodule tweaks --- .gitmodules | 4 ++-- external/utilities | 1 + utilities | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) create mode 160000 external/utilities delete mode 160000 utilities diff --git a/.gitmodules b/.gitmodules index 385ab00e4..70eb8999a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ -[submodule "utilities"] - path = utilities +[submodule "morpheus_utils"] + path = external/utilities url = git@github.com:nv-morpheus/utilities.git branch = devin-issue-225-87 diff --git a/external/utilities b/external/utilities new file mode 160000 index 000000000..04e481da6 --- /dev/null +++ b/external/utilities @@ -0,0 +1 @@ +Subproject commit 04e481da6bbde2de383150bf6df8a6da9ece9c7a diff --git a/utilities b/utilities deleted file mode 160000 index 8cf6c40f5..000000000 --- a/utilities +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8cf6c40f5ebd4674531ff61cd4b45dabe35d8b31 From bc483cdb1f434234bc17e133f48e535d75b45d8d Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 8 Dec 2022 12:38:24 -0700 Subject: [PATCH 21/55] Typo fixes --- CMakeLists.txt | 2 +- external/utilities | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7005663cf..7b6b4cc28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ enable_testing() # MRC CMake path and module extensions set(MRC_CMAKE_MODULE_PATH_EXTENSIONS "${CMAKE_CURRENT_SOURCE_DIR}/cmake" - "${CMAKE_CURRENT_SOURCE_DIR}/utilities/cmake") + "${CMAKE_CURRENT_SOURCE_DIR}/external/utilities/cmake") set(MRC_CMAKE_PREFIX_PATH_EXTENSIONS "${CMAKE_CURRENT_SOURCE_DIR}/cmake" diff --git a/external/utilities b/external/utilities index 04e481da6..684ff051c 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 04e481da6bbde2de383150bf6df8a6da9ece9c7a +Subproject commit 684ff051c1fab05389e0e25ccc12578af5d7212e From bbc3a5ecbc1dc76f50a94752ea6460276e861548 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 8 Dec 2022 16:31:59 -0700 Subject: [PATCH 22/55] Disable IWYU + CCACHE --- CMakeLists.txt | 4 ++++ external/utilities | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b6b4cc28..e37e446a0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,10 @@ mark_as_advanced(MRC_CACHE_DIR) enable_language(C CXX) enable_testing() +if (MRC_USE_IWYU AND MRC_USE_CCACHE) + message(FATAL_ERROR "MRC_USE_IWYU and MRC_USE_CCACHE cannot be set simultaneously") +endif() + # MRC CMake path and module extensions set(MRC_CMAKE_MODULE_PATH_EXTENSIONS "${CMAKE_CURRENT_SOURCE_DIR}/cmake" diff --git a/external/utilities b/external/utilities index 684ff051c..008b3e7e5 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 684ff051c1fab05389e0e25ccc12578af5d7212e +Subproject commit 008b3e7e50db214c5eaaff34b4620cd756dfa9b3 From c0f5a00697f5cc87e97478e716f7a24b2bbe903a Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 12 Dec 2022 16:01:33 -0700 Subject: [PATCH 23/55] Update utilities repo --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index 008b3e7e5..4485faa60 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 008b3e7e50db214c5eaaff34b4620cd756dfa9b3 +Subproject commit 4485faa6029f6172ab590a615e544293f3775b21 From 5fb2933f3e118dd44bed084e036d0759f4252e19 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 12 Dec 2022 17:37:03 -0700 Subject: [PATCH 24/55] Remove unused .yml config --- ci/conda/environments/dev_env_nogcc.yml | 38 ------------------------- 1 file changed, 38 deletions(-) delete mode 100644 ci/conda/environments/dev_env_nogcc.yml diff --git a/ci/conda/environments/dev_env_nogcc.yml b/ci/conda/environments/dev_env_nogcc.yml deleted file mode 100644 index 5be1b1455..000000000 --- a/ci/conda/environments/dev_env_nogcc.yml +++ /dev/null @@ -1,38 +0,0 @@ -channels: - - conda-forge - - rapidsai - - nvidia - - rapidsai-nightly -dependencies: - - autoconf>=2.69 - - benchmark=1.6.0 - - boost-cpp=1.74 - - ccache - - cmake>=3.22 - - cython=0.29.24 - - doxygen=1.9.2 - - flatbuffers=2.0 - - gflags=2.2 - - git>=2.35.3 # Needed for wildcards on safe.directory - - glog=0.6 - - gmock=1.10 - - graphviz=3.0 - - grpc-cpp=1.46 - - gtest=1.10 - - libhwloc=2.5 - - libprotobuf=3.20 - - librmm=22.08 - - ninja=1.10 - - nlohmann_json=3.9 - - pkg-config=0.29 - - python=3.8 - - scikit-build>=0.12 - - spdlog=1.8.5 - - ucx=1.13 - - pip: - - cython - - flake8 - - isort - - pytest - - pytest-timeout - - yapf From b82836bf80dd9810f9515c718a4f0b22a56c4b27 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 12 Dec 2022 17:43:47 -0700 Subject: [PATCH 25/55] consolidate scripts --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- scripts/gen_coverage.sh | 22 ------ scripts/print_env.sh | 101 -------------------------- 3 files changed, 1 insertion(+), 124 deletions(-) delete mode 100755 scripts/gen_coverage.sh delete mode 100755 scripts/print_env.sh diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3f1304365..dc56973c6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -70,7 +70,7 @@ body: id: env-printout attributes: label: Full env printout - description: Please run and paste the output of the `./scripts/print_env.sh` script here, to gather any other relevant environment details + description: Please run and paste the output of the `./external/utilities/scripts/print_env.sh` script here, to gather any other relevant environment details render: shell - type: textarea diff --git a/scripts/gen_coverage.sh b/scripts/gen_coverage.sh deleted file mode 100755 index 7834aa570..000000000 --- a/scripts/gen_coverage.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2021-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. -set -x -set -e - -cmake -DCMAKE_BUILD_TYPE=Debug -GNinja -DCMAKE_BUILD_TYPE=Debug -DMRC_ENABLE_CODECOV=ON -DMRC_BUILD_PYTHON=ON -DMRC_BUILD_TESTS=ON -B ./build -cmake --build ./build -pip install -e ./build/python -cd ./build && ctest && pytest ./build/python/tests -cmake --build ./build --target gcovr-html-report diff --git a/scripts/print_env.sh b/scripts/print_env.sh deleted file mode 100755 index a5b63aed9..000000000 --- a/scripts/print_env.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2021-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. - -# Reports relevant environment information useful for diagnosing and -# debugging cuDF issues. -# Usage: -# "./print_env.sh" - prints to stdout -# "./print_env.sh > env.txt" - prints to file "env.txt" - -print_env() { -echo "**git***" -if [ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" == "true" ]; then -git log --decorate -n 1 -echo "**git submodules***" -git submodule status --recursive -else -echo "Not inside a git repository" -fi -echo - -echo "***OS Information***" -cat /etc/*-release -uname -a -echo - -echo "***GPU Information***" -nvidia-smi -echo - -echo "***CPU***" -lscpu -echo - -echo "***CMake***" -which cmake && cmake --version -echo - -echo "***g++***" -which g++ && g++ --version -echo - -echo "***nvcc***" -which nvcc && nvcc --version -echo - -echo "***Python***" -which python && python -c "import sys; print('Python {0}.{1}.{2}'.format(sys.version_info[0], sys.version_info[1], sys.version_info[2]))" -echo - -echo "***Environment Variables***" - -printf '%-32s: %s\n' PATH $PATH - -printf '%-32s: %s\n' LD_LIBRARY_PATH $LD_LIBRARY_PATH - -printf '%-32s: %s\n' NUMBAPRO_NVVM $NUMBAPRO_NVVM - -printf '%-32s: %s\n' NUMBAPRO_LIBDEVICE $NUMBAPRO_LIBDEVICE - -printf '%-32s: %s\n' CONDA_PREFIX $CONDA_PREFIX - -printf '%-32s: %s\n' PYTHON_PATH $PYTHON_PATH - -echo - - -# Print conda packages if conda exists -if type "conda" &> /dev/null; then -echo '***conda packages***' -which conda && conda list -echo -# Print pip packages if pip exists -elif type "pip" &> /dev/null; then -echo "conda not found" -echo "***pip packages***" -which pip && pip list -echo -else -echo "conda not found" -echo "pip not found" -fi -} - -echo "
Click here to see environment details
"
-echo "     "
-print_env | while read -r line; do
-    echo "     $line"
-done
-echo "
" From 4961fb1fb34de31a633ee29ee172ffb378abf7ee Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 13 Dec 2022 13:41:13 -0700 Subject: [PATCH 26/55] Update utilities version --- .clang-tidy | 6 +++--- .github/workflows/ci_pipe.yml | 2 +- CMakeLists.txt | 8 ++++---- ci/conda/environments/dev_env.yml | 6 +++--- ci/conda/recipes/libmrc/conda_build_config.yaml | 10 ++++++---- ci/conda/recipes/libmrc/meta.yaml | 4 ++-- ci/scripts/github/test.sh | 5 ----- ci/scripts/github/test_codecov.sh | 2 -- cpp/mrc/CMakeLists.txt | 9 +++++++++ cpp/mrc/src/internal/control_plane/server.cpp | 4 ++-- cpp/mrc/src/tests/common.hpp | 10 ++++++++++ cpp/mrc/src/tests/test_expected.cpp | 2 +- cpp/mrc/src/tests/test_ucx.cpp | 11 +++++++++++ cpp/mrc/tests/CMakeLists.txt | 5 +++++ cpp/mrc/tests/test_mrc.hpp | 8 ++++++++ docs/quickstart/CMakeLists.txt | 4 ++-- docs/quickstart/environment_cpp.yml | 4 ++-- external/utilities | 2 +- python/tests/test_module_registry.py | 2 +- 19 files changed, 71 insertions(+), 33 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index aa0a1392f..308574f11 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -174,7 +174,7 @@ CheckOptions: - key: readability-identifier-naming.StructCase value: CamelCase - key: readability-identifier-naming.StructIgnoredRegexp - value: ^is_.*$ + value: ^is_.*$|^.*_traits$ - key: readability-identifier-naming.StructPrefix value: '' - key: readability-identifier-naming.StructSuffix @@ -182,7 +182,7 @@ CheckOptions: - key: readability-identifier-naming.TypeAliasCase value: lower_case - key: readability-identifier-naming.TypeAliasIgnoredRegexp - value: '' + value: ^.*_type$ - key: readability-identifier-naming.TypeAliasPrefix value: '' - key: readability-identifier-naming.TypeAliasSuffix @@ -190,7 +190,7 @@ CheckOptions: - key: readability-identifier-naming.TypedefCase value: lower_case - key: readability-identifier-naming.TypedefIgnoredRegexp - value: '' + value: ^.*_type$ - key: readability-identifier-naming.TypedefPrefix value: '' - key: readability-identifier-naming.TypedefSuffix diff --git a/.github/workflows/ci_pipe.yml b/.github/workflows/ci_pipe.yml index b8cf8cc89..6f6d95fb6 100644 --- a/.github/workflows/ci_pipe.yml +++ b/.github/workflows/ci_pipe.yml @@ -121,7 +121,7 @@ jobs: username: '$oauthtoken' password: ${{ secrets.NGC_API_KEY }} image: ${{ inputs.test_container }} - options: --cap-add=sys_nice + options: "--cap-add=sys_nice --cap-add=sys_ptrace" env: NVIDIA_VISIBLE_DEVICES: ${{ env.NVIDIA_VISIBLE_DEVICES }} PARALLEL_LEVEL: '10' diff --git a/CMakeLists.txt b/CMakeLists.txt index 8edd113e8..303d48def 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.22 FATAL_ERROR) +cmake_minimum_required(VERSION 3.24 FATAL_ERROR) list(APPEND CMAKE_MESSAGE_CONTEXT "mrc") @@ -36,8 +36,8 @@ option(MRC_USE_CONDA "Enables finding dependencies via conda. All dependencies m environment" ON) option(MRC_USE_IWYU "Enable running include-what-you-use as part of the build process" OFF) -set(MRC_RAPIDS_VERSION "22.08" CACHE STRING "Which version of RAPIDS to build for. - Sets default versions for RAPIDS CMake and RMM.") +set(MRC_RAPIDS_VERSION "22.10" CACHE STRING "Which version of RAPIDS to build for. Sets default versions for RAPIDS CMake and RMM.") + set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) @@ -77,7 +77,7 @@ morpheus_utils_initialize_package_manager( morpheus_utils_initialize_cuda_arch(mrc) project(mrc - VERSION 22.11.00 + VERSION 23.01.00 LANGUAGES C CXX ) diff --git a/ci/conda/environments/dev_env.yml b/ci/conda/environments/dev_env.yml index 187aae3d4..e596cf139 100644 --- a/ci/conda/environments/dev_env.yml +++ b/ci/conda/environments/dev_env.yml @@ -8,7 +8,7 @@ dependencies: - benchmark=1.6.0 - boost-cpp=1.74 - ccache - - cmake=3.22 + - cmake=3.24 - cuda-nvml-dev=11.4 - cudatoolkit=11.4 - cython=0.29.24 @@ -24,11 +24,12 @@ dependencies: - grpc-cpp=1.46 - gtest=1.10 - gxx_linux-64=11.2 + - isort - jinja2=3.0 - lcov=1.15 - libhwloc=2.5 - libprotobuf=3.20 - - librmm=22.08 + - librmm=22.10 - libtool - ninja=1.10 - nlohmann_json=3.9 @@ -46,7 +47,6 @@ dependencies: - pip: - cython - flake8 - - isort - numpy==1.21.2 - pytest - pytest-timeout diff --git a/ci/conda/recipes/libmrc/conda_build_config.yaml b/ci/conda/recipes/libmrc/conda_build_config.yaml index e1f4951e8..11ef76893 100644 --- a/ci/conda/recipes/libmrc/conda_build_config.yaml +++ b/ci/conda/recipes/libmrc/conda_build_config.yaml @@ -31,29 +31,31 @@ python: # Setup the dependencies to build with multiple versions of RAPIDS rapids_version: # Keep around compatibility with current version -1 - - 22.06 - 22.08 - 22.08 + - 22.10 + # Multiple versions of abseil are required to satisfy the solver for some # environments. RAPIDS 22.06 only works with gRPC 1.45 and 22.08 only works with # 1.46. For each version of gRPC, support 2 abseil versions. Zip all of the keys # together to avoid impossible combinations abseil_cpp: - - 20210324.2 - 20211102.0 - 20220623.0 + - 20220623.0 grpc_cpp: - - 1.45 + - 1.46 - 1.46 - 1.46 # UCX 1.12 is required for RAPIDS 22.06 ucx: - - 1.12 - 1.13 - 1.13 + - 1.13 + zip_keys: - rapids_version diff --git a/ci/conda/recipes/libmrc/meta.yaml b/ci/conda/recipes/libmrc/meta.yaml index 945869465..6d9fabdc3 100644 --- a/ci/conda/recipes/libmrc/meta.yaml +++ b/ci/conda/recipes/libmrc/meta.yaml @@ -42,7 +42,7 @@ requirements: - {{ compiler("cxx") }} - autoconf >=2.69 - ccache - - cmake 3.22.* + - cmake >=3.24 - libtool - ninja - numactl-libs-cos7-x86_64 @@ -87,7 +87,7 @@ outputs: - {{ compiler("c") }} - {{ compiler("cuda") }} - {{ compiler("cxx") }} - - cmake 3.22.* + - cmake >=3.24 - numactl-libs-cos7-x86_64 - sysroot_linux-64 2.17 host: diff --git a/ci/scripts/github/test.sh b/ci/scripts/github/test.sh index 87a06ea79..5cccec867 100755 --- a/ci/scripts/github/test.sh +++ b/ci/scripts/github/test.sh @@ -41,12 +41,7 @@ cmake -B build -G Ninja ${CMAKE_BUILD_ALL_FEATURES} . rapids-logger "Running C++ Tests" cd ${MRC_ROOT}/build set +e -# Tests known to be failing -# Issues: -# * test_mrc_private - https://github.com/nv-morpheus/MRC/issues/33 -# * nvrpc - https://github.com/nv-morpheus/MRC/issues/34 ctest --output-on-failure \ - --exclude-regex "test_mrc_private|nvrpc" \ --output-junit ${REPORTS_DIR}/report_ctest.xml CTEST_RESULTS=$? diff --git a/ci/scripts/github/test_codecov.sh b/ci/scripts/github/test_codecov.sh index 36e0c24c1..969c43153 100755 --- a/ci/scripts/github/test_codecov.sh +++ b/ci/scripts/github/test_codecov.sh @@ -44,9 +44,7 @@ set +e # Tests known to be failing # Issues: # * test_mrc_private - https://github.com/nv-morpheus/MRC/issues/33 -# * nvrpc - https://github.com/nv-morpheus/MRC/issues/34 ctest --output-on-failure \ - --exclude-regex "test_mrc_private|nvrpc" \ --output-junit ${REPORTS_DIR}/report_ctest.xml CTEST_RESULTS=$? diff --git a/cpp/mrc/CMakeLists.txt b/cpp/mrc/CMakeLists.txt index 2202cf70c..2e140e191 100644 --- a/cpp/mrc/CMakeLists.txt +++ b/cpp/mrc/CMakeLists.txt @@ -119,6 +119,11 @@ add_library(libmrc src/public/core/executor.cpp src/public/core/fiber_pool.cpp src/public/core/logging.cpp + src/public/core/thread.cpp + src/public/coroutines/event.cpp + src/public/coroutines/sync_wait.cpp + src/public/coroutines/thread_local_context.cpp + src/public/coroutines/thread_pool.cpp src/public/cuda/device_guard.cpp src/public/cuda/sync.cpp src/public/manifold/manifold.cpp @@ -194,6 +199,10 @@ target_compile_definitions(libmrc $<$:MRC_ENABLE_BENCHMARKING> ) +if (MRC_ENABLE_CODECOV) + target_compile_definitions(libmrc INTERFACE "MRC_CODECOV_ENABLED") +endif() + target_compile_features(libmrc PUBLIC cxx_std_20) set_target_properties(libmrc PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) diff --git a/cpp/mrc/src/internal/control_plane/server.cpp b/cpp/mrc/src/internal/control_plane/server.cpp index 49ef83b0c..ecc0e3fd9 100644 --- a/cpp/mrc/src/internal/control_plane/server.cpp +++ b/cpp/mrc/src/internal/control_plane/server.cpp @@ -603,8 +603,8 @@ void Server::drop_stream(const stream_id_t& stream_id) auto search = m_connections.streams().find(stream_id); if (search == m_connections.streams().end()) { - LOG(WARNING) << "attempting to drop stream_id: " << stream_id - << " which is not found in set of connected streams"; + LOG(FATAL) << "attempting to drop stream_id: " << stream_id + << " which is not found in set of connected streams"; } auto writer = search->second->writer(); diff --git a/cpp/mrc/src/tests/common.hpp b/cpp/mrc/src/tests/common.hpp index 1773594d1..45bb03342 100644 --- a/cpp/mrc/src/tests/common.hpp +++ b/cpp/mrc/src/tests/common.hpp @@ -17,10 +17,20 @@ #pragma once +#include + +#include #include #include namespace mrc { + +#ifdef MRC_CODECOV_ENABLED + #define SKIP_IF_CODE_COV() GTEST_SKIP() << "Skipping test when code coverage is enabled"; +#else + #define SKIP_IF_CODE_COV() +#endif + class Options; } // namespace mrc namespace mrc::internal::system { diff --git a/cpp/mrc/src/tests/test_expected.cpp b/cpp/mrc/src/tests/test_expected.cpp index 10204240a..366bfccae 100644 --- a/cpp/mrc/src/tests/test_expected.cpp +++ b/cpp/mrc/src/tests/test_expected.cpp @@ -108,7 +108,7 @@ TEST_F(TestExpected, Chaining3) EXPECT_FALSE(rc); EXPECT_EQ(rc.error().message(), "void fail"); - EXPECT_ANY_THROW(rc->value()); + EXPECT_ANY_THROW(rc.value()); } TEST_F(TestExpected, UniquePointer) diff --git a/cpp/mrc/src/tests/test_ucx.cpp b/cpp/mrc/src/tests/test_ucx.cpp index abf9e249f..6f10ceb8a 100644 --- a/cpp/mrc/src/tests/test_ucx.cpp +++ b/cpp/mrc/src/tests/test_ucx.cpp @@ -15,6 +15,8 @@ * limitations under the License. */ +#include "common.hpp" + #include "internal/ucx/all.hpp" #include "internal/ucx/endpoint.hpp" @@ -72,6 +74,9 @@ TEST_F(TestUCX, CreateWorkerAddress) TEST_F(TestUCX, EndpointsInProcess) { + // note this test really should use a progress engine + GTEST_SKIP(); + auto worker_1 = std::make_shared(m_context); auto worker_2 = std::make_shared(m_context); @@ -107,6 +112,8 @@ static void rdma_get_callback(void* request, ucs_status_t status, void* user_dat TEST_F(TestUCX, Get) { + SKIP_IF_CODE_COV() + auto context = std::make_shared(); auto worker_get_src = std::make_shared(context); @@ -205,6 +212,8 @@ class SendRecvManager TEST_F(TestUCX, Recv) { + SKIP_IF_CODE_COV(); + auto context = std::make_shared(); auto worker_src = std::make_shared(context); @@ -279,6 +288,8 @@ TEST_F(TestUCX, Recv) TEST_F(TestUCX, Recv2) { + SKIP_IF_CODE_COV(); + auto context = std::make_shared(); auto worker_src = std::make_shared(context); diff --git a/cpp/mrc/tests/CMakeLists.txt b/cpp/mrc/tests/CMakeLists.txt index 7192e0dbe..366afed8e 100644 --- a/cpp/mrc/tests/CMakeLists.txt +++ b/cpp/mrc/tests/CMakeLists.txt @@ -15,6 +15,10 @@ # Keep all source files sorted!!! add_executable(test_mrc + coroutines/test_event.cpp + coroutines/test_latch.cpp + coroutines/test_ring_buffer.cpp + coroutines/test_task.cpp modules/test_module_registry.cpp modules/test_module_util.cpp modules/test_segment_modules.cpp @@ -26,6 +30,7 @@ add_executable(test_mrc test_node.cpp test_pipeline.cpp test_segment.cpp + test_thread.cpp test_type_utils.cpp ) diff --git a/cpp/mrc/tests/test_mrc.hpp b/cpp/mrc/tests/test_mrc.hpp index af2b17357..0dd9f93d8 100644 --- a/cpp/mrc/tests/test_mrc.hpp +++ b/cpp/mrc/tests/test_mrc.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include // for mutex & unique_lock #define TEST_CLASS(name) \ @@ -33,6 +34,13 @@ {} namespace mrc { + +#ifdef MRC_CODECOV_ENABLED + #define SKIP_IF_CODE_COV() GTEST_SKIP() << "Skipping test when code coverage is enabled"; +#else + #define SKIP_IF_CODE_COV() +#endif + // class that records when it's moved/copied struct CopyMoveCounter { diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index d212c92f4..246db715f 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -15,7 +15,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "quickstart") -cmake_minimum_required(VERSION 3.17 FATAL_ERROR) +cmake_minimum_required(VERSION 3.24 FATAL_ERROR) # Add the Conda environment to the prefix path and add the CMake files list(PREPEND CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}") @@ -26,7 +26,7 @@ list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake") # include(morpheus_utils/environment_config/rapids_cmake/setup) project(mrc-quickstart - VERSION 22.11.00 + VERSION 23.01 LANGUAGES C CXX ) diff --git a/docs/quickstart/environment_cpp.yml b/docs/quickstart/environment_cpp.yml index f97aeace0..3ee4bbe0a 100644 --- a/docs/quickstart/environment_cpp.yml +++ b/docs/quickstart/environment_cpp.yml @@ -21,6 +21,7 @@ dependencies: - graphviz=3.0 - gtest=1.10 - gxx_linux-64=11.2 + - isort - libtool - ninja=1.10 - numactl-libs-cos7-x86_64 @@ -30,12 +31,11 @@ dependencies: - python=3.8 - scikit-build>=0.12 - spdlog=1.8.5 - - mrc=22.11 + - mrc=23.01 - sysroot_linux-64=2.17 - pip: - cython - flake8 - - isort - numpy==1.21.2 - pytest - pytest-timeout diff --git a/external/utilities b/external/utilities index 4485faa60..99c7b57c5 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 4485faa6029f6172ab590a615e544293f3775b21 +Subproject commit 99c7b57c5758a342dec0b33a5b8f1335d45fe86a diff --git a/python/tests/test_module_registry.py b/python/tests/test_module_registry.py index 72f28d228..bbbf9e4d7 100644 --- a/python/tests/test_module_registry.py +++ b/python/tests/test_module_registry.py @@ -45,7 +45,7 @@ def test_contains(): def test_is_version_compatible(): registry = mrc.ModuleRegistry - release_version = [22, 11, 0] + release_version = [int(x) for x in mrc.__version__.split(".")] old_release_version = [22, 10, 0] no_version_patch = [22, 10] no_version_minor_and_patch = [22] From 120abbf5d4b0d65ec24bf37d749ded488866c69c Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 13 Dec 2022 13:44:58 -0700 Subject: [PATCH 27/55] Clang tidy cleanup --- cpp/mrc/include/mrc/core/thread.hpp | 26 + .../mrc/coroutines/concepts/awaitable.hpp | 112 ++++ .../mrc/coroutines/concepts/buffer.hpp | 65 ++ .../mrc/coroutines/concepts/executor.hpp | 58 ++ .../mrc/coroutines/concepts/promise.hpp | 64 ++ .../mrc/coroutines/concepts/range_of.hpp | 60 ++ .../mrc/coroutines/detail/void_value.hpp | 45 ++ cpp/mrc/include/mrc/coroutines/event.hpp | 207 ++++++ cpp/mrc/include/mrc/coroutines/generator.hpp | 255 ++++++++ cpp/mrc/include/mrc/coroutines/latch.hpp | 126 ++++ .../include/mrc/coroutines/ring_buffer.hpp | 520 +++++++++++++++ .../mrc/coroutines/schedule_policy.hpp | 28 + cpp/mrc/include/mrc/coroutines/sync_wait.hpp | 285 +++++++++ cpp/mrc/include/mrc/coroutines/task.hpp | 346 ++++++++++ .../mrc/coroutines/thread_local_context.hpp | 96 +++ .../include/mrc/coroutines/thread_pool.hpp | 329 ++++++++++ cpp/mrc/include/mrc/coroutines/when_all.hpp | 591 ++++++++++++++++++ cpp/mrc/src/public/core/thread.cpp | 61 ++ cpp/mrc/src/public/coroutines/event.cpp | 133 ++++ cpp/mrc/src/public/coroutines/sync_wait.cpp | 67 ++ .../coroutines/thread_local_context.cpp | 89 +++ cpp/mrc/src/public/coroutines/thread_pool.cpp | 229 +++++++ cpp/mrc/tests/coroutines/test_event.cpp | 320 ++++++++++ cpp/mrc/tests/coroutines/test_latch.cpp | 158 +++++ cpp/mrc/tests/coroutines/test_ring_buffer.cpp | 276 ++++++++ cpp/mrc/tests/coroutines/test_task.cpp | 118 ++++ cpp/mrc/tests/test_thread.cpp | 54 ++ .../hybrid/mrc_qs_hybrid/_version.py | 5 +- docs/quickstart/hybrid/versioneer.py | 199 +++--- .../python/mrc_qs_python/_version.py | 5 +- docs/quickstart/python/versioneer.py | 199 +++--- 31 files changed, 4938 insertions(+), 188 deletions(-) create mode 100644 cpp/mrc/include/mrc/core/thread.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/concepts/awaitable.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/concepts/buffer.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/concepts/executor.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/concepts/promise.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/concepts/range_of.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/detail/void_value.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/event.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/generator.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/latch.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/ring_buffer.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/schedule_policy.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/sync_wait.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/task.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/thread_local_context.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/thread_pool.hpp create mode 100644 cpp/mrc/include/mrc/coroutines/when_all.hpp create mode 100644 cpp/mrc/src/public/core/thread.cpp create mode 100644 cpp/mrc/src/public/coroutines/event.cpp create mode 100644 cpp/mrc/src/public/coroutines/sync_wait.cpp create mode 100644 cpp/mrc/src/public/coroutines/thread_local_context.cpp create mode 100644 cpp/mrc/src/public/coroutines/thread_pool.cpp create mode 100644 cpp/mrc/tests/coroutines/test_event.cpp create mode 100644 cpp/mrc/tests/coroutines/test_latch.cpp create mode 100644 cpp/mrc/tests/coroutines/test_ring_buffer.cpp create mode 100644 cpp/mrc/tests/coroutines/test_task.cpp create mode 100644 cpp/mrc/tests/test_thread.cpp diff --git a/cpp/mrc/include/mrc/core/thread.hpp b/cpp/mrc/include/mrc/core/thread.hpp new file mode 100644 index 000000000..c0d9785e7 --- /dev/null +++ b/cpp/mrc/include/mrc/core/thread.hpp @@ -0,0 +1,26 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +#pragma once + +#include + +namespace mrc::this_thread { + +const std::string& get_id(); + +} // namespace mrc::this_thread diff --git a/cpp/mrc/include/mrc/coroutines/concepts/awaitable.hpp b/cpp/mrc/include/mrc/coroutines/concepts/awaitable.hpp new file mode 100644 index 000000000..4b903669e --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/concepts/awaitable.hpp @@ -0,0 +1,112 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace mrc::coroutines::concepts { +/** + * This concept declares a type that is required to meet the c++20 coroutine operator co_await() + * retun type. It requires the following three member functions: + * await_ready() -> bool + * await_suspend(std::coroutine_handle<>) -> void|bool|std::coroutine_handle<> + * await_resume() -> decltype(auto) + * Where the return type on await_resume is the requested return of the awaitable. + */ +// clang-format off +template +concept awaiter = requires(T t, std::coroutine_handle<> c) +{ + { t.await_ready() } -> std::same_as; + requires std::same_as || + std::same_as || + std::same_as>; + { t.await_resume() }; +}; + +/** + * This concept declares a type that can be operator co_await()'ed and returns an awaiter_type. + */ +template +concept awaitable = requires(T t) +{ + // operator co_await() + { t.operator co_await() } -> awaiter; +}; + +template +concept awaiter_void = requires(T t, std::coroutine_handle<> c) +{ + { t.await_ready() } -> std::same_as; + requires std::same_as || + std::same_as || + std::same_as>; + {t.await_resume()} -> std::same_as; +}; + +template +concept awaitable_void = requires(T t) +{ + // operator co_await() + { t.operator co_await() } -> awaiter_void; +}; + +template +struct awaitable_traits +{ +}; + +template +static auto get_awaiter(AwaitableT&& value) +{ + return std::forward(value).operator co_await(); +} + +template +struct awaitable_traits +{ + using awaiter_type = decltype(get_awaiter(std::declval())); + using awaiter_return_type = decltype(std::declval().await_resume()); +}; +// clang-format on + +} // namespace mrc::coroutines::concepts diff --git a/cpp/mrc/include/mrc/coroutines/concepts/buffer.hpp b/cpp/mrc/include/mrc/coroutines/concepts/buffer.hpp new file mode 100644 index 000000000..47b880d19 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/concepts/buffer.hpp @@ -0,0 +1,65 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace mrc::coroutines::concepts { + +// clang-format off +template +concept const_buffer = requires(const T t) +{ + { t.empty() } -> std::same_as; + { t.data() } -> std::same_as; + { t.size() } -> std::same_as; +}; + +template +concept mutable_buffer = requires(T t) +{ + { t.empty() } -> std::same_as; + { t.data() } -> std::same_as; + { t.size() } -> std::same_as; +}; +// clang-format on + +} // namespace mrc::coroutines::concepts diff --git a/cpp/mrc/include/mrc/coroutines/concepts/executor.hpp b/cpp/mrc/include/mrc/coroutines/concepts/executor.hpp new file mode 100644 index 000000000..f39befd75 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/concepts/executor.hpp @@ -0,0 +1,58 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/awaitable.hpp" + +#include +#include + +namespace mrc::coroutines::concepts { + +// clang-format off +template +concept executor = requires(T t, std::coroutine_handle<> c) +{ + { t.schedule() } -> awaiter; + { t.yield() } -> awaiter; + { t.resume(c) } -> std::same_as; +}; +// clang-format on + +} // namespace mrc::coroutines::concepts diff --git a/cpp/mrc/include/mrc/coroutines/concepts/promise.hpp b/cpp/mrc/include/mrc/coroutines/concepts/promise.hpp new file mode 100644 index 000000000..a88a42d3f --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/concepts/promise.hpp @@ -0,0 +1,64 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/awaitable.hpp" + +#include + +namespace mrc::coroutines::concepts { + +// clang-format off +template +concept promise = requires(T t) +{ + { t.get_return_object() } -> std::convertible_to>; + { t.initial_suspend() } -> awaiter; + { t.final_suspend() } -> awaiter; + { t.yield_value() } -> awaitable; +} +&& requires(T t, ReturnT return_value) +{ + requires std::same_as || + std::same_as || + requires { t.yield_value(return_value); }; +}; +// clang-format on + +} // namespace mrc::coroutines::concepts diff --git a/cpp/mrc/include/mrc/coroutines/concepts/range_of.hpp b/cpp/mrc/include/mrc/coroutines/concepts/range_of.hpp new file mode 100644 index 000000000..a25e45367 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/concepts/range_of.hpp @@ -0,0 +1,60 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include +#include + +namespace mrc::coroutines::concepts { +// clang-format off + +/** + * Concept to require that the range contains a specific type of value. + */ +template +concept range_of = std::ranges::range && std::is_same_v>; + +/** + * Concept to require that a sized range contains a specific type of value. + */ +template +concept sized_range_of = std::ranges::sized_range && std::is_same_v>; + +// clang-format on +} // namespace mrc::coroutines::concepts diff --git a/cpp/mrc/include/mrc/coroutines/detail/void_value.hpp b/cpp/mrc/include/mrc/coroutines/detail/void_value.hpp new file mode 100644 index 000000000..af8cb8ff9 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/detail/void_value.hpp @@ -0,0 +1,45 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +namespace mrc::coroutines::detail { +struct VoidValue +{}; + +} // namespace mrc::coroutines::detail diff --git a/cpp/mrc/include/mrc/coroutines/event.hpp b/cpp/mrc/include/mrc/coroutines/event.hpp new file mode 100644 index 000000000..6211bf361 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/event.hpp @@ -0,0 +1,207 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/executor.hpp" +#include "mrc/coroutines/thread_local_context.hpp" + +#include +#include + +namespace mrc::coroutines { + +enum class ResumeOrderPolicy +{ + /// Last in first out, this is the default policy and will execute the fastest + /// if you do not need the first waiter to execute first upon the event being set. + lifo, + /// First in first out, this policy has an extra overhead to reverse the order of + /// the waiters but will guarantee the ordering is fifo. + fifo +}; + +/** + * Event is a manully triggered thread safe signal that can be co_await()'ed by multiple awaiters. + * Each awaiter should co_await the event and upon the event being set each awaiter will have their + * coroutine resumed. + * + * The event can be manually reset to the un-set state to be re-used. + * \code +t1: coroutines::event e; +... +t2: func(coroutines::event& e) { ... co_await e; ... } +... +t1: do_work(); +t1: e.set(); +... +t2: resume() + * \endcode + */ +class Event +{ + public: + struct Awaiter : ThreadLocalContext + { + /** + * @param e The event to wait for it to be set. + */ + Awaiter(const Event& e) noexcept : m_event(e) {} + + /** + * @return True if the event is already set, otherwise false to suspend this coroutine. + */ + auto await_ready() const noexcept -> bool + { + return m_event.is_set(); + } + + /** + * Adds this coroutine to the list of awaiters in a thread safe fashion. If the event + * is set while attempting to add this coroutine to the awaiters then this will return false + * to resume execution immediately. + * @return False if the event is already set, otherwise true to suspend this coroutine. + */ + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool; + + /** + * Nothing to do on resume. + */ + auto await_resume() noexcept -> void; + + /** + * @brief Used to resume the coroutine + */ + void resume(); + + /// Refernce to the event that this awaiter is waiting on. + const Event& m_event; + /// The awaiting continuation coroutine handle. + std::coroutine_handle<> m_awaiting_coroutine; + /// The next awaiter in line for this event, nullptr if this is the end. + Awaiter* m_next{nullptr}; + }; + + /** + * Creates an event with the given initial state of being set or not set. + * @param initially_set By default all events start as not set, but if needed this parameter can + * set the event to already be triggered. + */ + explicit Event(bool initially_set = false) noexcept; + ~Event() = default; + + Event(const Event&) = delete; + Event(Event&&) = delete; + auto operator=(const Event&) -> Event& = delete; + auto operator=(Event&&) -> Event& = delete; + + /** + * @return True if this event is currently in the set state. + */ + auto is_set() const noexcept -> bool + { + return m_state.load(std::memory_order_acquire) == this; + } + + /** + * Sets this event and resumes all awaiters. Note that all waiters will be resumed onto this + * thread of execution. + * @param policy The order in which the waiters should be resumed, defaults to LIFO since it + * is more efficient, FIFO requires reversing the order of the waiters first. + */ + auto set(ResumeOrderPolicy policy = ResumeOrderPolicy::lifo) noexcept -> void; + + /** + * Sets this event and resumes all awaiters onto the given executor. This will distribute + * the waiters across the executor's threads. + */ + template + auto set(ExecutorT& e, ResumeOrderPolicy policy = ResumeOrderPolicy::lifo) noexcept -> void + { + void* old_value = m_state.exchange(this, std::memory_order::acq_rel); + if (old_value != this) + { + // If FIFO has been requsted then reverse the order upon resuming. + if (policy == ResumeOrderPolicy::fifo) + { + old_value = reverse(static_cast(old_value)); + } + // else lifo nothing to do + + auto* waiters = static_cast(old_value); + while (waiters != nullptr) + { + auto* next = waiters->m_next; + e.resume(waiters->m_awaiting_coroutine); + waiters = next; + } + } + } + + /** + * @return An awaiter struct to suspend and resume this coroutine for when the event is set. + */ + auto operator co_await() const noexcept -> Awaiter + { + return {*this}; + } + + /** + * Resets the event from set to not set so it can be re-used. If the event is not currently + * set then this function has no effect. + */ + auto reset() noexcept -> void; + + protected: + /// For access to m_state. + friend struct Awaiter; + /// The state of the event, nullptr is not set with zero awaiters. Set to an awaiter* there are + /// coroutines awaiting the event to be set, and set to this the event has triggered. + /// 1) nullptr == not set + /// 2) awaiter* == linked list of awaiters waiting for the event to trigger. + /// 3) this == The event is triggered and all awaiters are resumed. + mutable std::atomic m_state; + + private: + /** + * Reverses the set of waiters from LIFO->FIFO and returns the new head. + */ + static auto reverse(Awaiter* curr) -> Awaiter*; +}; + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/generator.hpp b/cpp/mrc/include/mrc/coroutines/generator.hpp new file mode 100644 index 000000000..03967e4ad --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/generator.hpp @@ -0,0 +1,255 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace mrc::coroutines { + +template +class Generator; + +namespace detail { + +template +class GeneratorPromise +{ + public: + using value_type = std::remove_reference_t; + using reference_type = std::conditional_t, T, T&>; + using pointer_type = value_type*; + + GeneratorPromise() = default; + + auto get_return_object() noexcept -> Generator; + + auto initial_suspend() const + { + return std::suspend_always{}; + } + + auto final_suspend() const noexcept(true) + { + return std::suspend_always{}; + } + + template ::value, int> = 0> + auto yield_value(std::remove_reference_t& value) noexcept + { + m_value = std::addressof(value); + return std::suspend_always{}; + } + + auto yield_value(std::remove_reference_t&& value) noexcept + { + m_value = std::addressof(value); + return std::suspend_always{}; + } + + auto unhandled_exception() -> void + { + m_exception = std::current_exception(); + } + + auto return_void() noexcept -> void {} + + auto value() const noexcept -> reference_type + { + return static_cast(*m_value); + } + + template + auto await_transform(U&& value) -> std::suspend_never = delete; + + auto rethrow_if_exception() -> void + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } + + private: + pointer_type m_value{nullptr}; + std::exception_ptr m_exception; +}; + +struct GeneratorSentinel +{}; + +template +class GeneratorIterator +{ + using coroutine_handle = std::coroutine_handle>; // NOLINT + + public: + using iterator_category = std::input_iterator_tag; // NOLINT + using difference_type = std::ptrdiff_t; + using value_type = typename GeneratorPromise::value_type; + using reference = typename GeneratorPromise::reference_type; // NOLINT + using pointer = typename GeneratorPromise::pointer_type; // NOLINT + + GeneratorIterator() noexcept = default; + + explicit GeneratorIterator(coroutine_handle coroutine) noexcept : m_coroutine(coroutine) {} + + friend auto operator==(const GeneratorIterator& it, GeneratorSentinel /*unused*/) noexcept -> bool + { + return it.m_coroutine == nullptr || it.m_coroutine.done(); + } + + friend auto operator!=(const GeneratorIterator& it, GeneratorSentinel s) noexcept -> bool + { + return !(it == s); + } + + friend auto operator==(GeneratorSentinel s, const GeneratorIterator& it) noexcept -> bool + { + return (it == s); + } + + friend auto operator!=(GeneratorSentinel s, const GeneratorIterator& it) noexcept -> bool + { + return it != s; + } + + GeneratorIterator& operator++() + { + m_coroutine.resume(); + if (m_coroutine.done()) + { + m_coroutine.promise().rethrow_if_exception(); + } + + return *this; + } + + auto operator++(int) -> void + { + (void)operator++(); + } + + reference operator*() const noexcept + { + return m_coroutine.promise().value(); + } + + pointer operator->() const noexcept + { + return std::addressof(operator*()); + } + + private: + coroutine_handle m_coroutine{nullptr}; +}; + +} // namespace detail + +template +class Generator +{ + public: + using promise_type = detail::GeneratorPromise; + using iterator = detail::GeneratorIterator; // NOLINT + using sentinel = detail::GeneratorSentinel; // NOLINT + + Generator() noexcept : m_coroutine(nullptr) {} + + Generator(const Generator&) = delete; + Generator(Generator&& other) noexcept : m_coroutine(other.m_coroutine) + { + other.m_coroutine = nullptr; + } + + auto operator=(const Generator&) = delete; + auto operator=(Generator&& other) noexcept -> Generator& + { + m_coroutine = other.m_coroutine; + other.m_coroutine = nullptr; + + return *this; + } + + ~Generator() + { + if (m_coroutine) + { + m_coroutine.destroy(); + } + } + + auto begin() -> iterator + { + if (m_coroutine != nullptr) + { + m_coroutine.resume(); + if (m_coroutine.done()) + { + m_coroutine.promise().rethrow_if_exception(); + } + } + + return iterator{m_coroutine}; + } + + auto end() noexcept -> sentinel + { + return sentinel{}; + } + + private: + friend class detail::GeneratorPromise; + + explicit Generator(std::coroutine_handle coroutine) noexcept : m_coroutine(coroutine) {} + + std::coroutine_handle m_coroutine; +}; + +namespace detail { +template +auto GeneratorPromise::get_return_object() noexcept -> Generator +{ + return Generator{std::coroutine_handle>::from_promise(*this)}; +} + +} // namespace detail + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/latch.hpp b/cpp/mrc/include/mrc/coroutines/latch.hpp new file mode 100644 index 000000000..9c2af6751 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/latch.hpp @@ -0,0 +1,126 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/event.hpp" +#include "mrc/coroutines/thread_pool.hpp" + +#include + +namespace mrc::coroutines { +/** + * The latch is thread safe counter to wait for 1 or more other tasks to complete, they signal their + * completion by calling `count_down()` on the latch and upon the latch counter reaching zero the + * coroutine `co_await`ing the latch then resumes execution. + * + * This is useful for spawning many worker tasks to complete either a computationally complex task + * across a thread pool of workers, or waiting for many asynchronous results like http requests + * to complete. + */ +class Latch +{ + public: + /** + * Creates a latch with the given count of tasks to wait to complete. + * @param count The number of tasks to wait to complete, if this is zero or negative then the + * latch starts 'completed' immediately and execution is resumed with no suspension. + */ + Latch(std::ptrdiff_t count) noexcept : m_count(count), m_event(count <= 0) {} + + Latch(const Latch&) = delete; + Latch(Latch&&) noexcept = delete; + auto operator=(const Latch&) -> Latch& = delete; + auto operator=(Latch&&) noexcept -> Latch& = delete; + + /** + * @return True if the latch has been counted down to zero. + */ + auto is_ready() const noexcept -> bool + { + return m_event.is_set(); + } + + /** + * @return The number of tasks this latch is still waiting to complete. + */ + auto remaining() const noexcept -> std::size_t + { + return m_count.load(std::memory_order::acquire); + } + + /** + * If the latch counter goes to zero then the task awaiting the latch is resumed. + * @param n The number of tasks to complete towards the latch, defaults to 1. + */ + auto count_down(std::ptrdiff_t n = 1) noexcept -> void + { + if (m_count.fetch_sub(n, std::memory_order::acq_rel) <= n) + { + m_event.set(); + } + } + + /** + * If the latch counter goes to then the task awaiting the latch is resumed on the given + * thread pool. + * @param tp The thread pool to schedule the task that is waiting on the latch on. + * @param n The number of tasks to complete towards the latch, defaults to 1. + */ + auto count_down(ThreadPool& tp, std::ptrdiff_t n = 1) noexcept -> void + { + if (m_count.fetch_sub(n, std::memory_order::acq_rel) <= n) + { + m_event.set(tp); + } + } + + auto operator co_await() const noexcept -> Event::Awaiter + { + return m_event.operator co_await(); + } + + private: + /// The number of tasks to wait for completion before triggering the event to resume. + std::atomic m_count; + /// The event to trigger when the latch counter reaches zero, this resume the coroutine that + /// is co_await'ing on the latch. + Event m_event; +}; + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/ring_buffer.hpp b/cpp/mrc/include/mrc/coroutines/ring_buffer.hpp new file mode 100644 index 000000000..94625ff4b --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/ring_buffer.hpp @@ -0,0 +1,520 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/core/std23_expected.hpp" +#include "mrc/coroutines/schedule_policy.hpp" +#include "mrc/coroutines/thread_local_context.hpp" +#include "mrc/coroutines/thread_pool.hpp" + +#include + +#include +#include +#include +#include +#include + +namespace mrc::coroutines { + +enum class RingBufferOpStatus +{ + Success, + Stopped, +}; + +/** + * @tparam ElementT The type of element the ring buffer will store. Note that this type should be + * cheap to move if possible as it is moved into and out of the buffer upon write and + * read operations. + */ +template +class RingBuffer +{ + using mutex_type = std::mutex; + + public: + struct Options + { + // capacity of ring buffer + std::size_t capacity{8}; + + // when there is an awaiting reader, the active execution context of the next writer will resume the awaiting + // reader, the schedule_policy_t dictates how that is accomplished. + SchedulePolicy reader_policy{SchedulePolicy::Reschedule}; + + // when there is an awaiting writer, the active execution context of the next reader will resume the awaiting + // writer, the producder_policy_t dictates how that is accomplished. + SchedulePolicy writer_policy{SchedulePolicy::Reschedule}; + }; + + /** + * @throws std::runtime_error If `num_elements` == 0. + */ + explicit RingBuffer(Options opts = {}) : + m_elements(opts.capacity), // elements needs to be extended from just holding ElementT to include a TraceContext + m_num_elements(opts.capacity), + m_writer_policy(opts.writer_policy), + m_reader_policy(opts.reader_policy) + { + if (m_num_elements == 0) + { + throw std::runtime_error{"num_elements cannot be zero"}; + } + } + + ~RingBuffer() + { + // Wake up anyone still using the ring buffer. + notify_waiters(); + } + + RingBuffer(const RingBuffer&) = delete; + RingBuffer(RingBuffer&&) = delete; + + auto operator=(const RingBuffer&) noexcept -> RingBuffer& = delete; + auto operator=(RingBuffer&&) noexcept -> RingBuffer& = delete; + + struct WriteOperation : ThreadLocalContext + { + WriteOperation(RingBuffer& rb, ElementT e) : + m_rb(rb), + m_e(std::move(e)), + m_policy(m_rb.m_writer_policy) + {} + + auto await_ready() noexcept -> bool + { + // return immediate if the buffer is closed + if (m_rb.m_stopped.load(std::memory_order::acquire)) + { + m_stopped = true; + return true; + } + + // start a span to time the write - this would include time suspended if the buffer is full + // m_write_span->AddEvent("start_on", {{"thead.id", mrc::this_thread::get_id()}}); + + // the lock is owned by the operation, not scoped to the await_ready function + m_lock = std::unique_lock(m_rb.m_mutex); + return m_rb.try_write_locked(m_lock, m_e); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + // m_lock was acquired as part of await_ready; await_suspend is responsible for releasing the lock + auto lock = std::move(m_lock); // use raii + + ThreadLocalContext::suspend_thread_local_context(); + + m_awaiting_coroutine = awaiting_coroutine; + m_next = m_rb.m_write_waiters; + m_rb.m_write_waiters = this; + return true; + } + + /** + * @return write_result + */ + auto await_resume() -> RingBufferOpStatus + { + ThreadLocalContext::resume_thread_local_context(); + return (!m_stopped ? RingBufferOpStatus::Success : RingBufferOpStatus::Stopped); + } + + WriteOperation& use_scheduling_policy(SchedulePolicy policy) + { + m_policy = policy; + return *this; + } + + WriteOperation& resume_immediately() + { + m_policy = SchedulePolicy::Immediate; + return *this; + } + + WriteOperation& resume_on(ThreadPool* thread_pool) + { + m_policy = SchedulePolicy::Reschedule; + set_resume_on_thread_pool(thread_pool); + return *this; + } + + private: + friend RingBuffer; + + void resume() + { + if (m_policy == SchedulePolicy::Immediate) + { + set_resume_on_thread_pool(nullptr); + } + resume_coroutine(m_awaiting_coroutine); + } + + /// The lock is acquired in await_ready; if ready it is release; otherwise, await_suspend should release it + std::unique_lock m_lock; + /// The ring buffer the element is being written into. + RingBuffer& m_rb; + /// If the operation needs to suspend, the coroutine to resume when the element can be written. + std::coroutine_handle<> m_awaiting_coroutine; + /// Linked list of write operations that are awaiting to write their element. + WriteOperation* m_next{nullptr}; + /// The element this write operation is producing into the ring buffer. + ElementT m_e; + /// Was the operation stopped? + bool m_stopped{false}; + /// Scheduling Policy - default provided by the RingBuffer, but can be overrided owner of the Awaiter + SchedulePolicy m_policy; + /// Span to measure the duration the writer spent writting data + // trace::Handle m_write_span{nullptr}; + }; + + struct ReadOperation : ThreadLocalContext + { + explicit ReadOperation(RingBuffer& rb) : m_rb(rb), m_policy(m_rb.m_reader_policy) {} + + auto await_ready() noexcept -> bool + { + // the lock is owned by the operation, not scoped to the await_ready function + m_lock = std::unique_lock(m_rb.m_mutex); + // m_read_span->AddEvent("start_on", {{"thead.id", mrc::this_thread::get_id()}}); + return m_rb.try_read_locked(m_lock, this); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + // m_lock was acquired as part of await_ready; await_suspend is responsible for releasing the lock + auto lock = std::move(m_lock); + + // the buffer is empty; don't suspend if the stop signal has been set. + if (m_rb.m_stopped.load(std::memory_order::acquire)) + { + m_stopped = true; + return false; + } + + // m_read_span->AddEvent("buffer_empty"); + ThreadLocalContext::suspend_thread_local_context(); + + m_awaiting_coroutine = awaiting_coroutine; + m_next = m_rb.m_read_waiters; + m_rb.m_read_waiters = this; + return true; + } + + /** + * @return The consumed element or std::nullopt if the read has failed. + */ + auto await_resume() -> std23::expected + { + ThreadLocalContext::resume_thread_local_context(); + + if (m_stopped) + { + return std23::unexpected(RingBufferOpStatus::Stopped); + } + + return std::move(m_e); + } + + ReadOperation& use_scheduling_policy(SchedulePolicy policy) + { + m_policy = policy; + return *this; + } + + ReadOperation& resume_immediately() + { + m_policy = SchedulePolicy::Immediate; + return *this; + } + + ReadOperation& resume_on(ThreadPool* thread_pool) + { + m_policy = SchedulePolicy::Reschedule; + set_resume_on_thread_pool(thread_pool); + return *this; + } + + private: + friend RingBuffer; + + void resume() + { + if (m_policy == SchedulePolicy::Immediate) + { + set_resume_on_thread_pool(nullptr); + } + resume_coroutine(m_awaiting_coroutine); + } + + /// The lock is acquired in await_ready; if ready it is release; otherwise, await_suspend should release it + std::unique_lock m_lock; + /// The ring buffer to read an element from. + RingBuffer& m_rb; + /// If the operation needs to suspend, the coroutine to resume when the element can be consumed. + std::coroutine_handle<> m_awaiting_coroutine; + /// Linked list of read operations that are awaiting to read an element. + ReadOperation* m_next{nullptr}; + /// The element this read operation will read. + ElementT m_e; + /// Was the operation stopped? + bool m_stopped{false}; + /// Scheduling Policy - default provided by the RingBuffer, but can be overrided owner of the Awaiter + SchedulePolicy m_policy; + /// Span measure time awaiting on reading data + // trace::Handle m_read_span; + }; + + /** + * Produces the given element into the ring buffer. This operation will suspend until a slot + * in the ring buffer becomes available. + * @param e The element to write. + */ + [[nodiscard]] auto write(ElementT e) -> WriteOperation + { + return WriteOperation{*this, std::move(e)}; + } + + /** + * Consumes an element from the ring buffer. This operation will suspend until an element in + * the ring buffer becomes available. + */ + [[nodiscard]] auto read() -> ReadOperation + { + return ReadOperation{*this}; + } + + void close() + { + // if there are awaiting readers, then we must wait them up and signal that the buffer is closed; + // otherwise, mark the buffer as closed and fail all new writes immediately. readers should be allowed + // to keep reading until the buffer is empty. when the buffer is empty, readers will fail to suspend and exit + // with a stopped status + + // Only wake up waiters once. + if (m_stopped.load(std::memory_order::acquire)) + { + return; + } + + std::unique_lock lk{m_mutex}; + m_stopped.exchange(true, std::memory_order::release); + + // the buffer is empty and no more items will be added + if (m_used == 0) + { + // there should be no awaiting writers + CHECK(m_write_waiters == nullptr); + + // signal all awaiting readers that the buffer is stopped + while (m_read_waiters != nullptr) + { + auto* to_resume = m_read_waiters; + to_resume->m_stopped = true; + m_read_waiters = m_read_waiters->m_next; + + lk.unlock(); + to_resume->resume(); + lk.lock(); + } + } + } + + bool is_closed() const noexcept + { + return m_stopped.load(std::memory_order::acquire); + } + + /** + * @return The current number of elements contained in the ring buffer. + */ + auto size() const -> size_t + { + std::atomic_thread_fence(std::memory_order::acquire); + return m_used; + } + + /** + * @return True if the ring buffer contains zero elements. + */ + auto empty() const -> bool + { + return size() == 0; + } + + /** + * Wakes up all currently awaiting writers and readers. Their await_resume() function + * will return an expected read result that the ring buffer has stopped. + */ + auto notify_waiters() -> void + { + // Only wake up waiters once. + if (m_stopped.load(std::memory_order::acquire)) + { + return; + } + + std::unique_lock lk{m_mutex}; + m_stopped.exchange(true, std::memory_order::release); + + while (m_write_waiters != nullptr) + { + auto* to_resume = m_write_waiters; + to_resume->m_stopped = true; + m_write_waiters = m_write_waiters->m_next; + + lk.unlock(); + to_resume->resume(); + lk.lock(); + } + + while (m_read_waiters != nullptr) + { + auto* to_resume = m_read_waiters; + to_resume->m_stopped = true; + m_read_waiters = m_read_waiters->m_next; + + lk.unlock(); + to_resume->resume(); + lk.lock(); + } + } + + private: + friend WriteOperation; + friend ReadOperation; + + mutex_type m_mutex{}; + + std::vector m_elements; + const std::size_t m_num_elements; + const SchedulePolicy m_writer_policy; + const SchedulePolicy m_reader_policy; + + /// The current front pointer to an open slot if not full. + size_t m_front{0}; + /// The current back pointer to the oldest item in the buffer if not empty. + size_t m_back{0}; + /// The number of items in the ring buffer. + size_t m_used{0}; + + /// The LIFO list of write waiters - single writers will have order perserved + // Note: if there are multiple writers order can not be guaranteed, so no need for FIFO + WriteOperation* m_write_waiters{nullptr}; + /// The LIFO list of read watier. + ReadOperation* m_read_waiters{nullptr}; + + std::atomic m_stopped{false}; + + auto try_write_locked(std::unique_lock& lk, ElementT& e) -> bool + { + if (m_used == m_num_elements) + { + DCHECK(m_read_waiters == nullptr); + return false; + } + + m_elements[m_front] = std::move(e); + m_front = (m_front + 1) % m_num_elements; + ++m_used; + + ReadOperation* to_resume = nullptr; + + if (m_read_waiters != nullptr) + { + to_resume = m_read_waiters; + m_read_waiters = m_read_waiters->m_next; + + // Since the read operation suspended it needs to be provided an element to read. + to_resume->m_e = std::move(m_elements[m_back]); + m_back = (m_back + 1) % m_num_elements; + --m_used; // And we just consumed up another item. + } + + // release lock + lk.unlock(); + + if (to_resume != nullptr) + { + to_resume->resume(); + } + + return true; + } + + auto try_read_locked(std::unique_lock& lk, ReadOperation* op) -> bool + { + if (m_used == 0) + { + return false; + } + + op->m_e = std::move(m_elements[m_back]); + m_back = (m_back + 1) % m_num_elements; + --m_used; + + WriteOperation* to_resume = nullptr; + + if (m_write_waiters != nullptr) + { + to_resume = m_write_waiters; + m_write_waiters = m_write_waiters->m_next; + + // Since the write operation suspended it needs to be provided a slot to place its element. + m_elements[m_front] = std::move(to_resume->m_e); + m_front = (m_front + 1) % m_num_elements; + ++m_used; // And we just written another item. + } + + // release lock + lk.unlock(); + + if (to_resume != nullptr) + { + to_resume->resume(); + } + + return true; + } +}; + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/schedule_policy.hpp b/cpp/mrc/include/mrc/coroutines/schedule_policy.hpp new file mode 100644 index 000000000..d66af09d1 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/schedule_policy.hpp @@ -0,0 +1,28 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +#pragma once + +namespace mrc::coroutines { + +enum class SchedulePolicy +{ + Immediate, + Reschedule +}; + +} diff --git a/cpp/mrc/include/mrc/coroutines/sync_wait.hpp b/cpp/mrc/include/mrc/coroutines/sync_wait.hpp new file mode 100644 index 000000000..4c841fcc6 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/sync_wait.hpp @@ -0,0 +1,285 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/awaitable.hpp" +#include "mrc/coroutines/when_all.hpp" + +#include +#include + +namespace mrc::coroutines { + +namespace detail { + +class SyncWaitEvent +{ + public: + SyncWaitEvent(bool initially_set = false); + SyncWaitEvent(const SyncWaitEvent&) = delete; + SyncWaitEvent(SyncWaitEvent&&) = delete; + auto operator=(const SyncWaitEvent&) -> SyncWaitEvent& = delete; + auto operator=(SyncWaitEvent&&) -> SyncWaitEvent& = delete; + ~SyncWaitEvent() = default; + + auto set() noexcept -> void; + auto reset() noexcept -> void; + auto wait() noexcept -> void; + + private: + std::mutex m_mutex; + std::condition_variable m_cv; + bool m_set{false}; +}; + +class SyncWaitTaskPromiseBase +{ + public: + SyncWaitTaskPromiseBase() noexcept = default; + virtual ~SyncWaitTaskPromiseBase() = default; + + constexpr static auto initial_suspend() noexcept -> std::suspend_always + { + return {}; + } + + auto unhandled_exception() -> void + { + m_exception = std::current_exception(); + } + + protected: + SyncWaitEvent* m_event{nullptr}; + std::exception_ptr m_exception; +}; + +template +class SyncWaitTaskPromise : public SyncWaitTaskPromiseBase +{ + public: + using coroutine_type = std::coroutine_handle>; + + SyncWaitTaskPromise() noexcept = default; + ~SyncWaitTaskPromise() override = default; + + auto start(SyncWaitEvent& event) + { + m_event = &event; + coroutine_type::from_promise(*this).resume(); + } + + auto get_return_object() noexcept + { + return coroutine_type::from_promise(*this); + } + + auto yield_value(ReturnT&& value) noexcept + { + m_return_value = std::addressof(value); + return final_suspend(); + } + + auto final_suspend() noexcept + { + struct CompletionNotifier + { + auto await_ready() const noexcept + { + return false; + } + auto await_suspend(coroutine_type coroutine) const noexcept + { + coroutine.promise().m_event->set(); + } + auto await_resume() noexcept {}; + }; + + return CompletionNotifier{}; + } + + auto result() -> ReturnT&& + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + + return static_cast(*m_return_value); + } + + private: + std::remove_reference_t* m_return_value; +}; + +template <> +class SyncWaitTaskPromise : public SyncWaitTaskPromiseBase +{ + using coroutine_type = std::coroutine_handle>; + + public: + SyncWaitTaskPromise() noexcept = default; + ~SyncWaitTaskPromise() override = default; + + auto start(SyncWaitEvent& event) + { + m_event = &event; + coroutine_type::from_promise(*this).resume(); + } + + auto get_return_object() noexcept + { + return coroutine_type::from_promise(*this); + } + + static auto final_suspend() noexcept + { + struct CompletionNotifier + { + constexpr static auto await_ready() noexcept + { + return false; + } + + static auto await_suspend(coroutine_type coroutine) noexcept + { + coroutine.promise().m_event->set(); + } + + constexpr static auto await_resume() noexcept {}; + }; + + return CompletionNotifier{}; + } + + auto return_void() noexcept -> void {} + + auto result() -> void + { + if (m_exception) + { + std::rethrow_exception(m_exception); + } + } +}; + +template +class SyncWaitTask +{ + public: + using promise_type = SyncWaitTaskPromise; + using coroutine_type = std::coroutine_handle; + + SyncWaitTask(coroutine_type coroutine) noexcept : m_coroutine(coroutine) {} + + SyncWaitTask(const SyncWaitTask&) = delete; + SyncWaitTask(SyncWaitTask&& other) noexcept : m_coroutine(std::exchange(other.m_coroutine, coroutine_type{})) {} + auto operator=(const SyncWaitTask&) -> SyncWaitTask& = delete; + auto operator=(SyncWaitTask&& other) -> SyncWaitTask& + { + if (std::addressof(other) != this) + { + m_coroutine = std::exchange(other.m_coroutine, coroutine_type{}); + } + + return *this; + } + + ~SyncWaitTask() + { + if (m_coroutine) + { + m_coroutine.destroy(); + } + } + + auto start(SyncWaitEvent& event) noexcept + { + m_coroutine.promise().start(event); + } + + auto return_value() -> decltype(auto) + { + if constexpr (std::is_same_v) + { + // Propagate exceptions. + m_coroutine.promise().result(); + return; + } + else + { + return m_coroutine.promise().result(); + } + } + + private: + coroutine_type m_coroutine; +}; + +template ::awaiter_return_type> +static auto make_sync_wait_task(AwaitableT&& a) -> SyncWaitTask; + +template +static auto make_sync_wait_task(AwaitableT&& a) -> SyncWaitTask +{ + if constexpr (std::is_void_v) + { + co_await std::forward(a); + co_return; + } + else + { + co_yield co_await std::forward(a); + } +} + +} // namespace detail + +template +auto sync_wait(AwaitableT&& a) -> decltype(auto) +{ + detail::SyncWaitEvent e{}; + auto task = detail::make_sync_wait_task(std::forward(a)); + task.start(e); + e.wait(); + + return task.return_value(); +} + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/task.hpp b/cpp/mrc/include/mrc/coroutines/task.hpp new file mode 100644 index 000000000..7530c86bc --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/task.hpp @@ -0,0 +1,346 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/promise.hpp" +#include "mrc/coroutines/thread_local_context.hpp" + +#include + +#include +#include +#include + +namespace mrc::coroutines { + +template +class Task; + +namespace detail { +struct PromiseBase +{ + friend struct FinalAwaitable; + + struct FinalAwaitable : ThreadLocalContext + { + constexpr static auto await_ready() noexcept -> bool + { + return false; + } + + template + auto await_suspend(std::coroutine_handle coroutine) noexcept -> std::coroutine_handle<> + { + // If there is a continuation call it, otherwise this is the end of the line. + auto& promise = coroutine.promise(); + if (promise.m_continuation != nullptr) + { + return promise.m_continuation; + } + + return std::noop_coroutine(); + } + + // on the final awaitable, we do not resume the captured thread local state + constexpr static auto await_resume() noexcept -> void {} + }; + + PromiseBase() noexcept = default; + ~PromiseBase() = default; + + constexpr static auto initial_suspend() -> std::suspend_always + { + return {}; + } + + constexpr static auto final_suspend() noexcept(true) -> FinalAwaitable + { + return {}; + } + + auto unhandled_exception() -> void + { + m_exception_ptr = std::current_exception(); + } + + auto continuation(std::coroutine_handle<> continuation) noexcept -> void + { + m_continuation = continuation; + } + + protected: + std::coroutine_handle<> m_continuation{nullptr}; + std::exception_ptr m_exception_ptr{}; +}; + +template +struct Promise final : public PromiseBase +{ + using task_type = Task; + using coroutine_type = std::coroutine_handle>; + + Promise() noexcept = default; + ~Promise() = default; + + auto get_return_object() noexcept -> task_type; + + auto return_value(ReturnT value) -> void + { + m_return_value = std::move(value); + } + + auto result() const& -> const ReturnT& + { + if (m_exception_ptr) + { + std::rethrow_exception(m_exception_ptr); + } + + return m_return_value; + } + + auto result() && -> ReturnT&& + { + if (m_exception_ptr) + { + std::rethrow_exception(m_exception_ptr); + } + + return std::move(m_return_value); + } + + private: + ReturnT m_return_value; +}; + +template <> +struct Promise : public PromiseBase +{ + using task_type = Task; + using coroutine_type = std::coroutine_handle>; + + Promise() noexcept = default; + ~Promise() = default; + + auto get_return_object() noexcept -> task_type; + + auto return_void() noexcept -> void {} + + auto result() -> void + { + if (m_exception_ptr) + { + std::rethrow_exception(m_exception_ptr); + } + } +}; + +} // namespace detail + +template +class [[nodiscard]] Task +{ + public: + using task_type = Task; + using promise_type = detail::Promise; + using coroutine_type = std::coroutine_handle; + + struct AwaitableBase : protected ThreadLocalContext + { + AwaitableBase(coroutine_type coroutine) noexcept : m_coroutine(coroutine) {} + + auto await_ready() const noexcept -> bool + { + return !m_coroutine || m_coroutine.done(); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> std::coroutine_handle<> + { + m_coroutine.promise().continuation(awaiting_coroutine); + return m_coroutine; + } + + std::coroutine_handle m_coroutine{nullptr}; + }; + + Task() noexcept : m_coroutine(nullptr) {} + + explicit Task(coroutine_type handle) : m_coroutine(handle) {} + Task(const Task&) = delete; + Task(Task&& other) noexcept : m_coroutine(std::exchange(other.m_coroutine, nullptr)) {} + + ~Task() + { + if (m_coroutine != nullptr) + { + m_coroutine.destroy(); + } + } + + auto operator=(const Task&) -> Task& = delete; + + auto operator=(Task&& other) noexcept -> Task& + { + if (std::addressof(other) != this) + { + if (m_coroutine != nullptr) + { + m_coroutine.destroy(); + } + + m_coroutine = std::exchange(other.m_coroutine, nullptr); + } + + return *this; + } + + /** + * @return True if the Task is in its final suspend or if the Task has been destroyed. + */ + auto is_ready() const noexcept -> bool + { + return m_coroutine == nullptr || m_coroutine.done(); + } + + auto resume() -> bool + { + if (!m_coroutine.done()) + { + ThreadLocalContext ctx; + ctx.suspend_thread_local_context(); + m_coroutine.resume(); + ctx.resume_thread_local_context(); + } + return !m_coroutine.done(); + } + + auto destroy() -> bool + { + if (m_coroutine != nullptr) + { + m_coroutine.destroy(); + m_coroutine = nullptr; + return true; + } + + return false; + } + + auto operator co_await() const& noexcept + { + struct Awaitable : public AwaitableBase + { + auto await_resume() -> decltype(auto) + { + if constexpr (std::is_same_v) + { + // Propagate uncaught exceptions. + this->m_coroutine.promise().result(); + return; + } + else + { + return this->m_coroutine.promise().result(); + } + } + }; + + return Awaitable{m_coroutine}; + } + + auto operator co_await() const&& noexcept + { + struct Awaitable : public AwaitableBase + { + auto await_resume() -> decltype(auto) + { + if constexpr (std::is_same_v) + { + // Propagate uncaught exceptions. + this->m_coroutine.promise().result(); + return; + } + else + { + return std::move(this->m_coroutine.promise()).result(); + } + } + }; + + return Awaitable{m_coroutine}; + } + + auto promise() & -> promise_type& + { + return m_coroutine.promise(); + } + + auto promise() const& -> const promise_type& + { + return m_coroutine.promise(); + } + auto promise() && -> promise_type&& + { + return std::move(m_coroutine.promise()); + } + + auto handle() -> coroutine_type + { + return m_coroutine; + } + + private: + coroutine_type m_coroutine{nullptr}; +}; + +namespace detail { +template +inline auto Promise::get_return_object() noexcept -> Task +{ + return Task{coroutine_type::from_promise(*this)}; +} + +inline auto Promise::get_return_object() noexcept -> Task<> +{ + return Task<>{coroutine_type::from_promise(*this)}; +} + +} // namespace detail + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/thread_local_context.hpp b/cpp/mrc/include/mrc/coroutines/thread_local_context.hpp new file mode 100644 index 000000000..d146fbaff --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/thread_local_context.hpp @@ -0,0 +1,96 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include +#include + +namespace mrc::coroutines { + +class ThreadPool; + +/** + * @brief The SRF Runtime has several third-party dependencies that make use of thread_local storage. Because + * coroutines can yield execution, other coroutines running on the same thread might modify the thread local storage + * which would have non-deterministic consequences for the resuming coroutine. Since coroutines can also migrate to + * other threads, it's important for the awaiter to capture any thread local state so it can be restored regardless of + * where the coroutine is resumed. + * + * This could be used to capture thread local state from libraries like CUDA or OpenTelemetry; however, at present time + * the cost to capture and restore thread local state far exceeds the benefits. + * + * This object will be used as a base for Awaiters in the hope that someday more thread local state can move as a + * context with a coroutine. In the meantime, ThreadLocalContext does capture one meaning thread local value, i.e. a + * pointer to the coroutines::ThreadPool that was executing the coroutine upto the point it was suspended. Capturing + * this information allows us to extend concept::awaiter objects to become concept::resumable objects where the + * programmer can provide guidance on how and where a coroutine should be resumed. + */ +class ThreadLocalContext +{ + public: + // use when suspending a coroutine + void suspend_thread_local_context(); + + // use when resuming a coroutine + void resume_thread_local_context(); + + protected: + // resume a suspended coroutine on either the captured thread_pool or a provided thread_pool + void resume_coroutine(std::coroutine_handle<> coroutine); + + // set the thread_pool on which to resume the suspended coroutine + void set_resume_on_thread_pool(ThreadPool* thread_pool); + + // if not nullptr, represents the thread pool on which the caller was executing when the coroutine was suspended + ThreadPool* thread_pool() const; + + private: + // Pointer to the active thread pool of the suspended coroutine; null if the coroutines was suspended from thread + // not in a mrc::coroutines::ThreadPool or if suspend_thread_local_context has not been called + ThreadPool* m_thread_pool{nullptr}; + + // TODO(ryan) - using m_should_resume only in debug mode + bool m_should_resume{false}; + + // We explored the idea of migrating the active cuda device id with coroutine awaiters, but unfortunately, + // the cost of capturing and resuming the thread_local CUDA device id is far too expensive to int + // int m_cuda_device_id{0}; +}; + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/thread_pool.hpp b/cpp/mrc/include/mrc/coroutines/thread_pool.hpp new file mode 100644 index 000000000..2f08b6c45 --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/thread_pool.hpp @@ -0,0 +1,329 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/range_of.hpp" +#include "mrc/coroutines/task.hpp" +#include "mrc/coroutines/thread_local_context.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mrc::coroutines { +/** + * Creates a thread pool that executes arbitrary coroutine tasks in a FIFO scheduler policy. + * The thread pool by default will create an execution thread per available core on the system. + * + * When shutting down, either by the thread pool destructing or by manually calling shutdown() + * the thread pool will stop accepting new tasks but will complete all tasks that were scheduled + * prior to the shutdown request. + */ +class ThreadPool +{ + public: + /** + * An operation is an awaitable type with a coroutine to resume the task scheduled on one of + * the executor threads. + */ + class Operation // : ThreadLocalContext + { + friend class ThreadPool; + /** + * Only thread_pools can create operations when a task is being scheduled. + * @param tp The thread pool that created this operation. + */ + explicit Operation(ThreadPool& tp) noexcept; + + public: + /** + * Operations always pause so the executing thread can be switched. + */ + constexpr static auto await_ready() noexcept -> bool + { + return false; + } + + /** + * Suspending always returns to the caller (using void return of await_suspend()) and + * stores the coroutine internally for the executing thread to resume from. + * Capture any thread-local state from the caller so it can be resumed on a thread from the pool. + */ + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> void; + + /** + * this is the function called first by the thread pool's executing thread. + * resume any thread local state that was captured on suspend + */ + auto await_resume() noexcept -> void; + + private: + /// The thread pool that this operation will execute on. + ThreadPool& m_thread_pool; + /// The coroutine awaiting execution. + std::coroutine_handle<> m_awaiting_coroutine{nullptr}; + /// Span to measure time spent being scheduled + // srf_OTEL_TRACE(trace::Handle m_span{nullptr}); + }; + + struct Options + { + /// The number of executor threads for this thread pool. Uses the hardware concurrency + /// value by default. + uint32_t thread_count = std::thread::hardware_concurrency(); + /// Functor to call on each executor thread upon starting execution. The parameter is the + /// thread's ID assigned to it by the thread pool. + std::function on_thread_start_functor = nullptr; + /// Functor to call on each executor thread upon stopping execution. The parameter is the + /// thread's ID assigned to it by the thread pool. + std::function on_thread_stop_functor = nullptr; + /// Description + std::string description; + }; + + /** + * @param opts Thread pool configuration options. + */ + explicit ThreadPool(Options opts = Options{.thread_count = std::thread::hardware_concurrency(), + .on_thread_start_functor = nullptr, + .on_thread_stop_functor = nullptr}); + + ThreadPool(const ThreadPool&) = delete; + ThreadPool(ThreadPool&&) = delete; + auto operator=(const ThreadPool&) -> ThreadPool& = delete; + auto operator=(ThreadPool&&) -> ThreadPool& = delete; + + virtual ~ThreadPool(); + + /** + * @return The number of executor threads for processing tasks. + */ + auto thread_count() const noexcept -> uint32_t + { + return m_threads.size(); + } + + /** + * Schedules the currently executing coroutine to be run on this thread pool. This must be + * called from within the coroutines function body to schedule the coroutine on the thread pool. + * @throw std::runtime_error If the thread pool is `shutdown()` scheduling new tasks is not permitted. + * @return The operation to switch from the calling scheduling thread to the executor thread + * pool thread. + */ + [[nodiscard]] auto schedule() -> Operation; + + /** + * @throw std::runtime_error If the thread pool is `shutdown()` scheduling new tasks is not permitted. + * @param f The function to execute on the thread pool. + * @param args The arguments to call the functor with. + * @return A task that wraps the given functor to be executed on the thread pool. + */ + template + [[nodiscard]] auto enqueue(FunctorT&& f, ArgumentsT... args) -> Task(args)...))> + { + co_await schedule(); + + if constexpr (std::is_same_v(args)...))>) + { + f(std::forward(args)...); + co_return; + } + else + { + co_return f(std::forward(args)...); + } + } + + /** + * Schedules any coroutine handle that is ready to be resumed. + * @param handle The coroutine handle to schedule. + */ + auto resume(std::coroutine_handle<> handle) noexcept -> void; + + /** + * Schedules the set of coroutine handles that are ready to be resumed. + * @param handles The coroutine handles to schedule. + */ + template > RangeT> + auto resume(const RangeT& handles) noexcept -> void + { + m_size.fetch_add(std::size(handles), std::memory_order::release); + + size_t null_handles{0}; + + { + std::scoped_lock lk{m_wait_mutex}; + for (const auto& handle : handles) + { + if (handle != nullptr) [[likely]] + { + m_queue.emplace_back(handle); + } + else + { + ++null_handles; + } + } + } + + if (null_handles > 0) + { + m_size.fetch_sub(null_handles, std::memory_order::release); + } + + m_wait_cv.notify_one(); + } + + /** + * Immediately yields the current task and places it at the end of the queue of tasks waiting + * to be processed. This will immediately be picked up again once it naturally goes through the + * FIFO task queue. This function is useful to yielding long processing tasks to let other tasks + * get processing time. + */ + [[nodiscard]] auto yield() -> Operation + { + return schedule(); + } + + /** + * Shutsdown the thread pool. This will finish any tasks scheduled prior to calling this + * function but will prevent the thread pool from scheduling any new tasks. This call is + * blocking and will wait until all inflight tasks are completed before returnin. + */ + auto shutdown() noexcept -> void; + + /** + * @return The number of tasks waiting in the task queue + the executing tasks. + */ + auto size() const noexcept -> std::size_t + { + return m_size.load(std::memory_order::acquire); + } + + /** + * @return True if the task queue is empty and zero tasks are currently executing. + */ + auto empty() const noexcept -> bool + { + return size() == 0; + } + + /** + * @return The number of tasks waiting in the task queue to be executed. + */ + auto queue_size() const noexcept -> std::size_t + { + // Might not be totally perfect but good enough, avoids acquiring the lock for now. + std::atomic_thread_fence(std::memory_order::acquire); + return m_queue.size(); + } + + /** + * @return True if the task queue is currently empty. + */ + auto queue_empty() const noexcept -> bool + { + return queue_size() == 0; + } + + /** + * If the calling thread is owned by a thread_pool, return a pointer to the thread_pool; otherwise, return a + * nullptr; + */ + static auto from_current_thread() -> ThreadPool*; + + /** + * If the calling thread is owned by a thread_pool, return the thread index (rank) of the current thread with + * respect the threads in the pool; otherwise, return the std::hash of std::this_thread::get_id + */ + static auto get_thread_id() -> std::size_t; + + /** + * @return std::string description of the thread pool + */ + const std::string& description() const; + + private: + /// The configuration options. + Options m_opts; + /// The background executor threads. + std::vector m_threads; + + /// Mutex for executor threads to sleep on the condition variable. + std::mutex m_wait_mutex; + /// Condition variable for each executor thread to wait on when no tasks are available. + std::condition_variable_any m_wait_cv; + /// FIFO queue of tasks waiting to be executed. + std::deque> m_queue; + /** + * Each background thread runs from this function. + * @param stop_token Token which signals when shutdown() has been called. + * @param idx The executor's idx for internal data structure accesses. + */ + auto executor(std::stop_token stop_token, std::size_t idx) -> void; + + /** + * @param handle Schedules the given coroutine to be executed upon the first available thread. + */ + auto schedule_impl(std::coroutine_handle<> handle) noexcept -> void; + + /// The number of tasks in the queue + currently executing. + std::atomic m_size{0}; + /// Has the thread pool been requested to shut down? + std::atomic m_shutdown_requested{false}; + + /// thead local pointer to the owning thread pool + static thread_local ThreadPool* m_self; + + /// user defined description + std::string m_description; + + /// thread local index of worker thread + static thread_local std::size_t m_thread_id; +}; + +} // namespace mrc::coroutines diff --git a/cpp/mrc/include/mrc/coroutines/when_all.hpp b/cpp/mrc/include/mrc/coroutines/when_all.hpp new file mode 100644 index 000000000..06df3c5dc --- /dev/null +++ b/cpp/mrc/include/mrc/coroutines/when_all.hpp @@ -0,0 +1,591 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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. + */ + +#pragma once + +#include "mrc/coroutines/concepts/awaitable.hpp" +#include "mrc/coroutines/detail/void_value.hpp" + +#include +#include +#include +#include +#include +#include + +namespace mrc::coroutines { + +namespace detail { + +class WhenAllLatch +{ + public: + WhenAllLatch(std::size_t count) noexcept : m_count(count + 1) {} + + WhenAllLatch(const WhenAllLatch&) = delete; + WhenAllLatch(WhenAllLatch&& other) : + m_count(other.m_count.load(std::memory_order::acquire)), + m_awaiting_coroutine(std::exchange(other.m_awaiting_coroutine, nullptr)) + {} + + auto operator=(const WhenAllLatch&) -> WhenAllLatch& = delete; + auto operator=(WhenAllLatch&& other) -> WhenAllLatch& + { + if (std::addressof(other) != this) + { + m_count.store(other.m_count.load(std::memory_order::acquire), std::memory_order::relaxed); + m_awaiting_coroutine = std::exchange(other.m_awaiting_coroutine, nullptr); + } + + return *this; + } + + auto is_ready() const noexcept -> bool + { + return m_awaiting_coroutine != nullptr && m_awaiting_coroutine.done(); + } + + auto try_await(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + m_awaiting_coroutine = awaiting_coroutine; + return m_count.fetch_sub(1, std::memory_order::acq_rel) > 1; + } + + auto notify_awaitable_completed() noexcept -> void + { + if (m_count.fetch_sub(1, std::memory_order::acq_rel) == 1) + { + m_awaiting_coroutine.resume(); + } + } + + private: + /// The number of tasks that are being waited on. + std::atomic m_count; + /// The when_all_task awaiting to be resumed upon all task completions. + std::coroutine_handle<> m_awaiting_coroutine{nullptr}; +}; + +template +class WhenAllReadyAwaitable; + +template +class when_all_task; + +/// Empty tuple<> implementation. +template <> +class WhenAllReadyAwaitable> +{ + public: + constexpr WhenAllReadyAwaitable() noexcept = default; + explicit constexpr WhenAllReadyAwaitable(std::tuple<> /*unused*/) noexcept {} + + static constexpr auto await_ready() noexcept -> bool + { + return true; + } + + static constexpr auto await_suspend(std::coroutine_handle<> /*unused*/) noexcept -> void {} + + static constexpr auto await_resume() noexcept -> std::tuple<> + { + return {}; + } +}; + +template +class WhenAllReadyAwaitable> +{ + public: + explicit WhenAllReadyAwaitable(TaskTypesT&&... tasks) noexcept( + std::conjunction...>::value) : + m_latch(sizeof...(TaskTypesT)), + m_tasks(std::move(tasks)...) + {} + + explicit WhenAllReadyAwaitable(std::tuple&& tasks) noexcept( + std::is_nothrow_move_constructible_v>) : + m_latch(sizeof...(TaskTypesT)), + m_tasks(std::move(tasks)) + {} + + WhenAllReadyAwaitable(const WhenAllReadyAwaitable&) = delete; + WhenAllReadyAwaitable(WhenAllReadyAwaitable&& other) : + m_latch(std::move(other.m_latch)), + m_tasks(std::move(other.m_tasks)) + {} + + auto operator=(const WhenAllReadyAwaitable&) -> WhenAllReadyAwaitable& = delete; + auto operator=(WhenAllReadyAwaitable&&) -> WhenAllReadyAwaitable& = delete; + + auto operator co_await() & noexcept + { + struct Awaiter + { + explicit Awaiter(WhenAllReadyAwaitable& awaitable) noexcept : m_awaitable(awaitable) {} + + auto await_ready() const noexcept -> bool + { + return m_awaitable.is_ready(); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + return m_awaitable.try_await(awaiting_coroutine); + } + + auto await_resume() noexcept -> std::tuple& + { + return m_awaitable.m_tasks; + } + + private: + WhenAllReadyAwaitable& m_awaitable; + }; + + return Awaiter{*this}; + } + + auto operator co_await() && noexcept + { + struct Awaiter + { + explicit Awaiter(WhenAllReadyAwaitable& awaitable) noexcept : m_awaitable(awaitable) {} + + auto await_ready() const noexcept -> bool + { + return m_awaitable.is_ready(); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + return m_awaitable.try_await(awaiting_coroutine); + } + + auto await_resume() noexcept -> std::tuple&& + { + return std::move(m_awaitable.m_tasks); + } + + private: + WhenAllReadyAwaitable& m_awaitable; + }; + + return Awaiter{*this}; + } + + private: + auto is_ready() const noexcept -> bool + { + return m_latch.is_ready(); + } + + auto try_await(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + std::apply([this](auto&&... tasks) { ((tasks.start(m_latch)), ...); }, m_tasks); + return m_latch.try_await(awaiting_coroutine); + } + + WhenAllLatch m_latch; + std::tuple m_tasks; +}; + +template +class WhenAllReadyAwaitable +{ + public: + explicit WhenAllReadyAwaitable(TaskContainerT&& tasks) noexcept : + m_latch(std::size(tasks)), + m_tasks(std::forward(tasks)) + {} + + WhenAllReadyAwaitable(const WhenAllReadyAwaitable&) = delete; + WhenAllReadyAwaitable(WhenAllReadyAwaitable&& other) noexcept( + std::is_nothrow_move_constructible_v) : + m_latch(std::move(other.m_latch)), + m_tasks(std::move(m_tasks)) + {} + + auto operator=(const WhenAllReadyAwaitable&) -> WhenAllReadyAwaitable& = delete; + auto operator=(WhenAllReadyAwaitable&) -> WhenAllReadyAwaitable& = delete; + + auto operator co_await() & noexcept + { + struct Awaiter + { + Awaiter(WhenAllReadyAwaitable& awaitable) : m_awaitable(awaitable) {} + + auto await_ready() const noexcept -> bool + { + return m_awaitable.is_ready(); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + return m_awaitable.try_await(awaiting_coroutine); + } + + auto await_resume() noexcept -> TaskContainerT& + { + return m_awaitable.m_tasks; + } + + private: + WhenAllReadyAwaitable& m_awaitable; + }; + + return Awaiter{*this}; + } + + auto operator co_await() && noexcept + { + struct Awaiter + { + Awaiter(WhenAllReadyAwaitable& awaitable) : m_awaitable(awaitable) {} + + auto await_ready() const noexcept -> bool + { + return m_awaitable.is_ready(); + } + + auto await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + return m_awaitable.try_await(awaiting_coroutine); + } + + auto await_resume() noexcept -> TaskContainerT&& + { + return std::move(m_awaitable.m_tasks); + } + + private: + WhenAllReadyAwaitable& m_awaitable; + }; + + return Awaiter{*this}; + } + + private: + auto is_ready() const noexcept -> bool + { + return m_latch.is_ready(); + } + + auto try_await(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool + { + for (auto& task : m_tasks) + { + task.start(m_latch); + } + + return m_latch.try_await(awaiting_coroutine); + } + + WhenAllLatch m_latch; + TaskContainerT m_tasks; +}; + +template +class WhenAllTaskPromise +{ + public: + using coroutine_handle_type = std::coroutine_handle>; + + WhenAllTaskPromise() noexcept = default; + + auto get_return_object() noexcept + { + return coroutine_handle_type::from_promise(*this); + } + + auto initial_suspend() noexcept -> std::suspend_always + { + return {}; + } + + auto final_suspend() noexcept + { + struct CompletionNotifier + { + auto await_ready() const noexcept -> bool + { + return false; + } + auto await_suspend(coroutine_handle_type coroutine) const noexcept -> void + { + coroutine.promise().m_latch->notify_awaitable_completed(); + } + auto await_resume() const noexcept {} + }; + + return CompletionNotifier{}; + } + + auto unhandled_exception() noexcept + { + m_exception_ptr = std::current_exception(); + } + + auto yield_value(ReturnT&& value) noexcept + { + m_return_value = std::addressof(value); + return final_suspend(); + } + + auto start(WhenAllLatch& latch) noexcept -> void + { + m_latch = &latch; + coroutine_handle_type::from_promise(*this).resume(); + } + + auto return_value() & -> ReturnT& + { + if (m_exception_ptr) + { + std::rethrow_exception(m_exception_ptr); + } + return *m_return_value; + } + + auto return_value() && -> ReturnT&& + { + if (m_exception_ptr) + { + std::rethrow_exception(m_exception_ptr); + } + return std::forward(*m_return_value); + } + + private: + WhenAllLatch* m_latch{nullptr}; + std::exception_ptr m_exception_ptr; + std::add_pointer_t m_return_value; +}; + +template <> +class WhenAllTaskPromise +{ + public: + using coroutine_handle_type = std::coroutine_handle>; + + WhenAllTaskPromise() noexcept = default; + + auto get_return_object() noexcept + { + return coroutine_handle_type::from_promise(*this); + } + + constexpr static auto initial_suspend() noexcept -> std::suspend_always + { + return {}; + } + + static auto final_suspend() noexcept + { + struct CompletionNotifier + { + static constexpr auto await_ready() noexcept -> bool + { + return false; + } + static auto await_suspend(coroutine_handle_type coroutine) noexcept -> void + { + coroutine.promise().m_latch->notify_awaitable_completed(); + } + static constexpr auto await_resume() noexcept -> void {} + }; + + return CompletionNotifier{}; + } + + auto unhandled_exception() noexcept -> void + { + m_exception_ptr = std::current_exception(); + } + + auto return_void() noexcept -> void {} + + auto result() -> void + { + if (m_exception_ptr) + { + std::rethrow_exception(m_exception_ptr); + } + } + + auto start(WhenAllLatch& latch) -> void + { + m_latch = &latch; + coroutine_handle_type::from_promise(*this).resume(); + } + + private: + WhenAllLatch* m_latch{nullptr}; + std::exception_ptr m_exception_ptr; +}; + +template +class when_all_task +{ + public: + // To be able to call start(). + template + friend class WhenAllReadyAwaitable; + + using promise_type = WhenAllTaskPromise; + using coroutine_handle_type = typename promise_type::coroutine_handle_type; + + when_all_task(coroutine_handle_type coroutine) noexcept : m_coroutine(coroutine) {} + + when_all_task(const when_all_task&) = delete; + when_all_task(when_all_task&& other) noexcept : + m_coroutine(std::exchange(other.m_coroutine, coroutine_handle_type{})) + {} + + auto operator=(const when_all_task&) -> when_all_task& = delete; + auto operator=(when_all_task&&) -> when_all_task& = delete; + + ~when_all_task() + { + if (m_coroutine != nullptr) + { + m_coroutine.destroy(); + } + } + + auto return_value() & -> decltype(auto) + { + if constexpr (std::is_void_v) + { + m_coroutine.promise().result(); + return VoidValue{}; + } + else + { + return m_coroutine.promise().return_value(); + } + } + + auto return_value() const& -> decltype(auto) + { + if constexpr (std::is_void_v) + { + m_coroutine.promise().result(); + return VoidValue{}; + } + else + { + return m_coroutine.promise().return_value(); + } + } + + auto return_value() && -> decltype(auto) + { + if constexpr (std::is_void_v) + { + m_coroutine.promise().result(); + return VoidValue{}; + } + else + { + return m_coroutine.promise().return_value(); + } + } + + private: + auto start(WhenAllLatch& latch) noexcept -> void + { + m_coroutine.promise().start(latch); + } + + coroutine_handle_type m_coroutine; +}; + +template ::awaiter_return_type> +static auto make_when_all_task(AwaitableT a) -> when_all_task; + +template +static auto make_when_all_task(AwaitableT a) -> when_all_task +{ + if constexpr (std::is_void_v) + { + co_await static_cast(a); + co_return; + } + else + { + co_yield co_await static_cast(a); + } +} + +} // namespace detail + +template +[[nodiscard]] auto when_all(AwaitablesT... awaitables) +{ + return detail::WhenAllReadyAwaitable< + std::tuple::awaiter_return_type>...>>( + std::make_tuple(detail::make_when_all_task(std::move(awaitables))...)); +} + +template , + typename ReturnT = typename concepts::awaitable_traits::awaiter_return_type> +[[nodiscard]] auto when_all(RangeT awaitables) + -> detail::WhenAllReadyAwaitable>> +{ + std::vector> output_tasks; + + // If the size is known in constant time reserve the output tasks size. + if constexpr (std::ranges::sized_range) + { + output_tasks.reserve(std::size(awaitables)); + } + + // Wrap each task into a when_all_task. + for (auto& a : awaitables) + { + output_tasks.emplace_back(detail::make_when_all_task(std::move(a))); + } + + // Return the single awaitable that drives all the user's tasks. + return detail::WhenAllReadyAwaitable(std::move(output_tasks)); +} + +} // namespace mrc::coroutines diff --git a/cpp/mrc/src/public/core/thread.cpp b/cpp/mrc/src/public/core/thread.cpp new file mode 100644 index 000000000..d9171b7b8 --- /dev/null +++ b/cpp/mrc/src/public/core/thread.cpp @@ -0,0 +1,61 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "mrc/core/thread.hpp" + +#include "mrc/coroutines/thread_pool.hpp" + +#include +#include +#include +#include + +namespace mrc::this_thread { + +namespace { + +std::string to_hex(std::integral auto i) +{ + std::stringstream ss; + ss << std::setfill('0') << std::setw(sizeof(i) * 2) << std::hex << i; + return ss.str(); +} + +std::string init_thread_id() +{ + const auto* thread_pool = coroutines::ThreadPool::from_current_thread(); + if (thread_pool == nullptr) + { + std::stringstream ss; + ss << "sys/" << to_hex(std::hash()(std::this_thread::get_id())); + return ss.str(); + } + + std::stringstream ss; + ss << thread_pool->description() << "/" << thread_pool->get_thread_id(); + return ss.str(); +} + +} // namespace + +const std::string& get_id() +{ + static thread_local std::string id = init_thread_id(); + return id; +} + +} // namespace mrc::this_thread diff --git a/cpp/mrc/src/public/coroutines/event.cpp b/cpp/mrc/src/public/coroutines/event.cpp new file mode 100644 index 000000000..7c18a35fb --- /dev/null +++ b/cpp/mrc/src/public/coroutines/event.cpp @@ -0,0 +1,133 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/event.hpp" + +#include "mrc/coroutines/thread_local_context.hpp" +#include "mrc/coroutines/thread_pool.hpp" + +namespace mrc::coroutines { + +auto Event::Awaiter::await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> bool +{ + const void* const set_state = &m_event; + + m_awaiting_coroutine = awaiting_coroutine; + + // This value will update if other threads write to it via acquire. + void* old_value = m_event.m_state.load(std::memory_order::acquire); + do + { + // Resume immediately if already in the set state. + if (old_value == set_state) + { + return false; + } + + m_next = static_cast(old_value); + } while (!m_event.m_state.compare_exchange_weak( + old_value, this, std::memory_order::release, std::memory_order::acquire)); + + ThreadLocalContext::suspend_thread_local_context(); + return true; +} + +auto Event::Awaiter::await_resume() noexcept -> void +{ + ThreadLocalContext::resume_thread_local_context(); +} + +void Event::Awaiter::resume() +{ + resume_coroutine(m_awaiting_coroutine); +} + +Event::Event(bool initially_set) noexcept : m_state((initially_set) ? static_cast(this) : nullptr) {} + +auto Event::set(ResumeOrderPolicy policy) noexcept -> void +{ + // Exchange the state to this, if the state was previously not this, then traverse the list + // of awaiters and resume their coroutines. + void* old_value = m_state.exchange(this, std::memory_order::acq_rel); + if (old_value != this) + { + // If FIFO has been requsted then reverse the order upon resuming. + if (policy == ResumeOrderPolicy::fifo) + { + old_value = reverse(static_cast(old_value)); + } + // else lifo nothing to do + + auto* waiters = static_cast(old_value); + while (waiters != nullptr) + { + auto* next = waiters->m_next; + // waiters->m_awaiting_coroutine.resume(); + waiters->resume(); + waiters = next; + } + } +} + +auto Event::reverse(Awaiter* curr) -> Awaiter* +{ + if (curr == nullptr || curr->m_next == nullptr) + { + return curr; + } + + Awaiter* prev = nullptr; + Awaiter* next = nullptr; + while (curr != nullptr) + { + next = curr->m_next; + curr->m_next = prev; + prev = curr; + curr = next; + } + + return prev; +} + +auto Event::reset() noexcept -> void +{ + void* old_value = this; + m_state.compare_exchange_strong(old_value, nullptr, std::memory_order::acquire); +} + +} // namespace mrc::coroutines diff --git a/cpp/mrc/src/public/coroutines/sync_wait.cpp b/cpp/mrc/src/public/coroutines/sync_wait.cpp new file mode 100644 index 000000000..1f805cfec --- /dev/null +++ b/cpp/mrc/src/public/coroutines/sync_wait.cpp @@ -0,0 +1,67 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/sync_wait.hpp" + +namespace mrc::coroutines::detail { + +SyncWaitEvent::SyncWaitEvent(bool initially_set) : m_set(initially_set) {} + +auto SyncWaitEvent::set() noexcept -> void +{ + { + std::lock_guard g{m_mutex}; + m_set = true; + } + + m_cv.notify_all(); +} + +auto SyncWaitEvent::reset() noexcept -> void +{ + std::lock_guard g{m_mutex}; + m_set = false; +} + +auto SyncWaitEvent::wait() noexcept -> void +{ + std::unique_lock lk{m_mutex}; + m_cv.wait(lk, [this] { return m_set; }); +} + +} // namespace mrc::coroutines::detail diff --git a/cpp/mrc/src/public/coroutines/thread_local_context.cpp b/cpp/mrc/src/public/coroutines/thread_local_context.cpp new file mode 100644 index 000000000..1c99e0e7f --- /dev/null +++ b/cpp/mrc/src/public/coroutines/thread_local_context.cpp @@ -0,0 +1,89 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/thread_local_context.hpp" + +#include "mrc/coroutines/thread_pool.hpp" + +#include + +namespace mrc::coroutines { + +void ThreadLocalContext::suspend_thread_local_context() +{ + // suspend the srf context + m_thread_pool = ThreadPool::from_current_thread(); + m_should_resume = true; +} + +void ThreadLocalContext::resume_thread_local_context() +{ + if (m_should_resume) + { + // resume the srf context + m_should_resume = false; + } +} + +void ThreadLocalContext::resume_coroutine(std::coroutine_handle<> coroutine) +{ + if (m_thread_pool != nullptr) + { + // add event - scheduled on + m_thread_pool->resume(coroutine); + return; + } + + // add a span since the current execution context will be suspended and the coroutine will be resumed + ThreadLocalContext ctx; + ctx.suspend_thread_local_context(); + coroutine.resume(); + ctx.resume_thread_local_context(); +} + +void ThreadLocalContext::set_resume_on_thread_pool(ThreadPool* thread_pool) +{ + m_thread_pool = thread_pool; +} + +ThreadPool* ThreadLocalContext::thread_pool() const +{ + return m_thread_pool; +} + +} // namespace mrc::coroutines diff --git a/cpp/mrc/src/public/coroutines/thread_pool.cpp b/cpp/mrc/src/public/coroutines/thread_pool.cpp new file mode 100644 index 000000000..a5a6dd4d8 --- /dev/null +++ b/cpp/mrc/src/public/coroutines/thread_pool.cpp @@ -0,0 +1,229 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/thread_pool.hpp" + +#include "mrc/core/thread.hpp" +#include "mrc/coroutines/thread_local_context.hpp" + +#include + +#include +#include +#include + +namespace mrc::coroutines { + +thread_local ThreadPool* ThreadPool::m_self{nullptr}; +thread_local std::size_t ThreadPool::m_thread_id{0}; + +ThreadPool::Operation::Operation(ThreadPool& tp) noexcept : m_thread_pool(tp) {} + +auto ThreadPool::Operation::await_suspend(std::coroutine_handle<> awaiting_coroutine) noexcept -> void +{ +// create span to measure the time spent in the scheduler +#if srf_ENABLE_OTEL_TRACE + m_span = mrc::trace::get_tracer()->StartSpan("schedule to thread_pool"); + if (m_span->Isrfcording()) + { + m_span->AddEvent("suspend coroutine for scheduling on " + m_thread_pool.description(), + {{"thread.id", mrc::this_thread::get_id()}}); + m_span->SetAttribute("component", "mrc::thread_pool"); + } +#endif + // DVLOG(10) << "suspend scheduling operation on " << mrc::this_thread::get_id(); + + // suspend thread local state + // ThreadLocalContext::suspend_thread_local_context(); + + // capture the coroutine handle and schedule it to be resumed + m_awaiting_coroutine = awaiting_coroutine; + m_thread_pool.schedule_impl(m_awaiting_coroutine); +} + +auto ThreadPool::Operation::await_resume() noexcept -> void +{ + // restore thread local state + // ThreadLocalContext::resume_thread_local_context(); + + // complete the span recording the time spent scheduling +#if srf_ENABLE_OTEL_TRACE + if (m_span->Isrfcording()) + { + m_span->AddEvent("resuming coroutine scheduled on " + m_thread_pool.description(), + {{"thread.id", mrc::this_thread::get_id()}}); + } + m_span->End(); +#endif + // DVLOG(10) << "resuming schedule operation on " << mrc::this_thread::get_id(); +} + +ThreadPool::ThreadPool(Options opts) : m_opts(std::move(opts)) +{ + if (m_opts.description.empty()) + { + std::stringstream ss; + ss << "thread_pool_" << this; + m_opts.description = ss.str(); + } + + m_threads.reserve(m_opts.thread_count); + + for (uint32_t i = 0; i < m_opts.thread_count; ++i) + { + m_threads.emplace_back([this, i](std::stop_token st) { executor(std::move(st), i); }); + } +} + +ThreadPool::~ThreadPool() +{ + shutdown(); +} + +auto ThreadPool::schedule() -> Operation +{ + if (!m_shutdown_requested.load(std::memory_order::relaxed)) + { + m_size.fetch_add(1, std::memory_order::release); + return Operation{*this}; + } + + throw std::runtime_error("coroutines::ThreadPool is shutting down, unable to schedule new tasks."); +} + +auto ThreadPool::resume(std::coroutine_handle<> handle) noexcept -> void +{ + if (handle == nullptr) + { + return; + } + + m_size.fetch_add(1, std::memory_order::release); + schedule_impl(handle); +} + +auto ThreadPool::shutdown() noexcept -> void +{ + // Only allow shutdown to occur once. + if (!m_shutdown_requested.exchange(true, std::memory_order::acq_rel)) + { + for (auto& thread : m_threads) + { + thread.request_stop(); + } + + for (auto& thread : m_threads) + { + if (thread.joinable()) + { + thread.join(); + } + } + } +} + +auto ThreadPool::executor(std::stop_token stop_token, std::size_t idx) -> void +{ + m_self = this; + m_thread_id = idx; + + if (m_opts.on_thread_start_functor != nullptr) + { + m_opts.on_thread_start_functor(idx); + } + + while (!stop_token.stop_requested()) + { + // Wait until the queue has operations to execute or shutdown has been requested. + while (true) + { + std::unique_lock lk{m_wait_mutex}; + m_wait_cv.wait(lk, stop_token, [this] { return !m_queue.empty(); }); + if (m_queue.empty()) + { + lk.unlock(); // would happen on scope destruction, but being explicit/faster(?) + break; + } + + auto handle = m_queue.front(); + m_queue.pop_front(); + + lk.unlock(); // Not needed for processing the coroutine. + + handle.resume(); + m_size.fetch_sub(1, std::memory_order::release); + } + } + + if (m_opts.on_thread_stop_functor != nullptr) + { + m_opts.on_thread_stop_functor(idx); + } +} + +auto ThreadPool::schedule_impl(std::coroutine_handle<> handle) noexcept -> void +{ + if (handle == nullptr) + { + return; + } + + { + std::scoped_lock lk{m_wait_mutex}; + m_queue.emplace_back(handle); + } + + m_wait_cv.notify_one(); +} + +auto ThreadPool::from_current_thread() -> ThreadPool* +{ + return m_self; +} + +auto ThreadPool::get_thread_id() -> std::size_t +{ + return m_thread_id; +} + +const std::string& ThreadPool::description() const +{ + return m_opts.description; +} + +} // namespace mrc::coroutines diff --git a/cpp/mrc/tests/coroutines/test_event.cpp b/cpp/mrc/tests/coroutines/test_event.cpp new file mode 100644 index 000000000..53b950a11 --- /dev/null +++ b/cpp/mrc/tests/coroutines/test_event.cpp @@ -0,0 +1,320 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/event.hpp" +#include "mrc/coroutines/sync_wait.hpp" +#include "mrc/coroutines/task.hpp" +#include "mrc/coroutines/thread_pool.hpp" +#include "mrc/coroutines/when_all.hpp" + +#include + +#include +#include + +using namespace mrc; + +class TestCoroEvent : public ::testing::Test +{}; + +TEST_F(TestCoroEvent, LifeCycle) +{ + coroutines::Event e{}; + + auto func = [&]() -> coroutines::Task { + co_await e; + co_return 42; + }; + + auto task = func(); + + task.resume(); + EXPECT_FALSE(task.is_ready()); + e.set(); // this will automaticaly resume the task that is awaiting the event. + EXPECT_TRUE(task.is_ready()); + EXPECT_TRUE(task.promise().result() == 42); +} + +auto producer(coroutines::Event& event) -> void +{ + // Long running task that consumers are waiting for goes here... + event.set(); +} + +auto consumer(const coroutines::Event& event) -> coroutines::Task +{ + co_await event; + // Normally consume from some object which has the stored result from the producer + co_return 42; +} + +// TEST_CASE("event one watcher", "[event]") +TEST_F(TestCoroEvent, SingleWatcher) +{ + coroutines::Event e{}; + + auto value = consumer(e); + value.resume(); // start co_awaiting event + EXPECT_FALSE(value.is_ready()); + + producer(e); + + EXPECT_TRUE(value.promise().result() == 42); +} + +// TEST_CASE("event multiple watchers", "[event]") +TEST_F(TestCoroEvent, MultipleWatchers) +{ + coroutines::Event e{}; + + auto value1 = consumer(e); + auto value2 = consumer(e); + auto value3 = consumer(e); + value1.resume(); // start co_awaiting event + value2.resume(); + value3.resume(); + EXPECT_FALSE(value1.is_ready()); + EXPECT_FALSE(value2.is_ready()); + EXPECT_FALSE(value3.is_ready()); + + producer(e); + + EXPECT_TRUE(value1.promise().result() == 42); + EXPECT_TRUE(value2.promise().result() == 42); + EXPECT_TRUE(value3.promise().result() == 42); +} + +// TEST_CASE("event reset", "[event]") +TEST_F(TestCoroEvent, Reset) +{ + coroutines::Event e{}; + + e.reset(); + EXPECT_FALSE(e.is_set()); + + auto value1 = consumer(e); + value1.resume(); // start co_awaiting event + EXPECT_FALSE(value1.is_ready()); + + producer(e); + EXPECT_TRUE(value1.promise().result() == 42); + + e.reset(); + + auto value2 = consumer(e); + value2.resume(); + EXPECT_FALSE(value2.is_ready()); + + producer(e); + + EXPECT_TRUE(value2.promise().result() == 42); +} + +// TEST_CASE("event fifo", "[event]") +TEST_F(TestCoroEvent, FIFO) +{ + coroutines::Event e{}; + + // Need consistency FIFO on a single thread to verify the execution order is correct. + coroutines::ThreadPool tp{coroutines::ThreadPool::Options{.thread_count = 1}}; + + std::atomic counter{0}; + + auto make_waiter = [&](uint64_t value) -> coroutines::Task { + co_await tp.schedule(); + co_await e; + + counter++; + EXPECT_TRUE(counter == value); + + co_return; + }; + + auto make_setter = [&]() -> coroutines::Task { + co_await tp.schedule(); + EXPECT_TRUE(counter == 0); + e.set(coroutines::ResumeOrderPolicy::fifo); + co_return; + }; + + coroutines::sync_wait(coroutines::when_all( + make_waiter(1), make_waiter(2), make_waiter(3), make_waiter(4), make_waiter(5), make_setter())); + + EXPECT_TRUE(counter == 5); +} + +// TEST_CASE("event fifo none", "[event]") +TEST_F(TestCoroEvent, FIFO_None) +{ + coroutines::Event e{}; + + // Need consistency FIFO on a single thread to verify the execution order is correct. + coroutines::ThreadPool tp{coroutines::ThreadPool::Options{.thread_count = 1}}; + + std::atomic counter{0}; + + auto make_setter = [&]() -> coroutines::Task { + co_await tp.schedule(); + EXPECT_TRUE(counter == 0); + e.set(coroutines::ResumeOrderPolicy::fifo); + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_setter())); + + EXPECT_TRUE(counter == 0); +} + +// TEST_CASE("event fifo single", "[event]") +TEST_F(TestCoroEvent, FIFO_Single) +{ + coroutines::Event e{}; + + // Need consistency FIFO on a single thread to verify the execution order is correct. + coroutines::ThreadPool tp{coroutines::ThreadPool::Options{.thread_count = 1}}; + + std::atomic counter{0}; + + auto make_waiter = [&](uint64_t value) -> coroutines::Task { + co_await tp.schedule(); + co_await e; + + counter++; + EXPECT_TRUE(counter == value); + + co_return; + }; + + auto make_setter = [&]() -> coroutines::Task { + co_await tp.schedule(); + EXPECT_TRUE(counter == 0); + e.set(coroutines::ResumeOrderPolicy::fifo); + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_waiter(1), make_setter())); + + EXPECT_TRUE(counter == 1); +} + +// TEST_CASE("event fifo executor", "[event]") +TEST_F(TestCoroEvent, FIFO_Executor) +{ + coroutines::Event e{}; + + // Need consistency FIFO on a single thread to verify the execution order is correct. + coroutines::ThreadPool tp{coroutines::ThreadPool::Options{.thread_count = 1}}; + + std::atomic counter{0}; + + auto make_waiter = [&](uint64_t value) -> coroutines::Task { + co_await tp.schedule(); + co_await e; + + counter++; + EXPECT_TRUE(counter == value); + + co_return; + }; + + auto make_setter = [&]() -> coroutines::Task { + co_await tp.schedule(); + EXPECT_TRUE(counter == 0); + e.set(tp, coroutines::ResumeOrderPolicy::fifo); + co_return; + }; + + coroutines::sync_wait(coroutines::when_all( + make_waiter(1), make_waiter(2), make_waiter(3), make_waiter(4), make_waiter(5), make_setter())); + + EXPECT_TRUE(counter == 5); +} + +// TEST_CASE("event fifo none executor", "[event]") +TEST_F(TestCoroEvent, FIFO_NoExecutor) +{ + coroutines::Event e{}; + + // Need consistency FIFO on a single thread to verify the execution order is correct. + coroutines::ThreadPool tp{coroutines::ThreadPool::Options{.thread_count = 1}}; + + std::atomic counter{0}; + + auto make_setter = [&]() -> coroutines::Task { + co_await tp.schedule(); + EXPECT_TRUE(counter == 0); + e.set(tp, coroutines::ResumeOrderPolicy::fifo); + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_setter())); + + EXPECT_TRUE(counter == 0); +} + +// TEST_CASE("event fifo single executor", "[event]") +TEST_F(TestCoroEvent, FIFO_SingleExecutor) +{ + coroutines::Event e{}; + + // Need consistency FIFO on a single thread to verify the execution order is correct. + coroutines::ThreadPool tp{coroutines::ThreadPool::Options{.thread_count = 1}}; + + std::atomic counter{0}; + + auto make_waiter = [&](uint64_t value) -> coroutines::Task { + co_await tp.schedule(); + co_await e; + + counter++; + EXPECT_TRUE(counter == value); + + co_return; + }; + + auto make_setter = [&]() -> coroutines::Task { + co_await tp.schedule(); + EXPECT_TRUE(counter == 0); + e.set(tp, coroutines::ResumeOrderPolicy::fifo); + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_waiter(1), make_setter())); + + EXPECT_TRUE(counter == 1); +} diff --git a/cpp/mrc/tests/coroutines/test_latch.cpp b/cpp/mrc/tests/coroutines/test_latch.cpp new file mode 100644 index 000000000..66f05efb5 --- /dev/null +++ b/cpp/mrc/tests/coroutines/test_latch.cpp @@ -0,0 +1,158 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/event.hpp" +#include "mrc/coroutines/latch.hpp" +#include "mrc/coroutines/task.hpp" + +#include + +#include +#include + +using namespace mrc; + +class TestCoroLatch : public ::testing::Test +{}; + +TEST_F(TestCoroLatch, Count0) +{ + coroutines::Latch l{0}; + + auto make_task = [&]() -> coroutines::Task { + co_await l; + co_return 42; + }; + + auto task = make_task(); + + task.resume(); + + EXPECT_TRUE(task.is_ready()); + EXPECT_EQ(task.promise().result(), 42); +} + +TEST_F(TestCoroLatch, Count1) +{ + coroutines::Latch l{1}; + + auto make_task = [&]() -> coroutines::Task { + auto workers = l.remaining(); + co_await l; + co_return workers; + }; + + auto task = make_task(); + + task.resume(); + EXPECT_FALSE(task.is_ready()); + + l.count_down(); + EXPECT_TRUE(task.is_ready()); + EXPECT_EQ(task.promise().result(), 1); +} + +TEST_F(TestCoroLatch, Count1Down5) +{ + coroutines::Latch l{1}; + + auto make_task = [&]() -> coroutines::Task { + auto workers = l.remaining(); + co_await l; + co_return workers; + }; + + auto task = make_task(); + + task.resume(); + EXPECT_FALSE(task.is_ready()); + + l.count_down(5); + EXPECT_TRUE(task.is_ready()); + EXPECT_TRUE(task.promise().result() == 1); +} + +// TEST_CASE("latch count=5 count_down=1 x5", "[latch]") +TEST_F(TestCoroLatch, Count5Down1x5) +{ + coroutines::Latch l{5}; + + auto make_task = [&]() -> coroutines::Task { + auto workers = l.remaining(); + co_await l; + co_return workers; + }; + + auto task = make_task(); + + task.resume(); + EXPECT_FALSE(task.is_ready()); + + l.count_down(1); + EXPECT_FALSE(task.is_ready()); + l.count_down(1); + EXPECT_FALSE(task.is_ready()); + l.count_down(1); + EXPECT_FALSE(task.is_ready()); + l.count_down(1); + EXPECT_FALSE(task.is_ready()); + l.count_down(1); + EXPECT_TRUE(task.is_ready()); + EXPECT_TRUE(task.promise().result() == 5); +} + +// TEST_CASE("latch count=5 count_down=5", "[latch]") +TEST_F(TestCoroLatch, Count5Down5) +{ + coroutines::Latch l{5}; + + auto make_task = [&]() -> coroutines::Task { + auto workers = l.remaining(); + co_await l; + co_return workers; + }; + + auto task = make_task(); + + task.resume(); + EXPECT_FALSE(task.is_ready()); + + l.count_down(5); + EXPECT_TRUE(task.is_ready()); + EXPECT_TRUE(task.promise().result() == 5); +} diff --git a/cpp/mrc/tests/coroutines/test_ring_buffer.cpp b/cpp/mrc/tests/coroutines/test_ring_buffer.cpp new file mode 100644 index 000000000..ed6a9f970 --- /dev/null +++ b/cpp/mrc/tests/coroutines/test_ring_buffer.cpp @@ -0,0 +1,276 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/coroutines/latch.hpp" +#include "mrc/coroutines/ring_buffer.hpp" +#include "mrc/coroutines/schedule_policy.hpp" +#include "mrc/coroutines/sync_wait.hpp" +#include "mrc/coroutines/task.hpp" +#include "mrc/coroutines/when_all.hpp" + +#include + +#include +#include + +using namespace mrc; + +class TestCoroRingBuffer : public ::testing::Test +{}; + +// TEST_CASE("ring_buffer zero num_elements", "[ring_buffer]") +TEST_F(TestCoroRingBuffer, ZeroCapacity) +{ + EXPECT_ANY_THROW(coroutines::RingBuffer rb{{.capacity = 0}}); +} + +// TEST_CASE("ring_buffer single element", "[ring_buffer]") +TEST_F(TestCoroRingBuffer, SingleElement) +{ + const size_t iterations = 10; + coroutines::RingBuffer rb{{.capacity = 1}}; + + std::vector output{}; + + auto make_producer_task = [&]() -> coroutines::Task { + for (size_t i = 1; i <= iterations; ++i) + { + co_await rb.write(i); + } + co_return; + }; + + auto make_consumer_task = [&]() -> coroutines::Task { + for (size_t i = 1; i <= iterations; ++i) + { + auto expected = co_await rb.read(); + auto value = std::move(*expected); + + output.emplace_back(std::move(value)); + } + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_producer_task(), make_consumer_task())); + + for (size_t i = 1; i <= iterations; ++i) + { + EXPECT_TRUE(output[i - 1] == i); + } + + EXPECT_TRUE(rb.empty()); +} + +TEST_F(TestCoroRingBuffer, WriteX5ThenClose) +{ + const size_t iterations = 5; + coroutines::RingBuffer rb{{.capacity = 2}}; + + std::vector output{}; + + auto make_producer_task = [&]() -> coroutines::Task { + for (size_t i = 1; i <= iterations; ++i) + { + EXPECT_FALSE(rb.is_closed()); + co_await rb.write(i); + } + rb.close(); + EXPECT_TRUE(rb.is_closed()); + auto status = co_await rb.write(42); + EXPECT_EQ(status, coroutines::RingBufferOpStatus::Stopped); + co_return; + }; + + auto make_consumer_task = [&]() -> coroutines::Task { + while (true) + { + auto expected = co_await rb.read(); + + if (!expected) + { + break; + } + auto value = std::move(*expected); + output.emplace_back(std::move(value)); + } + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_producer_task(), make_consumer_task())); + + for (size_t i = 1; i <= iterations; ++i) + { + EXPECT_TRUE(output[i - 1] == i); + } + + EXPECT_TRUE(rb.empty()); + EXPECT_TRUE(rb.is_closed()); +} + +TEST_F(TestCoroRingBuffer, FullyBufferedWriteX5ThenClose) +{ + const size_t iterations = 5; + coroutines::RingBuffer rb{{.capacity = 16}}; + coroutines::Latch latch{iterations + 1}; + + std::vector output{}; + + auto make_producer_task = [&]() -> coroutines::Task { + for (size_t i = 1; i <= iterations; ++i) + { + EXPECT_FALSE(rb.is_closed()); + co_await rb.write(i); + latch.count_down(); + } + rb.close(); + EXPECT_TRUE(rb.is_closed()); + auto status = co_await rb.write(42); + EXPECT_EQ(status, coroutines::RingBufferOpStatus::Stopped); + latch.count_down(); + co_return; + }; + + auto make_consumer_task = [&]() -> coroutines::Task { + co_await latch; + while (true) + { + auto expected = co_await rb.read(); + + if (!expected) + { + break; + } + auto value = std::move(*expected); + output.emplace_back(std::move(value)); + } + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(make_producer_task(), make_consumer_task())); + + for (size_t i = 1; i <= iterations; ++i) + { + EXPECT_TRUE(output[i - 1] == i); + } + + EXPECT_TRUE(rb.empty()); + EXPECT_TRUE(rb.is_closed()); +} + +// TEST_CASE("ring_buffer many elements many producers many consumers", "[ring_buffer]") +TEST_F(TestCoroRingBuffer, MultiProducerMultiConsumer) +{ + const size_t iterations = 1'000'000; + const size_t consumers = 100; + const size_t producers = 100; + + coroutines::ThreadPool tp{{.thread_count = 4}}; + coroutines::RingBuffer rb{{.capacity = 64}}; + coroutines::Latch producers_latch{producers}; + + auto make_producer_task = [&]() -> coroutines::Task { + co_await tp.schedule(); + auto to_produce = iterations / producers; + + for (size_t i = 1; i <= to_produce; ++i) + { + switch (i % 3) + { + case 0: + co_await rb.write(i); + break; + case 1: + co_await rb.write(i).resume_immediately(); + break; + case 2: + co_await rb.write(i).resume_on(&tp); + break; + } + } + + producers_latch.count_down(); + + co_return; + }; + + auto make_consumer_task = [&]() -> coroutines::Task { + co_await tp.schedule(); + + while (true) + { + auto expected = co_await rb.read(); + if (!expected) + { + break; + } + + auto item = std::move(*expected); + + co_await tp.yield(); // mimic some work + } + + co_return; + }; + + auto make_shutdown_task = [&]() -> coroutines::Task { + co_await tp.schedule(); + co_await producers_latch; + rb.close(); + co_return; + }; + + std::vector> tasks{}; + tasks.reserve(consumers + producers + 1); + + tasks.emplace_back(make_shutdown_task()); + + for (size_t i = 0; i < consumers; ++i) + { + tasks.emplace_back(make_consumer_task()); + } + for (size_t i = 0; i < producers; ++i) + { + tasks.emplace_back(make_producer_task()); + } + + EXPECT_EQ(tasks.size(), consumers + producers + 1); + + coroutines::sync_wait(coroutines::when_all(std::move(tasks))); + + EXPECT_TRUE(rb.empty()); +} diff --git a/cpp/mrc/tests/coroutines/test_task.cpp b/cpp/mrc/tests/coroutines/test_task.cpp new file mode 100644 index 000000000..1eed42893 --- /dev/null +++ b/cpp/mrc/tests/coroutines/test_task.cpp @@ -0,0 +1,118 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +/** + * Original Source: https://github.com/jbaldwin/libcoro + * Original License: Apache License, Version 2.0; included below + */ + +/** + * Copyright 2021 Josh Baldwin + * + * 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 "mrc/core/thread.hpp" +#include "mrc/coroutines/ring_buffer.hpp" +#include "mrc/coroutines/sync_wait.hpp" +#include "mrc/coroutines/task.hpp" +#include "mrc/coroutines/thread_pool.hpp" + +#include + +#include +#include +#include +#include + +using namespace mrc; + +class TestCoroTask : public ::testing::Test +{}; + +static auto double_task = [](std::uint64_t x) -> coroutines::Task { co_return x * 2; }; + +static auto scheduled_task = [](coroutines::ThreadPool& tp, std::uint64_t x) -> coroutines::Task { + co_await tp.schedule(); + co_return x * 2; +}; + +static auto double_and_add_5_task = [](std::uint64_t input) -> coroutines::Task { + auto doubled = co_await double_task(input); + co_return doubled + 5; +}; + +TEST_F(TestCoroTask, Task) +{ + auto output = coroutines::sync_wait(double_task(2)); + EXPECT_EQ(output, 4); +} + +TEST_F(TestCoroTask, ScheduledTask) +{ + coroutines::ThreadPool main({.thread_count = 1, .description = "main"}); + auto output = coroutines::sync_wait(scheduled_task(main, 2)); + EXPECT_EQ(output, 4); +} + +TEST_F(TestCoroTask, Tasks) +{ + auto output = coroutines::sync_wait(double_and_add_5_task(2)); + EXPECT_EQ(output, 9); +} + +TEST_F(TestCoroTask, RingBufferStressTest) +{ + coroutines::ThreadPool writer({.thread_count = 1, .description = "writer"}); + coroutines::ThreadPool reader({.thread_count = 1, .description = "reader"}); + coroutines::RingBuffer> buffer({.capacity = 2}); + + for (int iters = 16; iters <= 16; iters++) + { + auto source = [&writer, &buffer, iters]() -> coroutines::Task { + co_await writer.schedule(); + for (std::uint64_t i = 0; i < iters; i++) + { + co_await buffer.write(std::make_unique(i)); + } + co_return; + }; + + auto sink = [&reader, &buffer, iters]() -> coroutines::Task { + co_await reader.schedule(); + for (std::uint64_t i = 0; i < iters; i++) + { + auto unique = co_await buffer.read(); + EXPECT_TRUE(unique); + EXPECT_EQ(*(unique.value()), i); + } + co_return; + }; + + coroutines::sync_wait(coroutines::when_all(source(), sink())); + } +} diff --git a/cpp/mrc/tests/test_thread.cpp b/cpp/mrc/tests/test_thread.cpp new file mode 100644 index 000000000..ba7125585 --- /dev/null +++ b/cpp/mrc/tests/test_thread.cpp @@ -0,0 +1,54 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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 "mrc/core/thread.hpp" +#include "mrc/coroutines/sync_wait.hpp" +#include "mrc/coroutines/task.hpp" +#include "mrc/coroutines/thread_pool.hpp" +#include "mrc/coroutines/when_all.hpp" + +#include + +#include +#include + +using namespace mrc; + +class TestThread : public ::testing::Test +{}; + +TEST_F(TestThread, GetThreadID) +{ + coroutines::ThreadPool unnamed({.thread_count = 1}); + coroutines::ThreadPool main({.thread_count = 1, .description = "main"}); + + auto log_id = [](coroutines::ThreadPool& tp) -> coroutines::Task { + co_await tp.schedule(); + co_return mrc::this_thread::get_id(); + }; + + auto from_main = coroutines::sync_wait(log_id(main)); + auto from_unnamed = coroutines::sync_wait(log_id(unnamed)); + + VLOG(1) << mrc::this_thread::get_id(); + VLOG(1) << from_main; + VLOG(1) << from_unnamed; + + EXPECT_TRUE(mrc::this_thread::get_id().starts_with("sys")); + EXPECT_TRUE(from_main.starts_with("main")); + EXPECT_TRUE(from_unnamed.starts_with("thread_pool")); +} diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py b/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py index 30c03d776..c39b866e4 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py @@ -24,12 +24,13 @@ """Git implementation of _version.py.""" import errno +import functools import os import re import subprocess import sys -from typing import Callable, Dict -import functools +from typing import Callable +from typing import Dict def get_keywords(): diff --git a/docs/quickstart/hybrid/versioneer.py b/docs/quickstart/hybrid/versioneer.py index a142bf53e..5e21cd07d 100644 --- a/docs/quickstart/hybrid/versioneer.py +++ b/docs/quickstart/hybrid/versioneer.py @@ -1,6 +1,4 @@ - # Version: 0.22 - """The Versioneer - like a rocketeer, but for versions. The Versioneer @@ -282,13 +280,14 @@ import configparser import errno +import functools import json import os import re import subprocess import sys -from typing import Callable, Dict -import functools +from typing import Callable +from typing import Dict class VersioneerConfig: @@ -327,8 +326,7 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(my_path)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(my_path), versioneer_py)) + print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(my_path), versioneer_py)) except NameError: pass return root @@ -373,15 +371,16 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Create decorator to mark a method as the handler of a VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" HANDLERS.setdefault(vcs, {})[method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) process = None @@ -397,10 +396,12 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen([command] + args, cwd=cwd, env=env, + process = subprocess.Popen([command] + args, + cwd=cwd, + env=env, stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None), **popen_kwargs) + stderr=(subprocess.PIPE if hide_stderr else None), + **popen_kwargs) break except OSError: e = sys.exc_info()[1] @@ -412,7 +413,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return None, None else: if verbose: - print("unable to find command, tried %s" % (commands,)) + print("unable to find command, tried %s" % (commands, )) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: @@ -1164,16 +1165,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): continue if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1195,8 +1199,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1206,9 +1209,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", *MATCH_ARGS], - cwd=root) + describe_out, rc = runner(GITS, ["describe", "--tags", "--dirty", "--always", "--long", *MATCH_ARGS], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1223,8 +1224,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], - cwd=root) + branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") @@ -1273,8 +1273,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag @@ -1283,8 +1282,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] @@ -1359,15 +1357,18 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None + } rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1396,11 +1397,9 @@ def versions_from_file(filename): contents = f.read() except OSError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1409,8 +1408,7 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1442,8 +1440,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1472,8 +1469,7 @@ def render_pep440_branch(pieces): rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" - rendered += "+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1501,7 +1497,7 @@ def render_pep440_pre(pieces): tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: - rendered += ".post%d.dev%d" % (post_version+1, pieces["distance"]) + rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%d" % (pieces["distance"]) else: @@ -1634,11 +1630,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None + } if not style or style == "default": style = "pep440" # the default @@ -1662,9 +1660,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date") + } class VersioneerBadRootError(Exception): @@ -1742,9 +1744,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None + } def get_version(): @@ -1800,6 +1806,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1826,6 +1833,7 @@ def run(self): from distutils.command.build_py import build_py as _build_py class cmd_build_py(_build_py): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1834,10 +1842,10 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if 'build_ext' in cmds: @@ -1848,6 +1856,7 @@ def run(self): from distutils.command.build_ext import build_ext as _build_ext class cmd_build_ext(_build_ext): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1861,14 +1870,15 @@ def run(self): return # now locate _version.py in the new build/ directory and replace # it with an updated value - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_ext"] = cmd_build_ext if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1877,6 +1887,7 @@ def run(self): # ... class cmd_build_exe(_build_exe): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1889,13 +1900,15 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] @@ -1903,6 +1916,7 @@ def run(self): from py2exe.distutils_buildexe import py2exe as _py2exe class cmd_py2exe(_py2exe): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1915,13 +1929,15 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1933,6 +1949,7 @@ def run(self): from distutils.command.sdist import sdist as _sdist class cmd_sdist(_sdist): + def run(self): versions = get_versions() self._versioneer_generated_versions = versions @@ -1950,8 +1967,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file(target_versionfile, self._versioneer_generated_versions) + cmds["sdist"] = cmd_sdist return cmds @@ -2011,11 +2028,9 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (OSError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except (OSError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (OSError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -2024,15 +2039,16 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -2080,8 +2096,7 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print(" appending versionfile_source ('%s') to MANIFEST.in" % cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: diff --git a/docs/quickstart/python/mrc_qs_python/_version.py b/docs/quickstart/python/mrc_qs_python/_version.py index 0698d467f..94e5ba7f0 100644 --- a/docs/quickstart/python/mrc_qs_python/_version.py +++ b/docs/quickstart/python/mrc_qs_python/_version.py @@ -24,12 +24,13 @@ """Git implementation of _version.py.""" import errno +import functools import os import re import subprocess import sys -from typing import Callable, Dict -import functools +from typing import Callable +from typing import Dict def get_keywords(): diff --git a/docs/quickstart/python/versioneer.py b/docs/quickstart/python/versioneer.py index a142bf53e..5e21cd07d 100644 --- a/docs/quickstart/python/versioneer.py +++ b/docs/quickstart/python/versioneer.py @@ -1,6 +1,4 @@ - # Version: 0.22 - """The Versioneer - like a rocketeer, but for versions. The Versioneer @@ -282,13 +280,14 @@ import configparser import errno +import functools import json import os import re import subprocess import sys -from typing import Callable, Dict -import functools +from typing import Callable +from typing import Dict class VersioneerConfig: @@ -327,8 +326,7 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(my_path)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(my_path), versioneer_py)) + print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(my_path), versioneer_py)) except NameError: pass return root @@ -373,15 +371,16 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Create decorator to mark a method as the handler of a VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" HANDLERS.setdefault(vcs, {})[method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) process = None @@ -397,10 +396,12 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([command] + args) # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen([command] + args, cwd=cwd, env=env, + process = subprocess.Popen([command] + args, + cwd=cwd, + env=env, stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None), **popen_kwargs) + stderr=(subprocess.PIPE if hide_stderr else None), + **popen_kwargs) break except OSError: e = sys.exc_info()[1] @@ -412,7 +413,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return None, None else: if verbose: - print("unable to find command, tried %s" % (commands,)) + print("unable to find command, tried %s" % (commands, )) return None, None stdout = process.communicate()[0].strip().decode() if process.returncode != 0: @@ -1164,16 +1165,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): continue if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1195,8 +1199,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): env.pop("GIT_DIR", None) runner = functools.partial(runner, env=env) - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1206,9 +1209,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", *MATCH_ARGS], - cwd=root) + describe_out, rc = runner(GITS, ["describe", "--tags", "--dirty", "--always", "--long", *MATCH_ARGS], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1223,8 +1224,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], - cwd=root) + branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) # --abbrev-ref was added in git-1.6.3 if rc != 0 or branch_name is None: raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") @@ -1273,8 +1273,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag @@ -1283,8 +1282,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] @@ -1359,15 +1357,18 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for _ in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None + } rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1396,11 +1397,9 @@ def versions_from_file(filename): contents = f.read() except OSError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1409,8 +1408,7 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1442,8 +1440,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1472,8 +1469,7 @@ def render_pep440_branch(pieces): rendered = "0" if pieces["branch"] != "master": rendered += ".dev0" - rendered += "+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1501,7 +1497,7 @@ def render_pep440_pre(pieces): tag_version, post_version = pep440_split_post(pieces["closest-tag"]) rendered = tag_version if post_version is not None: - rendered += ".post%d.dev%d" % (post_version+1, pieces["distance"]) + rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) else: rendered += ".post0.dev%d" % (pieces["distance"]) else: @@ -1634,11 +1630,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None + } if not style or style == "default": style = "pep440" # the default @@ -1662,9 +1660,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date") + } class VersioneerBadRootError(Exception): @@ -1742,9 +1744,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None + } def get_version(): @@ -1800,6 +1806,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1826,6 +1833,7 @@ def run(self): from distutils.command.build_py import build_py as _build_py class cmd_build_py(_build_py): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1834,10 +1842,10 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if 'build_ext' in cmds: @@ -1848,6 +1856,7 @@ def run(self): from distutils.command.build_ext import build_ext as _build_ext class cmd_build_ext(_build_ext): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1861,14 +1870,15 @@ def run(self): return # now locate _version.py in the new build/ directory and replace # it with an updated value - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_ext"] = cmd_build_ext if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1877,6 +1887,7 @@ def run(self): # ... class cmd_build_exe(_build_exe): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1889,13 +1900,15 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] @@ -1903,6 +1916,7 @@ def run(self): from py2exe.distutils_buildexe import py2exe as _py2exe class cmd_py2exe(_py2exe): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1915,13 +1929,15 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1933,6 +1949,7 @@ def run(self): from distutils.command.sdist import sdist as _sdist class cmd_sdist(_sdist): + def run(self): versions = get_versions() self._versioneer_generated_versions = versions @@ -1950,8 +1967,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file(target_versionfile, self._versioneer_generated_versions) + cmds["sdist"] = cmd_sdist return cmds @@ -2011,11 +2028,9 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (OSError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except (OSError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (OSError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -2024,15 +2039,16 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -2080,8 +2096,7 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print(" appending versionfile_source ('%s') to MANIFEST.in" % cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From 4002f65ada3ad456fc9d84d54d8786d87032a8e9 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 13 Dec 2022 14:08:25 -0700 Subject: [PATCH 28/55] Formatting fixes --- python/versioneer.py | 189 +++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 86 deletions(-) diff --git a/python/versioneer.py b/python/versioneer.py index 0f6320e52..89d6cf34a 100644 --- a/python/versioneer.py +++ b/python/versioneer.py @@ -13,9 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. - # Version: 0.18 - """The Versioneer - like a rocketeer, but for versions. The Versioneer @@ -292,10 +290,12 @@ """ from __future__ import print_function + try: import configparser except ImportError: import ConfigParser as configparser + import errno import json import os @@ -340,8 +340,7 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) + print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(me), versioneer_py)) except NameError: pass return root @@ -363,6 +362,7 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None + cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -387,17 +387,18 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -405,10 +406,11 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, + p = subprocess.Popen([c] + args, + cwd=cwd, + env=env, stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + stderr=(subprocess.PIPE if hide_stderr else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -420,7 +422,7 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return None, None else: if verbose: - print("unable to find command, tried %s" % (commands,)) + print("unable to find command, tried %s" % (commands, )) return None, None stdout = p.communicate()[0].strip() if sys.version_info[0] >= 3: @@ -1028,16 +1030,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1052,8 +1057,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1096,8 +1100,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag @@ -1106,8 +1109,7 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] @@ -1120,13 +1122,11 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1182,16 +1182,19 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1220,11 +1223,9 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1233,8 +1234,7 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1266,8 +1266,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1381,11 +1380,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None + } if not style or style == "default": style = "pep440" # the default @@ -1405,9 +1406,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date") + } class VersioneerBadRootError(Exception): @@ -1485,9 +1490,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None + } def get_version(): @@ -1536,6 +1545,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1560,6 +1570,7 @@ def run(self): from distutils.command.build_py import build_py as _build_py class cmd_build_py(_build_py): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1568,14 +1579,15 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1584,6 +1596,7 @@ def run(self): # ... class cmd_build_exe(_build_exe): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1596,23 +1609,26 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] if 'py2exe' in sys.modules: # py2exe enabled? try: - from py2exe.distutils_buildexe import py2exe as _py2exe # py3 + from py2exe.distutils_buildexe import py2exe as _py2exe except ImportError: - from py2exe.build_exe import py2exe as _py2exe # py2 + from py2exe.build_exe import py2exe as _py2exe class cmd_py2exe(_py2exe): + def run(self): root = get_root() cfg = get_config_from_root(root) @@ -1625,13 +1641,15 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1641,6 +1659,7 @@ def run(self): from distutils.command.sdist import sdist as _sdist class cmd_sdist(_sdist): + def run(self): versions = get_versions() self._versioneer_generated_versions = versions @@ -1658,8 +1677,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file(target_versionfile, self._versioneer_generated_versions) + cmds["sdist"] = cmd_sdist return cmds @@ -1714,11 +1733,9 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except (EnvironmentError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1727,15 +1744,16 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1777,8 +1795,7 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print(" appending versionfile_source ('%s') to MANIFEST.in" % cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From 7b6eddb8c9555eef2c5c167734efe552035bcce5 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Wed, 14 Dec 2022 14:38:50 -0700 Subject: [PATCH 29/55] Bump utilities repo --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index e6506a90a..70e9043d6 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit e6506a90a456d3bf69dfd626ce4955f7ad26e79f +Subproject commit 70e9043d6525091c18d87b6a3fe2890bf110fc98 From b67b0e96354e3cdc47b7b14c323c9c21ef623bfe Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Wed, 14 Dec 2022 14:50:45 -0700 Subject: [PATCH 30/55] Bump utilties --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index 70e9043d6..f410de133 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 70e9043d6525091c18d87b6a3fe2890bf110fc98 +Subproject commit f410de13303b95468cb8771be767910df1daa06b From 1962543670052e47590a0f3c87d9cb5cf6fcc6f5 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 15 Dec 2022 16:13:14 -0700 Subject: [PATCH 31/55] PR feedback updates --- CMakeLists.txt | 5 ++++- cmake/dependencies.cmake | 5 +++-- cpp/mrc/tests/modules/test_segment_modules.cpp | 3 ++- docs/quickstart/CMakeLists.txt | 4 +--- .../hybrid/mrc_qs_hybrid/common/CMakeLists.txt | 14 +++++++------- external/utilities | 2 +- protos/CMakeLists.txt | 2 +- python/CMakeLists.txt | 1 - 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97baf13d4..ea5c77737 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,12 +91,16 @@ if(NOT DEFINED CMAKE_CUDA_HOST_COMPILER) # incompatible with CUDA 11.4/11.5/11.6. See Issue #102 if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER}) + endif() endif() if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Our version of NVCC officially only supports clang versions 3.2 - 13, we are now using 14 set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -allow-unsupported-compiler") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts") + #add_compile_options(-fcoroutines-ts) # Required for clang to use the coroutines libraries endif() # Now enable CUDA @@ -163,7 +167,6 @@ if(MRC_BUILD_DOCS) add_subdirectory(docs) endif() -# Uncomment the following to print all available targets if (MRC_ENABLE_DEBUG_INFO) morpheus_utils_print_all_targets() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 2a051a2b6..6af63e000 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -65,6 +65,7 @@ morpheus_utils_configure_ucx() morpheus_utils_configure_hwloc() # expected +# ======== morpheus_utils_configure_tl_expected() # NVIDIA RAPIDS RMM @@ -119,11 +120,11 @@ rapids_find_package(nlohmann_json REQUIRED # prometheus # ========= -morpheus_utils_configure_prometheus_cpp(${PROMETHEUS_CPP_VERSION}) +morpheus_utils_configure_prometheus_cpp() # libcudacxx # ========= -morpheus_utils_configure_libcudacxx(${LIBCUDACXX_VERSION}) +morpheus_utils_configure_libcudacxx() if(MRC_BUILD_BENCHMARKS) # google benchmark diff --git a/cpp/mrc/tests/modules/test_segment_modules.cpp b/cpp/mrc/tests/modules/test_segment_modules.cpp index 8c9edfb8e..046785836 100644 --- a/cpp/mrc/tests/modules/test_segment_modules.cpp +++ b/cpp/mrc/tests/modules/test_segment_modules.cpp @@ -407,8 +407,10 @@ TEST_F(TestSegmentModules, ModuleTemplateTest) #if !defined(__clang__) && defined(__GNUC__) // Work around for GCC : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83258 +#pragma GCC visibility push(default) auto F_1 = []() -> int { return 15; }; auto F_2 = []() -> std::string { return "test string"; }; +#pragma GCC visibility pop #endif TEST_F(TestSegmentModules, ModuleTemplateWithInitTest) @@ -473,5 +475,4 @@ TEST_F(TestSegmentModules, ModuleTemplateWithInitTest) EXPECT_EQ(packet_count_1, 42); EXPECT_EQ(packet_count_2, 24); } - } // namespace mrc diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index 246db715f..74441d15c 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -21,9 +21,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) list(PREPEND CMAKE_PREFIX_PATH "$ENV{CONDA_PREFIX}") list(PREPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake") -# Add the RAPIDS cmake helper scripts -# TODO: Shouldn't be required since we do it at source scope -# include(morpheus_utils/environment_config/rapids_cmake/setup) +morpheus_utils_python_modules_ensure_python3() project(mrc-quickstart VERSION 23.01 diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt index 5d4453fe6..5936267e3 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt @@ -18,16 +18,16 @@ morpheus_utils_add_pybind11_library( # MODULE_ROOT # ${QUICKSTART_HYBRID_HOME} SOURCE_FILES - data.cpp + data.cpp LINK_TARGETS - mrc::pymrc + mrc::pymrc OUTPUT_TARGET - common_data_target + common_data_target ) target_include_directories(${common_data_target} PUBLIC - ./include + ./include ) morpheus_utils_inplace_build_copy(${common_data_target} ${CMAKE_CURRENT_SOURCE_DIR}) @@ -35,11 +35,11 @@ morpheus_utils_inplace_build_copy(${common_data_target} ${CMAKE_CURRENT_SOURCE_D morpheus_utils_add_pybind11_library( nodes SOURCE_FILES - nodes.cpp + nodes.cpp LINK_TARGETS - ${common_data_target} + ${common_data_target} OUTPUT_TARGET - nodes_data_target + nodes_data_target ) morpheus_utils_inplace_build_copy(${nodes_data_target} ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/external/utilities b/external/utilities index f410de133..6c65b6a78 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit f410de13303b95468cb8771be767910df1daa06b +Subproject commit 6c65b6a78cadd8972d773c5eb715af5db7f560fc diff --git a/protos/CMakeLists.txt b/protos/CMakeLists.txt index 06c2afd1f..e281a8d53 100644 --- a/protos/CMakeLists.txt +++ b/protos/CMakeLists.txt @@ -20,7 +20,7 @@ set(MRC_PROTO_MODULE_PATH_EXTENSIONS # Prepend path updates so they take priority in this scope. list(PREPEND CMAKE_MODULE_PATH ${MRC_PROTO_MODULE_PATH_EXTENSIONS}) -include(morpheus_utils/grpc/GRPCGenerateCPP) +include(morpheus_utils/grpc/grpc_generate_cpp) add_library(mrc_protos) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 31b063418..95a821ad8 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -29,7 +29,6 @@ option(${OPTION_PREFIX}_PYTHON_BUILD_STUBS "Whether or not to generated .pyi stu set(Python3_FIND_VIRTUALENV "FIRST") set(Python3_FIND_STRATEGY "LOCATION") -include(morpheus_utils/python/register_api) morpheus_utils_print_python_info() # Create the mrc python package From 1c97bc6bc6f013a25c051347585a3940e5fb88bf Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 15 Dec 2022 16:49:46 -0700 Subject: [PATCH 32/55] Utilities version bump --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index 6c65b6a78..80db0c868 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 6c65b6a78cadd8972d773c5eb715af5db7f560fc +Subproject commit 80db0c868b8e8badb18c50503759b4411e5860ef From 979900eef9b540c548fabfe80158a623e9eb8c4f Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 16 Dec 2022 10:56:25 -0700 Subject: [PATCH 33/55] Remove early enable_language call --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea5c77737..567cbb2f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,6 @@ set(MRC_RAPIDS_VERSION "22.10" CACHE STRING "Which version of RAPIDS to build fo set(MRC_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache" CACHE PATH "Directory to contain all CPM and CCache data") mark_as_advanced(MRC_CACHE_DIR) -enable_language(C CXX) enable_testing() if (MRC_USE_IWYU AND MRC_USE_CCACHE) From 80a9372d8665f8d599d44d23e86fdb3072ae6639 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 16 Dec 2022 11:11:57 -0700 Subject: [PATCH 34/55] Utilities repo version bump --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index 80db0c868..b684e83e2 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 80db0c868b8e8badb18c50503759b4411e5860ef +Subproject commit b684e83e26d05a3241bc0f8398280be4c460b01a From ab0878b904078c71efc06151253c24dc104a421e Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 16 Dec 2022 18:08:33 -0700 Subject: [PATCH 35/55] Bump utilities repo version, and switch to morpheus utils init cpm --- CMakeLists.txt | 6 ++- cmake/dependencies.cmake | 32 +++------------- cmake/environment/init_compiler.cmake | 53 --------------------------- external/utilities | 2 +- 4 files changed, 10 insertions(+), 83 deletions(-) delete mode 100644 cmake/environment/init_compiler.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 567cbb2f2..573d87f1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,9 @@ endif() # MRC CMake path and module extensions set(MRC_CMAKE_MODULE_PATH_EXTENSIONS "${CMAKE_CURRENT_SOURCE_DIR}/cmake" - "${CMAKE_CURRENT_SOURCE_DIR}/external/utilities/cmake") + "${CMAKE_CURRENT_SOURCE_DIR}/external/utilities/cmake" + "${CMAKE_CURRENT_SOURCE_DIR}/external/utilities/cmake/morpheus_utils/package_search" + ) set(MRC_CMAKE_PREFIX_PATH_EXTENSIONS "${CMAKE_CURRENT_SOURCE_DIR}/cmake" @@ -145,7 +147,7 @@ add_subdirectory(protos) # ################################### # - Post dependencies setup -------- -include(environment/init_compiler) +morpheus_utils_compiler_set_defaults(MRC_USE_CLANG_TIDY) # Setup code coverage components include(environment/init_coverage) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 6af63e000..38f270f12 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -15,33 +15,11 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "dep") -# Print CMake settings when verbose output is enabled -message(VERBOSE "PROJECT_NAME: " ${PROJECT_NAME}) -message(VERBOSE "CMAKE_HOST_SYSTEM: ${CMAKE_HOST_SYSTEM}") -message(VERBOSE "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE}) -message(VERBOSE "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER}) -message(VERBOSE "CMAKE_CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID}) -message(VERBOSE "CMAKE_CXX_COMPILER_VERSION: " ${CMAKE_CXX_COMPILER_VERSION}) -message(VERBOSE "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS}) -message(VERBOSE "CMAKE_CUDA_COMPILER: " ${CMAKE_CUDA_COMPILER}) -message(VERBOSE "CMAKE_CUDA_COMPILER_ID: " ${CMAKE_CUDA_COMPILER_ID}) -message(VERBOSE "CMAKE_CUDA_COMPILER_VERSION: " ${CMAKE_CUDA_COMPILER_VERSION}) -message(VERBOSE "CMAKE_CUDA_FLAGS: " ${CMAKE_CUDA_FLAGS}) -message(VERBOSE "CMAKE_CURRENT_SOURCE_DIR: " ${CMAKE_CURRENT_SOURCE_DIR}) -message(VERBOSE "CMAKE_CURRENT_BINARY_DIR: " ${CMAKE_CURRENT_BINARY_DIR}) -message(VERBOSE "CMAKE_CURRENT_LIST_DIR: " ${CMAKE_CURRENT_LIST_DIR}) -message(VERBOSE "CMAKE_EXE_LINKER_FLAGS: " ${CMAKE_EXE_LINKER_FLAGS}) -message(VERBOSE "CMAKE_INSTALL_PREFIX: " ${CMAKE_INSTALL_PREFIX}) -message(VERBOSE "CMAKE_INSTALL_FULL_INCLUDEDIR: " ${CMAKE_INSTALL_FULL_INCLUDEDIR}) -message(VERBOSE "CMAKE_INSTALL_FULL_LIBDIR: " ${CMAKE_INSTALL_FULL_LIBDIR}) -message(VERBOSE "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH}) -message(VERBOSE "CMAKE_PREFIX_PATH: " ${CMAKE_PREFIX_PATH}) -message(VERBOSE "CMAKE_FIND_ROOT_PATH: " ${CMAKE_FIND_ROOT_PATH}) -message(VERBOSE "CMAKE_LIBRARY_ARCHITECTURE: " ${CMAKE_LIBRARY_ARCHITECTURE}) -message(VERBOSE "FIND_LIBRARY_USE_LIB64_PATHS: " ${FIND_LIBRARY_USE_LIB64_PATHS}) -message(VERBOSE "CMAKE_SYSROOT: " ${CMAKE_SYSROOT}) -message(VERBOSE "CMAKE_STAGING_PREFIX: " ${CMAKE_STAGING_PREFIX}) -message(VERBOSE "CMAKE_FIND_ROOT_PATH_MODE_INCLUDE: " ${CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}) +if (VERBOSE) + morpheus_utils_print_config() +endif() + +morpheus_utils_initialize_cpm(MRC_CACHE_DIR) # Start with CUDA. Need to add it to our export set rapids_find_package(CUDAToolkit diff --git a/cmake/environment/init_compiler.cmake b/cmake/environment/init_compiler.cmake deleted file mode 100644 index 3ea617d5f..000000000 --- a/cmake/environment/init_compiler.cmake +++ /dev/null @@ -1,53 +0,0 @@ -# ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. -# ============================================================================= - -# ###################################################################################################################### -# * CMake properties ------------------------------------------------------------------------------ - -list(APPEND CMAKE_MESSAGE_CONTEXT "compiler") - -include(CheckCCompilerFlag) -include(CheckCXXCompilerFlag) - -# ################################### -# - Compiler Flags ----------------- -check_c_compiler_flag("-O0" COMPILER_C_HAS_O0) - -if(COMPILER_C_HAS_O0) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0") -endif() - -check_cxx_compiler_flag("-O0" COMPILER_CXX_HAS_O0) - -if(COMPILER_CXX_HAS_O0) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0") - - # Also set cuda here - set(CMAKE_CUDA_FLAGS_DEBUG "${CMAKE_CUDA_FLAGS_DEBUG} -O0") -endif() - -# ################################### -# - Compiler Checks ---------------- - -# Only set the clang-tidy options for our source code targets -if(MRC_USE_CLANG_TIDY) - set(CMAKE_C_CLANG_TIDY "clang-tidy") - set(CMAKE_CXX_CLANG_TIDY "clang-tidy") - message(STATUS "Enabling clang-tidy for targets in project ${PROJECT_NAME}") -endif() - -list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/external/utilities b/external/utilities index b684e83e2..32d3ca98b 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit b684e83e26d05a3241bc0f8398280be4c460b01a +Subproject commit 32d3ca98b42f07a62ea4de3fbe752501b0f81e68 From d2445812ce805e3fc01e0bc6e5f9f888e8c06eb6 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 19 Dec 2022 13:20:19 -0700 Subject: [PATCH 36/55] Move additional files into utilities repo --- ci/runner/README.md | 43 --------------------------------- ci/runner/build_and_push.sh | 48 ------------------------------------- external/utilities | 2 +- 3 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 ci/runner/README.md delete mode 100755 ci/runner/build_and_push.sh diff --git a/ci/runner/README.md b/ci/runner/README.md deleted file mode 100644 index 912d947f9..000000000 --- a/ci/runner/README.md +++ /dev/null @@ -1,43 +0,0 @@ - - -The `Dockerfile` in this directory defines the images used by the CI runner not for MRC itself. - -# Building CI images -The `Dockerfile` defines two targets: `base` and `driver`. The `driver` target includes the Nvidia driver needed to build MRC on a machine without access to a GPU. - -To build the images from the root of the MRC repo run: -```bash -SKIP_PUSH=1 ci/runner/build_and_push.sh -``` - -# Build and push CI images -This will require being a member of the `Morpheus Early Access CI` group in [NGC](https://catalog.ngc.nvidia.com) and logging into the `nvcr.io` registry prior to running. - -From the root of the MRC repo run: -```bash -ci/runner/build_and_push.sh -``` - -If the images are already built, the build step can be skipped by setting `SKIP_BUILD=1`. - -# Updating CI to use the new images -Update `.github/workflows/pull_request.yml` changing these two lines with the new image names: -```yaml - container: nvcr.io/ea-nvidia-morpheus/morpheus:mrc-ci-driver-221128 - test_container: nvcr.io/ea-nvidia-morpheus/morpheus:mrc-ci-base-221128 -``` diff --git a/ci/runner/build_and_push.sh b/ci/runner/build_and_push.sh deleted file mode 100755 index 5b11f7fc4..000000000 --- a/ci/runner/build_and_push.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# 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. - -DOCKER_TARGET=${DOCKER_TARGET:-"base" "driver"} -DOCKER_BUILDKIT=${DOCKER_BUILDKIT:-1} -DOCKER_REGISTRY_SERVER=${DOCKER_REGISTRY_SERVER:-"nvcr.io"} -DOCKER_REGISTRY_PATH=${DOCKER_REGISTRY_PATH:-"/ea-nvidia-morpheus/morpheus"} -DOCKER_TAG_PREFIX=${DOCKER_TAG_PREFIX:-"mrc-ci"} -DOCKER_TAG_POSTFIX=${DOCKER_TAG_POSTFIX:-"$(date +'%y%m%d')"} -DOCKER_EXTRA_ARGS=${DOCKER_EXTRA_ARGS:-""} - -SKIP_BUILD=${SKIP_BUILD:-""} -SKIP_PUSH=${SKIP_PUSH:-""} - -set -e - -function get_image_full_name() { - echo "${DOCKER_REGISTRY_SERVER}${DOCKER_REGISTRY_PATH}:${DOCKER_TAG_PREFIX}-${build_target}-${DOCKER_TAG_POSTFIX}" -} - -if [[ "${SKIP_BUILD}" == "" ]]; then - for build_target in ${DOCKER_TARGET[@]}; do - FULL_NAME=$(get_image_full_name) - echo "Building target \"${build_target}\" as ${FULL_NAME}"; - docker buildx build --network=host ${DOCKER_EXTRA_ARGS} --target ${build_target} -t ${FULL_NAME} -f ./Dockerfile . - done -fi - -if [[ "${SKIP_PUSH}" == "" ]]; then - for build_target in ${DOCKER_TARGET[@]}; do - FULL_NAME=$(get_image_full_name) - echo "Pushing ${FULL_NAME}"; - docker push ${FULL_NAME} - done -fi diff --git a/external/utilities b/external/utilities index 32d3ca98b..e07a0462f 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 32d3ca98b42f07a62ea4de3fbe752501b0f81e68 +Subproject commit e07a0462f85f28fd15f7e92f317666a3287eb236 From 0db3416bcf73fa80265749ed1ad1de9bb690bae3 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 20 Dec 2022 12:56:42 -0700 Subject: [PATCH 37/55] Update .gitmodules Roll module code to point at public utilities repo. --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 70eb8999a..10b4ee8b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "morpheus_utils"] path = external/utilities - url = git@github.com:nv-morpheus/utilities.git - branch = devin-issue-225-87 + url = https://github.com/nv-morpheus/utilities.git + branch = branch-23.01 From 17b7c1915f832ddf4bb474d5b9fc92c6b448221f Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 20 Dec 2022 15:52:09 -0700 Subject: [PATCH 38/55] Bump utilities versions --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index e07a0462f..a3e7e1d3b 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit e07a0462f85f28fd15f7e92f317666a3287eb236 +Subproject commit a3e7e1d3b8004a766013e9e52fe6d34de77d6bbc From 2a22a08d406c0275cbac47e3ca9a0d51f4404a37 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 20 Dec 2022 16:00:44 -0700 Subject: [PATCH 39/55] Bump util repo version --- external/utilities | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/utilities b/external/utilities index a3e7e1d3b..1c2963a9d 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit a3e7e1d3b8004a766013e9e52fe6d34de77d6bbc +Subproject commit 1c2963a9dabbfadecf2cc30661a616c8f0d95912 From 4d04c2d4274e0c0e891ee53a2969da9cc994f17b Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 6 Jan 2023 14:55:41 -0700 Subject: [PATCH 40/55] Roll to utilities branch 23.01 --- external/utilities | 2 +- python/CMakeLists.txt | 7 +- python/mrc/_pymrc/CMakeLists.txt | 1 + python/mrc/_pymrc/include/pymrc/tracers.hpp | 14 ++ python/mrc/_pymrc/include/pymrc/watchers.hpp | 126 +++++++------- python/mrc/_pymrc/src/tracers.cpp | 19 +++ python/mrc/benchmarking/CMakeLists.txt | 4 +- python/mrc/benchmarking/tracers.cpp | 6 +- python/mrc/benchmarking/watchers.cpp | 168 ++++++++++++------- python/mrc/tests/test_edges.cpp | 2 + 10 files changed, 221 insertions(+), 128 deletions(-) create mode 100644 python/mrc/_pymrc/include/pymrc/tracers.hpp create mode 100644 python/mrc/_pymrc/src/tracers.cpp diff --git a/external/utilities b/external/utilities index 1c2963a9d..a83eb0ff3 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit 1c2963a9dabbfadecf2cc30661a616c8f0d95912 +Subproject commit a83eb0ff3281013a886a0f8ab5304d55094ae8ee diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 95a821ad8..13607d535 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -60,7 +60,12 @@ endmacro() add_subdirectory(mrc/_pymrc) add_subdirectory(mrc/core) -add_subdirectory(mrc/benchmarking) + +# ################################################################################################## +# - Benchmarks-------------------------------------------------------------------------------------- +if (MRC_BUILD_BENCHMARKS) + add_subdirectory(mrc/benchmarking) +endif() # ################################################################################################## # - tests ----------------------------------------------------------------------------------------- diff --git a/python/mrc/_pymrc/CMakeLists.txt b/python/mrc/_pymrc/CMakeLists.txt index a1078d5fe..3acd9fe57 100644 --- a/python/mrc/_pymrc/CMakeLists.txt +++ b/python/mrc/_pymrc/CMakeLists.txt @@ -33,6 +33,7 @@ add_library(pymrc src/segment_modules.cpp src/subscriber.cpp src/system.cpp + src/tracers.cpp src/types.cpp src/utilities/deserializers.cpp src/utilities/object_cache.cpp diff --git a/python/mrc/_pymrc/include/pymrc/tracers.hpp b/python/mrc/_pymrc/include/pymrc/tracers.hpp new file mode 100644 index 000000000..cd5603349 --- /dev/null +++ b/python/mrc/_pymrc/include/pymrc/tracers.hpp @@ -0,0 +1,14 @@ +// +// Created by drobison on 1/6/23. +// + +#pragma once + +#include "mrc/benchmarking/tracer.hpp" + +#include // for object, dict + +namespace mrc::pymrc { + using latency_tracer_t = mrc::benchmarking::TracerEnsemble; + using throughput_tracer_t = mrc::benchmarking::TracerEnsemble; +} diff --git a/python/mrc/_pymrc/include/pymrc/watchers.hpp b/python/mrc/_pymrc/include/pymrc/watchers.hpp index 00af0d5e7..16473d646 100644 --- a/python/mrc/_pymrc/include/pymrc/watchers.hpp +++ b/python/mrc/_pymrc/include/pymrc/watchers.hpp @@ -17,8 +17,8 @@ #pragma once +#include "pymrc/tracers.hpp" #include "mrc/benchmarking/segment_watcher.hpp" -#include "mrc/benchmarking/tracer.hpp" #include // for object, dict @@ -27,12 +27,13 @@ #include namespace mrc::segment { -class Builder; -struct ObjectProperties; + class Builder; + + struct ObjectProperties; } // namespace mrc::segment namespace mrc::pymrc { -class Executor; + class Executor; } namespace mrc::pymrc { @@ -40,60 +41,69 @@ namespace mrc::pymrc { // Export everything in the mrc::pymrc namespace by default since we compile with -fvisibility=hidden #pragma GCC visibility push(default) -using latency_ensemble_t = mrc::benchmarking::TracerEnsemble; -using latency_watcher_t = mrc::benchmarking::SegmentWatcher; - -using throughput_ensemble_t = mrc::benchmarking::TracerEnsemble; -using throughput_watcher_t = mrc::benchmarking::SegmentWatcher; - -class LatencyWatcher : public latency_watcher_t -{ - public: - LatencyWatcher(std::shared_ptr executor); - LatencyWatcher(std::shared_ptr executor, std::function payload_init); - - void make_segment(const std::string& name, - const std::function& init); - std::shared_ptr make_tracer_source(mrc::segment::Builder& seg, - const std::string& name, - bool force_sequential = false); - std::shared_ptr make_traced_node( - mrc::segment::Builder& seg, - const std::string& name, - std::function map_f); - std::shared_ptr make_tracer_sink( - mrc::segment::Builder& seg, const std::string& name, std::function sink_f); - - pybind11::dict aggregate_tracers_as_pydict(); - - private: - std::shared_ptr m_executor; -}; - -class ThroughputWatcher : public throughput_watcher_t -{ - public: - ThroughputWatcher(std::shared_ptr executor); - ThroughputWatcher(std::shared_ptr executor, - std::function payload_init); - - void make_segment(const std::string& name, - const std::function& init); - std::shared_ptr make_tracer_source(mrc::segment::Builder& seg, - const std::string& name, - bool force_sequential = false); - std::shared_ptr make_traced_node( - mrc::segment::Builder& seg, - const std::string& name, - std::function map_f); - std::shared_ptr make_tracer_sink( - mrc::segment::Builder& seg, const std::string& name, std::function sink_f); - - pybind11::dict aggregate_tracers_as_pydict(); - - private: - std::shared_ptr m_executor; -}; + using latency_ensemble_t = mrc::benchmarking::TracerEnsemble; + using latency_watcher_t = mrc::benchmarking::SegmentWatcher; + + using throughput_ensemble_t = mrc::benchmarking::TracerEnsemble; + using throughput_watcher_t = mrc::benchmarking::SegmentWatcher; + + class LatencyWatcher : public latency_watcher_t { + public: + LatencyWatcher(std::shared_ptr executor); + + LatencyWatcher(std::shared_ptr executor, + std::function payload_init); + + void make_segment(const std::string &name, + const std::function &init); + + std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, + const std::string &name, + bool force_sequential = false); + + std::shared_ptr make_traced_node( + mrc::segment::Builder &seg, + const std::string &name, + std::function map_f); + + std::shared_ptr make_tracer_sink( + mrc::segment::Builder &seg, const std::string &name, + std::function sink_f); + + pybind11::dict aggregate_tracers_as_pydict(); + + private: + std::shared_ptr m_executor; + }; + + class ThroughputWatcher : public throughput_watcher_t { + public: + ThroughputWatcher(std::shared_ptr executor); + + ThroughputWatcher(std::shared_ptr executor, + std::function payload_init); + + void make_segment(const std::string &name, + const std::function &init); + + std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, + const std::string &name, + bool force_sequential = false); + + std::shared_ptr make_traced_node( + mrc::segment::Builder &seg, + const std::string &name, + std::function map_f); + + std::shared_ptr make_tracer_sink( + mrc::segment::Builder &seg, const std::string &name, + std::function sink_f); + + pybind11::dict aggregate_tracers_as_pydict(); + + private: + std::shared_ptr m_executor; + }; #pragma GCC visibility pop } // namespace mrc::pymrc diff --git a/python/mrc/_pymrc/src/tracers.cpp b/python/mrc/_pymrc/src/tracers.cpp new file mode 100644 index 000000000..7e02c0209 --- /dev/null +++ b/python/mrc/_pymrc/src/tracers.cpp @@ -0,0 +1,19 @@ +/** + * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ + +// TODO(Devin) +#include "pymrc/tracers.hpp" \ No newline at end of file diff --git a/python/mrc/benchmarking/CMakeLists.txt b/python/mrc/benchmarking/CMakeLists.txt index 626c3720c..ea348a53a 100644 --- a/python/mrc/benchmarking/CMakeLists.txt +++ b/python/mrc/benchmarking/CMakeLists.txt @@ -14,7 +14,7 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "benchmarking") -mrc_add_pybind11_module(watchers SOURCE_FILES watchers.cpp) -mrc_add_pybind11_module(tracers SOURCE_FILES tracers.cpp trace_statistics.cpp) +mrc_add_pybind11_module(watchers SOURCE_FILES watchers.cpp trace_statistics.cpp) +#mrc_add_pybind11_module(tracers SOURCE_FILES tracers.cpp trace_statistics.cpp) list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/python/mrc/benchmarking/tracers.cpp b/python/mrc/benchmarking/tracers.cpp index 1374973b3..abf75bf86 100644 --- a/python/mrc/benchmarking/tracers.cpp +++ b/python/mrc/benchmarking/tracers.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ -#include "mrc/benchmarking/tracer.hpp" +#include "pymrc/tracers.hpp" #include #include @@ -27,13 +27,11 @@ namespace mrc::pymrc { namespace py = pybind11; +using namespace mrc::benchmarking; void init_tracer_stats_api(py::module_& m); void init_tracer_api(py::module_& m); -using latency_tracer_t = mrc::benchmarking::TracerEnsemble; -using throughput_tracer_t = mrc::benchmarking::TracerEnsemble; - // TODO (Devin): Not supporting direct tracers yet, file still needs to be implemented. PYBIND11_MODULE(tracers, m) { diff --git a/python/mrc/benchmarking/watchers.cpp b/python/mrc/benchmarking/watchers.cpp index 26720e54e..567aed434 100644 --- a/python/mrc/benchmarking/watchers.cpp +++ b/python/mrc/benchmarking/watchers.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include "pymrc/tracers.hpp" #include "pymrc/watchers.hpp" #include "pymrc/executor.hpp" // IWYU pragma: keep @@ -31,67 +32,110 @@ #include namespace mrc::pymrc { + namespace py = pybind11; -namespace py = pybind11; - -PYBIND11_MODULE(watchers, m) -{ - m.doc() = R"pbdoc()pbdoc"; - - // Segment watcher allows for each tracer object to have a data payload. To simplify, for now, we'll assume - // that the payload is a py::object. - // auto SegmentWatcher = py::class_>(m, "SegmentWatcher"); - auto PyLatencyWatcher = py::class_(m, "LatencyWatcher"); - PyLatencyWatcher.def(py::init>()); - PyLatencyWatcher.def(py::init, std::function>()); - PyLatencyWatcher.def("aggregate_tracers", &pymrc::LatencyWatcher::aggregate_tracers_as_pydict); - // PyLatencyWatcher.def("make_tracer_source", &pymrc::LatencyWatcher::create_rx_tracer_source); - PyLatencyWatcher.def("is_running", &pymrc::LatencyWatcher::is_running); - PyLatencyWatcher.def("make_segment", pymrc::wrap_segment_init_callback(&pymrc::LatencyWatcher::make_segment)); - PyLatencyWatcher.def( - "make_tracer_source", &pymrc::LatencyWatcher::make_tracer_source, py::return_value_policy::reference_internal); - PyLatencyWatcher.def( - "make_traced_node", &pymrc::LatencyWatcher::make_traced_node, py::return_value_policy::reference_internal); - PyLatencyWatcher.def( - "make_tracer_sink", &pymrc::LatencyWatcher::make_tracer_sink, py::return_value_policy::reference_internal); - PyLatencyWatcher.def("reset", &pymrc::LatencyWatcher::reset, py::call_guard()); - PyLatencyWatcher.def("run", &pymrc::LatencyWatcher::run, py::call_guard()); - PyLatencyWatcher.def("shutdown", &pymrc::LatencyWatcher::shutdown, py::call_guard()); - PyLatencyWatcher.def("start_trace", &pymrc::LatencyWatcher::start_trace, py::call_guard()); - PyLatencyWatcher.def("stop_trace", &pymrc::LatencyWatcher::stop_trace, py::call_guard()); - PyLatencyWatcher.def( - "trace_until_notified", &pymrc::LatencyWatcher::trace_until_notified, py::call_guard()); - PyLatencyWatcher.def("tracer_count", py::overload_cast(&pymrc::LatencyWatcher::tracer_count)); - PyLatencyWatcher.def("tracing", &pymrc::LatencyWatcher::tracing); - - /** Throughput Watcher Begin **/ - auto PyThroughputWatcher = py::class_(m, "ThroughputWatcher"); - - PyThroughputWatcher.def(py::init>()); - PyThroughputWatcher.def( - py::init, std::function>()); - PyThroughputWatcher.def("aggregate_tracers", &pymrc::ThroughputWatcher::aggregate_tracers_as_pydict); - // PyThroughputWatcher.def("make_tracer_source", &pymrc::ThroughputWatcher::create_rx_tracer_source); - PyThroughputWatcher.def("is_running", &pymrc::ThroughputWatcher::is_running); - PyThroughputWatcher.def("make_segment", pymrc::wrap_segment_init_callback(&pymrc::ThroughputWatcher::make_segment)); - PyThroughputWatcher.def("make_tracer_source", - &pymrc::ThroughputWatcher::make_tracer_source, - py::return_value_policy::reference_internal); - PyThroughputWatcher.def( - "make_traced_node", &pymrc::ThroughputWatcher::make_traced_node, py::return_value_policy::reference_internal); - PyThroughputWatcher.def( - "make_tracer_sink", &pymrc::ThroughputWatcher::make_tracer_sink, py::return_value_policy::reference_internal); - PyThroughputWatcher.def("reset", &pymrc::ThroughputWatcher::reset, py::call_guard()); - PyThroughputWatcher.def("run", &pymrc::ThroughputWatcher::run, py::call_guard()); - PyThroughputWatcher.def("shutdown", &pymrc::ThroughputWatcher::shutdown, py::call_guard()); - PyThroughputWatcher.def( - "start_trace", &pymrc::ThroughputWatcher::start_trace, py::call_guard()); - PyThroughputWatcher.def( - "stop_trace", &pymrc::ThroughputWatcher::stop_trace, py::call_guard()); - PyThroughputWatcher.def("trace_until_notified", - &pymrc::ThroughputWatcher::trace_until_notified, - py::call_guard()); - PyThroughputWatcher.def("tracer_count", py::overload_cast(&pymrc::ThroughputWatcher::tracer_count)); - PyThroughputWatcher.def("tracing", &pymrc::ThroughputWatcher::tracing); -} + void init_tracer_stats_api(py::module_& m); + void init_tracer_api(py::module_& m); + + PYBIND11_MODULE(watchers, m) { + m.doc() = R"pbdoc()pbdoc"; + + pymrc::import(m, "mrc.core.executor"); + + init_tracer_stats_api(m); + + /** + * @brief define tracer implementations for use with segment watchers + */ + // pymrc::init_tracer_api(m); + + /** + * @brief Tracer objects are packaged into tracer ensembles; we'll just support tracer's with py::object payloads + * for now. + */ + auto LatencyTracer = py::class_>(m, "LatencyTracer"); + LatencyTracer.def(py::init()); + + // TODO(devin) + // LatencyTracer.def("add_counters", &mrc::LatencyTracer::add_counters); + LatencyTracer.def_static("aggregate", [](py::object& obj_type, py::list ensemble_tracers) { + // Something is broken with calling static members + }); + LatencyTracer.def("emit", &latency_tracer_t::emit); + + /** + * @brief ThroughputTracer + */ + auto ThroughputTracer = + py::class_>(m, "ThroughputTracer"); + ThroughputTracer.def(py::init()); + + // Segment watcher allows for each tracer object to have a data payload. To simplify, for now, we'll assume + // that the payload is a py::object. + // auto SegmentWatcher = py::class_>(m, "SegmentWatcher"); + auto PyLatencyWatcher = py::class_(m, "LatencyWatcher"); + PyLatencyWatcher.def(py::init>()); + PyLatencyWatcher.def( + py::init, std::function>()); + PyLatencyWatcher.def("aggregate_tracers", &pymrc::LatencyWatcher::aggregate_tracers_as_pydict); + // PyLatencyWatcher.def("make_tracer_source", &pymrc::LatencyWatcher::create_rx_tracer_source); + PyLatencyWatcher.def("is_running", &pymrc::LatencyWatcher::is_running); + PyLatencyWatcher.def("make_segment", pymrc::wrap_segment_init_callback(&pymrc::LatencyWatcher::make_segment)); + PyLatencyWatcher.def( + "make_tracer_source", &pymrc::LatencyWatcher::make_tracer_source, + py::return_value_policy::reference_internal); + PyLatencyWatcher.def( + "make_traced_node", &pymrc::LatencyWatcher::make_traced_node, + py::return_value_policy::reference_internal); + PyLatencyWatcher.def( + "make_tracer_sink", &pymrc::LatencyWatcher::make_tracer_sink, + py::return_value_policy::reference_internal); + PyLatencyWatcher.def("reset", &pymrc::LatencyWatcher::reset, py::call_guard()); + PyLatencyWatcher.def("run", &pymrc::LatencyWatcher::run, py::call_guard()); + PyLatencyWatcher.def("shutdown", &pymrc::LatencyWatcher::shutdown, py::call_guard()); + PyLatencyWatcher.def("start_trace", &pymrc::LatencyWatcher::start_trace, + py::call_guard()); + PyLatencyWatcher.def("stop_trace", &pymrc::LatencyWatcher::stop_trace, + py::call_guard()); + PyLatencyWatcher.def( + "trace_until_notified", &pymrc::LatencyWatcher::trace_until_notified, + py::call_guard()); + PyLatencyWatcher.def("tracer_count", py::overload_cast(&pymrc::LatencyWatcher::tracer_count)); + PyLatencyWatcher.def("tracing", &pymrc::LatencyWatcher::tracing); + + /** Throughput Watcher Begin **/ + auto PyThroughputWatcher = py::class_(m, "ThroughputWatcher"); + + PyThroughputWatcher.def(py::init>()); + PyThroughputWatcher.def( + py::init, std::function>()); + PyThroughputWatcher.def("aggregate_tracers", &pymrc::ThroughputWatcher::aggregate_tracers_as_pydict); + // PyThroughputWatcher.def("make_tracer_source", &pymrc::ThroughputWatcher::create_rx_tracer_source); + PyThroughputWatcher.def("is_running", &pymrc::ThroughputWatcher::is_running); + PyThroughputWatcher.def("make_segment", + pymrc::wrap_segment_init_callback(&pymrc::ThroughputWatcher::make_segment)); + PyThroughputWatcher.def("make_tracer_source", + &pymrc::ThroughputWatcher::make_tracer_source, + py::return_value_policy::reference_internal); + PyThroughputWatcher.def( + "make_traced_node", &pymrc::ThroughputWatcher::make_traced_node, + py::return_value_policy::reference_internal); + PyThroughputWatcher.def( + "make_tracer_sink", &pymrc::ThroughputWatcher::make_tracer_sink, + py::return_value_policy::reference_internal); + PyThroughputWatcher.def("reset", &pymrc::ThroughputWatcher::reset, py::call_guard()); + PyThroughputWatcher.def("run", &pymrc::ThroughputWatcher::run, py::call_guard()); + PyThroughputWatcher.def("shutdown", &pymrc::ThroughputWatcher::shutdown, + py::call_guard()); + PyThroughputWatcher.def( + "start_trace", &pymrc::ThroughputWatcher::start_trace, py::call_guard()); + PyThroughputWatcher.def( + "stop_trace", &pymrc::ThroughputWatcher::stop_trace, py::call_guard()); + PyThroughputWatcher.def("trace_until_notified", + &pymrc::ThroughputWatcher::trace_until_notified, + py::call_guard()); + PyThroughputWatcher.def("tracer_count", + py::overload_cast(&pymrc::ThroughputWatcher::tracer_count)); + PyThroughputWatcher.def("tracing", &pymrc::ThroughputWatcher::tracing); + } } // namespace mrc::pymrc diff --git a/python/mrc/tests/test_edges.cpp b/python/mrc/tests/test_edges.cpp index 273ec3af2..1b13604eb 100644 --- a/python/mrc/tests/test_edges.cpp +++ b/python/mrc/tests/test_edges.cpp @@ -23,6 +23,7 @@ #include "mrc/channel/status.hpp" #include "mrc/node/edge_connector.hpp" #include "mrc/segment/builder.hpp" +#include "mrc/segment/object.hpp" #include "mrc/utils/string_utils.hpp" #include "mrc/version.hpp" @@ -181,6 +182,7 @@ PYBIND11_MODULE(test_edges_cpp, module) module.doc() = R"pbdoc()pbdoc"; pymrc::import(module, "mrc"); + pymrc::import(module, "mrc.core.segment"); py::class_>(module, "Base").def(py::init<>([]() { return std::make_shared(); })); mrc::pymrc::PortBuilderUtil::register_port_util(); From 883b68f2fb772a3b2c6e848104c71e7ab058e326 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 6 Jan 2023 15:15:31 -0700 Subject: [PATCH 41/55] Update watcher/tracer python bindings to fix stub generation problem --- python/CMakeLists.txt | 4 +--- python/mrc/benchmarking/__init__.py | 10 +++++----- python/mrc/benchmarking/watchers.cpp | 2 -- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 13607d535..8d52aa8d5 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -63,9 +63,7 @@ add_subdirectory(mrc/core) # ################################################################################################## # - Benchmarks-------------------------------------------------------------------------------------- -if (MRC_BUILD_BENCHMARKS) - add_subdirectory(mrc/benchmarking) -endif() +add_subdirectory(mrc/benchmarking) # ################################################################################################## # - tests ----------------------------------------------------------------------------------------- diff --git a/python/mrc/benchmarking/__init__.py b/python/mrc/benchmarking/__init__.py index 7b5408997..a5bb7cf8a 100644 --- a/python/mrc/benchmarking/__init__.py +++ b/python/mrc/benchmarking/__init__.py @@ -13,10 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .tracers import get_tracing_stats -from .tracers import reset_tracing_stats -from .tracers import sync_tracing_state -from .tracers import trace_channels -from .tracers import trace_operators +from .watchers import get_tracing_stats +from .watchers import reset_tracing_stats +from .watchers import sync_tracing_state +from .watchers import trace_channels +from .watchers import trace_operators from .watchers import LatencyWatcher from .watchers import ThroughputWatcher diff --git a/python/mrc/benchmarking/watchers.cpp b/python/mrc/benchmarking/watchers.cpp index 567aed434..88a9d26ae 100644 --- a/python/mrc/benchmarking/watchers.cpp +++ b/python/mrc/benchmarking/watchers.cpp @@ -29,13 +29,11 @@ #include #include #include -#include namespace mrc::pymrc { namespace py = pybind11; void init_tracer_stats_api(py::module_& m); - void init_tracer_api(py::module_& m); PYBIND11_MODULE(watchers, m) { m.doc() = R"pbdoc()pbdoc"; From e44496b260c177350f4e5d1db2e689ac0479f912 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 6 Jan 2023 15:19:28 -0700 Subject: [PATCH 42/55] Formatting updates --- CMakeLists.txt | 2 +- cmake/dependencies.cmake | 2 +- cmake/environment/init_coverage.cmake | 2 +- cmake/environment/init_iwyu.cmake | 2 +- cpp/mrc/CMakeLists.txt | 2 +- cpp/mrc/include/mrc/runnable/types.hpp | 2 +- cpp/mrc/include/mrc/utils/type_utils.hpp | 2 +- cpp/mrc/src/public/utils/type_utils.cpp | 2 +- .../tests/modules/test_segment_modules.cpp | 2 +- docs/quickstart/CMakeLists.txt | 2 +- docs/quickstart/hybrid/CMakeLists.txt | 2 +- .../hybrid/mrc_qs_hybrid/_version.py | 2 +- .../mrc_qs_hybrid/common/CMakeLists.txt | 2 +- .../ex00_wrap_data_objects/CMakeLists.txt | 2 +- .../ex01_wrap_nodes/CMakeLists.txt | 2 +- docs/quickstart/python/CMakeLists.txt | 2 +- .../python/mrc_qs_python/_version.py | 2 +- protos/CMakeLists.txt | 2 +- python/CMakeLists.txt | 2 +- python/mrc/_pymrc/CMakeLists.txt | 2 +- python/mrc/_pymrc/include/pymrc/tracers.hpp | 19 ++++++++++++++++--- python/mrc/_pymrc/include/pymrc/watchers.hpp | 2 +- python/mrc/_pymrc/src/tracers.cpp | 2 +- python/mrc/benchmarking/CMakeLists.txt | 2 +- python/mrc/benchmarking/__init__.py | 6 +++--- python/mrc/benchmarking/tracers.cpp | 2 +- python/mrc/benchmarking/watchers.cpp | 2 +- python/mrc/tests/CMakeLists.txt | 2 +- python/mrc/tests/test_edges.cpp | 2 +- 29 files changed, 46 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 573d87f1e..e93e1dff9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2018-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 38f270f12..b52cc1245 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cmake/environment/init_coverage.cmake b/cmake/environment/init_coverage.cmake index 995758315..8edb1fac7 100644 --- a/cmake/environment/init_coverage.cmake +++ b/cmake/environment/init_coverage.cmake @@ -1,5 +1,5 @@ # ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cmake/environment/init_iwyu.cmake b/cmake/environment/init_iwyu.cmake index 80b6fae6f..d5faebec6 100644 --- a/cmake/environment/init_iwyu.cmake +++ b/cmake/environment/init_iwyu.cmake @@ -1,5 +1,5 @@ # ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cpp/mrc/CMakeLists.txt b/cpp/mrc/CMakeLists.txt index 51905c92c..8593778ca 100644 --- a/cpp/mrc/CMakeLists.txt +++ b/cpp/mrc/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cpp/mrc/include/mrc/runnable/types.hpp b/cpp/mrc/include/mrc/runnable/types.hpp index a817fd3aa..ba672501e 100644 --- a/cpp/mrc/include/mrc/runnable/types.hpp +++ b/cpp/mrc/include/mrc/runnable/types.hpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cpp/mrc/include/mrc/utils/type_utils.hpp b/cpp/mrc/include/mrc/utils/type_utils.hpp index bb3950160..1d2c93868 100644 --- a/cpp/mrc/include/mrc/utils/type_utils.hpp +++ b/cpp/mrc/include/mrc/utils/type_utils.hpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cpp/mrc/src/public/utils/type_utils.cpp b/cpp/mrc/src/public/utils/type_utils.cpp index abdc5a945..71d57f394 100644 --- a/cpp/mrc/src/public/utils/type_utils.cpp +++ b/cpp/mrc/src/public/utils/type_utils.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cpp/mrc/tests/modules/test_segment_modules.cpp b/cpp/mrc/tests/modules/test_segment_modules.cpp index 046785836..7bea2fd29 100644 --- a/cpp/mrc/tests/modules/test_segment_modules.cpp +++ b/cpp/mrc/tests/modules/test_segment_modules.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/CMakeLists.txt b/docs/quickstart/CMakeLists.txt index 74441d15c..216955826 100644 --- a/docs/quickstart/CMakeLists.txt +++ b/docs/quickstart/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/hybrid/CMakeLists.txt b/docs/quickstart/hybrid/CMakeLists.txt index 2a105988d..c7a6eb862 100644 --- a/docs/quickstart/hybrid/CMakeLists.txt +++ b/docs/quickstart/hybrid/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py b/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py index c39b866e4..60d48d0ef 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/_version.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt index 5936267e3..a53462b00 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/common/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt index 12b24787c..7cd4e0ce8 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/ex00_wrap_data_objects/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt b/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt index 0f42b7c21..6b3b429a2 100644 --- a/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt +++ b/docs/quickstart/hybrid/mrc_qs_hybrid/ex01_wrap_nodes/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/python/CMakeLists.txt b/docs/quickstart/python/CMakeLists.txt index c08024524..93751c001 100644 --- a/docs/quickstart/python/CMakeLists.txt +++ b/docs/quickstart/python/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/docs/quickstart/python/mrc_qs_python/_version.py b/docs/quickstart/python/mrc_qs_python/_version.py index 94e5ba7f0..1ca6b055c 100644 --- a/docs/quickstart/python/mrc_qs_python/_version.py +++ b/docs/quickstart/python/mrc_qs_python/_version.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/protos/CMakeLists.txt b/protos/CMakeLists.txt index e281a8d53..93a538f88 100644 --- a/protos/CMakeLists.txt +++ b/protos/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 8d52aa8d5..e9b846a36 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/mrc/_pymrc/CMakeLists.txt b/python/mrc/_pymrc/CMakeLists.txt index 3acd9fe57..b2d6de068 100644 --- a/python/mrc/_pymrc/CMakeLists.txt +++ b/python/mrc/_pymrc/CMakeLists.txt @@ -1,5 +1,5 @@ # ============================================================================= -# Copyright (c) 2020-2022, NVIDIA CORPORATION. +# Copyright (c) 2020-2023, 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 diff --git a/python/mrc/_pymrc/include/pymrc/tracers.hpp b/python/mrc/_pymrc/include/pymrc/tracers.hpp index cd5603349..cc63eb6a9 100644 --- a/python/mrc/_pymrc/include/pymrc/tracers.hpp +++ b/python/mrc/_pymrc/include/pymrc/tracers.hpp @@ -1,6 +1,19 @@ -// -// Created by drobison on 1/6/23. -// +/* + * SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + */ #pragma once diff --git a/python/mrc/_pymrc/include/pymrc/watchers.hpp b/python/mrc/_pymrc/include/pymrc/watchers.hpp index 16473d646..d3507e44b 100644 --- a/python/mrc/_pymrc/include/pymrc/watchers.hpp +++ b/python/mrc/_pymrc/include/pymrc/watchers.hpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/mrc/_pymrc/src/tracers.cpp b/python/mrc/_pymrc/src/tracers.cpp index 7e02c0209..5956b749d 100644 --- a/python/mrc/_pymrc/src/tracers.cpp +++ b/python/mrc/_pymrc/src/tracers.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/mrc/benchmarking/CMakeLists.txt b/python/mrc/benchmarking/CMakeLists.txt index ea348a53a..d98203c40 100644 --- a/python/mrc/benchmarking/CMakeLists.txt +++ b/python/mrc/benchmarking/CMakeLists.txt @@ -1,5 +1,5 @@ # ============================================================================= -# Copyright (c) 2020-2022, NVIDIA CORPORATION. +# Copyright (c) 2020-2023, 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 diff --git a/python/mrc/benchmarking/__init__.py b/python/mrc/benchmarking/__init__.py index a5bb7cf8a..5ba5f7b6f 100644 --- a/python/mrc/benchmarking/__init__.py +++ b/python/mrc/benchmarking/__init__.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright (c) 2018-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. +from .watchers import LatencyWatcher +from .watchers import ThroughputWatcher from .watchers import get_tracing_stats from .watchers import reset_tracing_stats from .watchers import sync_tracing_state from .watchers import trace_channels from .watchers import trace_operators -from .watchers import LatencyWatcher -from .watchers import ThroughputWatcher diff --git a/python/mrc/benchmarking/tracers.cpp b/python/mrc/benchmarking/tracers.cpp index abf75bf86..c3c6210e9 100644 --- a/python/mrc/benchmarking/tracers.cpp +++ b/python/mrc/benchmarking/tracers.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/mrc/benchmarking/watchers.cpp b/python/mrc/benchmarking/watchers.cpp index 88a9d26ae..9bbcf6671 100644 --- a/python/mrc/benchmarking/watchers.cpp +++ b/python/mrc/benchmarking/watchers.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/mrc/tests/CMakeLists.txt b/python/mrc/tests/CMakeLists.txt index b712a888e..826628337 100644 --- a/python/mrc/tests/CMakeLists.txt +++ b/python/mrc/tests/CMakeLists.txt @@ -1,5 +1,5 @@ # ============================================================================= -# SPDX-FileCopyrightText: Copyright (c) 2020-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except diff --git a/python/mrc/tests/test_edges.cpp b/python/mrc/tests/test_edges.cpp index 1b13604eb..9353a4043 100644 --- a/python/mrc/tests/test_edges.cpp +++ b/python/mrc/tests/test_edges.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); From 20e58c306a8d835473b5f3d86a6e355649fbf492 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 9 Jan 2023 10:56:06 -0700 Subject: [PATCH 43/55] Testing changes to fix CI --- ci/conda/recipes/libmrc/build.sh | 3 +++ ci/scripts/github/common.sh | 2 ++ 2 files changed, 5 insertions(+) diff --git a/ci/conda/recipes/libmrc/build.sh b/ci/conda/recipes/libmrc/build.sh index e6f0582e4..da1e05a1a 100644 --- a/ci/conda/recipes/libmrc/build.sh +++ b/ci/conda/recipes/libmrc/build.sh @@ -87,6 +87,9 @@ fi echo "PYTHON: ${PYTHON}" echo "which python: $(which python)" +git submodule init +git submodule update + # Run configure cmake -B ${BUILD_DIR} \ ${CMAKE_ARGS} \ diff --git a/ci/scripts/github/common.sh b/ci/scripts/github/common.sh index 4da5afab6..c969bddc3 100644 --- a/ci/scripts/github/common.sh +++ b/ci/scripts/github/common.sh @@ -96,6 +96,8 @@ function fetch_base_branch() { # Change target is the branch name we are merging into but due to the weird way jenkins does # the checkout it isn't recognized by git without the origin/ prefix export CHANGE_TARGET="origin/${BASE_BRANCH}" + git submodule init + git submodule update rapids-logger "Base branch: ${BASE_BRANCH}" } From ab41b44cfa6dfad4971c356d4a5c55df778c924f Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 9 Jan 2023 11:12:37 -0700 Subject: [PATCH 44/55] CI testing --- ci/scripts/github/checks.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/scripts/github/checks.sh b/ci/scripts/github/checks.sh index 65ee64ff4..6792c90fb 100755 --- a/ci/scripts/github/checks.sh +++ b/ci/scripts/github/checks.sh @@ -23,6 +23,8 @@ fetch_base_branch update_conda_env rapids-logger "Configuring CMake" +git submodule init +git submodule update cmake -B build -G Ninja ${CMAKE_BUILD_ALL_FEATURES} . rapids-logger "Building targets that generate source code" From 8b916542bf63ef8de7a5d77871185ad681b2a364 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 9 Jan 2023 11:33:50 -0700 Subject: [PATCH 45/55] Formatting and CI updates --- ci/scripts/github/checks.sh | 2 +- ci/scripts/github/common.sh | 2 +- .../tests/modules/test_segment_modules.cpp | 696 +++++++++--------- python/mrc/_pymrc/include/pymrc/tracers.hpp | 4 +- python/mrc/_pymrc/include/pymrc/watchers.hpp | 99 +-- python/mrc/_pymrc/src/watchers.cpp | 131 ++-- 6 files changed, 454 insertions(+), 480 deletions(-) diff --git a/ci/scripts/github/checks.sh b/ci/scripts/github/checks.sh index 6792c90fb..5d3f01c40 100755 --- a/ci/scripts/github/checks.sh +++ b/ci/scripts/github/checks.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ci/scripts/github/common.sh b/ci/scripts/github/common.sh index c969bddc3..fae327469 100644 --- a/ci/scripts/github/common.sh +++ b/ci/scripts/github/common.sh @@ -1,5 +1,5 @@ #!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/cpp/mrc/tests/modules/test_segment_modules.cpp b/cpp/mrc/tests/modules/test_segment_modules.cpp index 7bea2fd29..333ce90ff 100644 --- a/cpp/mrc/tests/modules/test_segment_modules.cpp +++ b/cpp/mrc/tests/modules/test_segment_modules.cpp @@ -44,435 +44,423 @@ namespace mrc { -TEST_F(TestSegmentModules, ModuleConstructorTest) -{ - using namespace modules; + TEST_F(TestSegmentModules, ModuleConstructorTest) { + using namespace modules; - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); - config_2["config_key_1"] = true; - - auto mod1 = SimpleModule("InitModuleTest_mod1"); - auto mod2 = ConfigurableModule("InitModuleTest_2"); - auto mod3 = ConfigurableModule("InitModuleTest_3", config_1); - auto mod4 = ConfigurableModule("InitModuleTest_4", config_2); + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); + config_2["config_key_1"] = true; - ASSERT_EQ(mod4.config().contains("config_key_1"), true); + auto mod1 = SimpleModule("InitModuleTest_mod1"); + auto mod2 = ConfigurableModule("InitModuleTest_2"); + auto mod3 = ConfigurableModule("InitModuleTest_3", config_1); + auto mod4 = ConfigurableModule("InitModuleTest_4", config_2); + + ASSERT_EQ(mod4.config().contains("config_key_1"), true); + + ASSERT_THROW(SimpleModule("bad/module/name"), std::invalid_argument); + } + + TEST_F(TestSegmentModules, ModuleInitializationTest) { + using namespace modules; + + auto init_wrapper = [](segment::Builder &builder) { + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); + config_2["config_key_1"] = true; + + auto simple_mod = builder.make_module("ModuleInitializationTest_mod1"); + auto configurable_1_mod = builder.make_module("ModuleInitializationTest_mod2", + config_1); + auto configurable_2_mod = builder.make_module("ModuleInitializationTest_mod3", + config_2); + auto configurable_mod_3 = ConfigurableModule("ModuleInitializationTest_mod4", config_2); + + configurable_mod_3(builder); + + EXPECT_EQ(simple_mod->input_ids().size(), 2); + EXPECT_EQ(simple_mod->output_ids().size(), 2); + EXPECT_EQ(simple_mod->input_ports().size(), 2); + EXPECT_EQ(simple_mod->output_ports().size(), 2); + EXPECT_EQ(simple_mod->input_ports().find("input1") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->input_ports().find("input2") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->input_port_type_id("input1"), typeid(bool)); + EXPECT_EQ(simple_mod->input_port_type_id("input2"), typeid(bool)); + EXPECT_EQ(simple_mod->input_port_type_ids().find("input1")->second, typeid(bool)); + EXPECT_EQ(simple_mod->input_port_type_ids().find("input2")->second, typeid(bool)); + EXPECT_EQ(simple_mod->output_ports().find("output1") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->output_ports().find("output2") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->output_port_type_id("output1"), typeid(std::string)); + EXPECT_EQ(simple_mod->output_port_type_id("output2"), typeid(std::string)); + EXPECT_EQ(simple_mod->output_port_type_ids().find("output1")->second, typeid(std::string)); + EXPECT_EQ(simple_mod->output_port_type_ids().find("output2")->second, typeid(std::string)); + + EXPECT_THROW(simple_mod->input_port("DOES_NOT_EXIST"), std::invalid_argument); + EXPECT_THROW(simple_mod->output_port("DOES_NOT_EXIST"), std::invalid_argument); + EXPECT_THROW(simple_mod->input_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); + EXPECT_THROW(simple_mod->output_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); + + EXPECT_EQ(configurable_1_mod->input_ports().size(), 1); + EXPECT_EQ(configurable_1_mod->output_ports().size(), 1); + EXPECT_EQ(configurable_1_mod->m_was_configured, false); + + EXPECT_EQ(configurable_2_mod->input_ports().size(), 1); + EXPECT_EQ(configurable_2_mod->output_ports().size(), 1); + EXPECT_EQ(configurable_2_mod->m_was_configured, true); + }; + + m_pipeline->make_segment("Initialization_Segment", init_wrapper); + + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); + + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.stop(); + executor.join(); + } + + TEST_F(TestSegmentModules, ModuleEndToEndTest) { + using namespace modules; + unsigned int packets_1{0}; + unsigned int packets_2{0}; + unsigned int packets_3{0}; + + auto init_wrapper = [&packets_1, &packets_2, &packets_3](segment::Builder &builder) { + auto simple_mod = builder.make_module("ModuleEndToEndTest_mod1"); + auto configurable_mod = builder.make_module("ModuleEndToEndTest_mod2"); + + auto source1 = builder.make_source("src1", [](rxcpp::subscriber &sub) { + if (sub.is_subscribed()) { + sub.on_next(true); + sub.on_next(false); + sub.on_next(true); + sub.on_next(true); + } - ASSERT_THROW(SimpleModule("bad/module/name"), std::invalid_argument); -} + sub.on_completed(); + }); -TEST_F(TestSegmentModules, ModuleInitializationTest) -{ - using namespace modules; + // Ex1. Partially dynamic edge construction + builder.make_edge(source1, simple_mod->input_port("input1")); - auto init_wrapper = [](segment::Builder& builder) { - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); - config_2["config_key_1"] = true; + auto source2 = builder.make_source("src2", [](rxcpp::subscriber &sub) { + if (sub.is_subscribed()) { + sub.on_next(true); + sub.on_next(false); + sub.on_next(false); + sub.on_next(false); + sub.on_next(true); + sub.on_next(false); + } - auto simple_mod = builder.make_module("ModuleInitializationTest_mod1"); - auto configurable_1_mod = builder.make_module("ModuleInitializationTest_mod2", config_1); - auto configurable_2_mod = builder.make_module("ModuleInitializationTest_mod3", config_2); - auto configurable_mod_3 = ConfigurableModule("ModuleInitializationTest_mod4", config_2); - - configurable_mod_3(builder); - - EXPECT_EQ(simple_mod->input_ids().size(), 2); - EXPECT_EQ(simple_mod->output_ids().size(), 2); - EXPECT_EQ(simple_mod->input_ports().size(), 2); - EXPECT_EQ(simple_mod->output_ports().size(), 2); - EXPECT_EQ(simple_mod->input_ports().find("input1") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->input_ports().find("input2") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->input_port_type_id("input1"), typeid(bool)); - EXPECT_EQ(simple_mod->input_port_type_id("input2"), typeid(bool)); - EXPECT_EQ(simple_mod->input_port_type_ids().find("input1")->second, typeid(bool)); - EXPECT_EQ(simple_mod->input_port_type_ids().find("input2")->second, typeid(bool)); - EXPECT_EQ(simple_mod->output_ports().find("output1") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->output_ports().find("output2") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->output_port_type_id("output1"), typeid(std::string)); - EXPECT_EQ(simple_mod->output_port_type_id("output2"), typeid(std::string)); - EXPECT_EQ(simple_mod->output_port_type_ids().find("output1")->second, typeid(std::string)); - EXPECT_EQ(simple_mod->output_port_type_ids().find("output2")->second, typeid(std::string)); - - EXPECT_THROW(simple_mod->input_port("DOES_NOT_EXIST"), std::invalid_argument); - EXPECT_THROW(simple_mod->output_port("DOES_NOT_EXIST"), std::invalid_argument); - EXPECT_THROW(simple_mod->input_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); - EXPECT_THROW(simple_mod->output_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); - - EXPECT_EQ(configurable_1_mod->input_ports().size(), 1); - EXPECT_EQ(configurable_1_mod->output_ports().size(), 1); - EXPECT_EQ(configurable_1_mod->m_was_configured, false); - - EXPECT_EQ(configurable_2_mod->input_ports().size(), 1); - EXPECT_EQ(configurable_2_mod->output_ports().size(), 1); - EXPECT_EQ(configurable_2_mod->m_was_configured, true); - }; - - m_pipeline->make_segment("Initialization_Segment", init_wrapper); - - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); - - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.stop(); - executor.join(); -} - -TEST_F(TestSegmentModules, ModuleEndToEndTest) -{ - using namespace modules; - unsigned int packets_1{0}; - unsigned int packets_2{0}; - unsigned int packets_3{0}; - - auto init_wrapper = [&packets_1, &packets_2, &packets_3](segment::Builder& builder) { - auto simple_mod = builder.make_module("ModuleEndToEndTest_mod1"); - auto configurable_mod = builder.make_module("ModuleEndToEndTest_mod2"); - - auto source1 = builder.make_source("src1", [](rxcpp::subscriber& sub) { - if (sub.is_subscribed()) - { - sub.on_next(true); - sub.on_next(false); - sub.on_next(true); - sub.on_next(true); - } - - sub.on_completed(); - }); - - // Ex1. Partially dynamic edge construction - builder.make_edge(source1, simple_mod->input_port("input1")); - - auto source2 = builder.make_source("src2", [](rxcpp::subscriber& sub) { - if (sub.is_subscribed()) - { - sub.on_next(true); - sub.on_next(false); - sub.on_next(false); - sub.on_next(false); - sub.on_next(true); - sub.on_next(false); - } - - sub.on_completed(); - }); - - // Ex2. Dynamic edge construction -- requires type specification - builder.make_dynamic_edge(source2, simple_mod->input_port("input2")); - - auto sink1 = builder.make_sink("sink1", [&packets_1](std::string input) { - packets_1++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(simple_mod->output_port("output1"), sink1); - - auto sink2 = builder.make_sink("sink2", [&packets_2](std::string input) { - packets_2++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(simple_mod->output_port("output2"), sink2); - - auto source3 = builder.make_source("src3", [](rxcpp::subscriber& sub) { - if (sub.is_subscribed()) - { - sub.on_next(true); - sub.on_next(false); - sub.on_next(true); - sub.on_next(true); - } - - sub.on_completed(); - }); - - builder.make_edge(source3, configurable_mod->input_port("configurable_input_a")); - - auto sink3 = builder.make_sink("sink3", [&packets_3](std::string input) { - packets_3++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(configurable_mod->output_port("configurable_output_x"), sink3); - }; - - m_pipeline->make_segment("EndToEnd_Segment", init_wrapper); - - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); - - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); - - EXPECT_EQ(packets_1, 4); - EXPECT_EQ(packets_2, 6); - EXPECT_EQ(packets_3, 4); -} - -TEST_F(TestSegmentModules, ModuleAsSourceTest) -{ - using namespace modules; - - unsigned int packet_count{0}; - - auto init_wrapper = [&packet_count](segment::Builder& builder) { - auto config = nlohmann::json(); - unsigned int source_count{42}; - config["source_count"] = source_count; - - auto source_mod = builder.make_module("ModuleSourceTest_mod1", config); - - auto sink = builder.make_sink("sink", [&packet_count](bool input) { - packet_count++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(source_mod->output_port("source"), sink); - }; + sub.on_completed(); + }); - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + // Ex2. Dynamic edge construction -- requires type specification + builder.make_dynamic_edge(source2, simple_mod->input_port("input2")); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto sink1 = builder.make_sink("sink1", [&packets_1](std::string input) { + packets_1++; + VLOG(10) << "Sinking " << input << std::endl; + }); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); - - EXPECT_EQ(packet_count, 42); -} + builder.make_edge(simple_mod->output_port("output1"), sink1); -TEST_F(TestSegmentModules, ModuleAsSinkTest) -{ - using namespace modules; + auto sink2 = builder.make_sink("sink2", [&packets_2](std::string input) { + packets_2++; + VLOG(10) << "Sinking " << input << std::endl; + }); - unsigned int packet_count{0}; + builder.make_edge(simple_mod->output_port("output2"), sink2); - auto init_wrapper = [&packet_count](segment::Builder& builder) { - auto source = builder.make_source("source", [&packet_count](rxcpp::subscriber& sub) { - if (sub.is_subscribed()) - { - for (unsigned int i = 0; i < 43; ++i) - { + auto source3 = builder.make_source("src3", [](rxcpp::subscriber &sub) { + if (sub.is_subscribed()) { + sub.on_next(true); + sub.on_next(false); + sub.on_next(true); sub.on_next(true); - packet_count++; } - } - sub.on_completed(); - }); + sub.on_completed(); + }); + + builder.make_edge(source3, configurable_mod->input_port("configurable_input_a")); - auto sink_mod = builder.make_module("ModuleSinkTest_mod1"); + auto sink3 = builder.make_sink("sink3", [&packets_3](std::string input) { + packets_3++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source, sink_mod->input_port("sink")); - }; + builder.make_edge(configurable_mod->output_port("configurable_output_x"), sink3); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("EndToEnd_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(packet_count, 43); -} + EXPECT_EQ(packets_1, 4); + EXPECT_EQ(packets_2, 6); + EXPECT_EQ(packets_3, 4); + } -TEST_F(TestSegmentModules, ModuleChainingTest) -{ - using namespace modules; + TEST_F(TestSegmentModules, ModuleAsSourceTest) { + using namespace modules; - auto sink_mod = std::make_shared("ModuleChainingTest_mod2"); - auto init_wrapper = [&sink_mod](segment::Builder& builder) { - auto config = nlohmann::json(); - unsigned int source_count{42}; - config["source_count"] = source_count; + unsigned int packet_count{0}; - auto source_mod = builder.make_module("ModuleChainingTest_mod1", config); - builder.init_module(sink_mod); + auto init_wrapper = [&packet_count](segment::Builder &builder) { + auto config = nlohmann::json(); + unsigned int source_count{42}; + config["source_count"] = source_count; - builder.make_dynamic_edge(source_mod->output_port("source"), sink_mod->input_port("sink")); - }; + auto source_mod = builder.make_module("ModuleSourceTest_mod1", config); - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + auto sink = builder.make_sink("sink", [&packet_count](bool input) { + packet_count++; + VLOG(10) << "Sinking " << input << std::endl; + }); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + builder.make_edge(source_mod->output_port("source"), sink); + }; - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - EXPECT_EQ(sink_mod->m_packet_count, 42); -} + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); -TEST_F(TestSegmentModules, ModuleNestingTest) -{ - using namespace modules; + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - unsigned int packet_count{0}; + EXPECT_EQ(packet_count, 42); + } - auto init_wrapper = [&packet_count](segment::Builder& builder) { - auto nested_mod = builder.make_module("ModuleNestingTest_mod1"); + TEST_F(TestSegmentModules, ModuleAsSinkTest) { + using namespace modules; - auto nested_sink = builder.make_sink("nested_sink", [&packet_count](std::string input) { - packet_count++; - VLOG(10) << "Sinking " << input << std::endl; - }); + unsigned int packet_count{0}; - builder.make_edge(nested_mod->output_port("nested_module_output"), nested_sink); - }; + auto init_wrapper = [&packet_count](segment::Builder &builder) { + auto source = builder.make_source("source", [&packet_count](rxcpp::subscriber &sub) { + if (sub.is_subscribed()) { + for (unsigned int i = 0; i < 43; ++i) { + sub.on_next(true); + packet_count++; + } + } - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + sub.on_completed(); + }); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto sink_mod = builder.make_module("ModuleSinkTest_mod1"); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + builder.make_edge(source, sink_mod->input_port("sink")); + }; - EXPECT_EQ(packet_count, 4); -} + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); -TEST_F(TestSegmentModules, ModuleTemplateTest) -{ - using namespace modules; + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - unsigned int packet_count_1{0}; - unsigned int packet_count_2{0}; + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder& builder) { - using data_type_1_t = int; - using data_type_2_t = std::string; + EXPECT_EQ(packet_count, 43); + } - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); + TEST_F(TestSegmentModules, ModuleChainingTest) { + using namespace modules; + + auto sink_mod = std::make_shared("ModuleChainingTest_mod2"); + auto init_wrapper = [&sink_mod](segment::Builder &builder) { + auto config = nlohmann::json(); + unsigned int source_count{42}; + config["source_count"] = source_count; + + auto source_mod = builder.make_module("ModuleChainingTest_mod1", config); + builder.init_module(sink_mod); - unsigned int source_count_1{42}; - unsigned int source_count_2{24}; + builder.make_dynamic_edge(source_mod->output_port("source"), sink_mod->input_port("sink")); + }; - config_1["source_count"] = source_count_1; - config_2["source_count"] = source_count_2; + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto source_1_mod = builder.make_module>("ModuleTemplateTest_mod1", config_1); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { - packet_count_1++; - VLOG(10) << "Sinking " << input << std::endl; - }); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - builder.make_edge(source_1_mod->output_port("source"), sink_1); + EXPECT_EQ(sink_mod->m_packet_count, 42); + } - auto source_2_mod = builder.make_module>("ModuleTemplateTest_mod2", config_2); + TEST_F(TestSegmentModules, ModuleNestingTest) { + using namespace modules; - auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { - packet_count_2++; - VLOG(10) << "Sinking " << input << std::endl; - }); + unsigned int packet_count{0}; - builder.make_edge(source_2_mod->output_port("source"), sink_2); - }; + auto init_wrapper = [&packet_count](segment::Builder &builder) { + auto nested_mod = builder.make_module("ModuleNestingTest_mod1"); - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + auto nested_sink = builder.make_sink("nested_sink", [&packet_count](std::string input) { + packet_count++; + VLOG(10) << "Sinking " << input << std::endl; + }); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + builder.make_edge(nested_mod->output_port("nested_module_output"), nested_sink); + }; - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - EXPECT_EQ(packet_count_1, 42); - EXPECT_EQ(packet_count_2, 24); -} + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); + + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); + + EXPECT_EQ(packet_count, 4); + } + + TEST_F(TestSegmentModules, ModuleTemplateTest) { + using namespace modules; + + unsigned int packet_count_1{0}; + unsigned int packet_count_2{0}; + + auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder &builder) { + using data_type_1_t = int; + using data_type_2_t = std::string; + + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); + + unsigned int source_count_1{42}; + unsigned int source_count_2{24}; + + config_1["source_count"] = source_count_1; + config_2["source_count"] = source_count_2; + + auto source_1_mod = builder.make_module>("ModuleTemplateTest_mod1", config_1); + + auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { + packet_count_1++; + VLOG(10) << "Sinking " << input << std::endl; + }); + + builder.make_edge(source_1_mod->output_port("source"), sink_1); + + auto source_2_mod = builder.make_module>("ModuleTemplateTest_mod2", config_2); + + auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { + packet_count_2++; + VLOG(10) << "Sinking " << input << std::endl; + }); + + builder.make_edge(source_2_mod->output_port("source"), sink_2); + }; + + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); + + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); + + EXPECT_EQ(packet_count_1, 42); + EXPECT_EQ(packet_count_2, 24); + } #if !defined(__clang__) && defined(__GNUC__) // Work around for GCC : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83258 -#pragma GCC visibility push(default) -auto F_1 = []() -> int { return 15; }; -auto F_2 = []() -> std::string { return "test string"; }; -#pragma GCC visibility pop + #pragma GCC visibility push(default) + auto F_1 = []() -> int { return 15; }; + auto F_2 = []() -> std::string { return "test string"; }; + #pragma GCC visibility pop #endif -TEST_F(TestSegmentModules, ModuleTemplateWithInitTest) -{ - using namespace modules; + TEST_F(TestSegmentModules, ModuleTemplateWithInitTest) { + using namespace modules; - unsigned int packet_count_1{0}; - unsigned int packet_count_2{0}; + unsigned int packet_count_1{0}; + unsigned int packet_count_2{0}; - auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder& builder) { - using data_type_1_t = int; - using data_type_2_t = std::string; + auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder &builder) { + using data_type_1_t = int; + using data_type_2_t = std::string; - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); - unsigned int source_count_1{42}; - unsigned int source_count_2{24}; + unsigned int source_count_1{42}; + unsigned int source_count_2{24}; - config_1["source_count"] = source_count_1; - config_2["source_count"] = source_count_2; + config_1["source_count"] = source_count_1; + config_2["source_count"] = source_count_2; #if defined(__clang__) - auto F_1 = []() -> int { return 15; }; - auto F_2 = []() -> std::string { return "test string"; }; + auto F_1 = []() -> int { return 15; }; + auto F_2 = []() -> std::string { return "test string"; }; #endif - auto source_1_mod = builder.make_module>( - "ModuleTemplateWithInitTest_mod1", config_1); + auto source_1_mod = builder.make_module>( + "ModuleTemplateWithInitTest_mod1", config_1); - auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { - assert(input == 15); - packet_count_1++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { + assert(input == 15); + packet_count_1++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source_1_mod->output_port("source"), sink_1); + builder.make_edge(source_1_mod->output_port("source"), sink_1); - auto source_2_mod = builder.make_module>( - "ModuleTemplateWithInitTest_mod2", config_2); + auto source_2_mod = builder.make_module>( + "ModuleTemplateWithInitTest_mod2", config_2); - auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { - assert(input == "test string"); - packet_count_2++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { + assert(input == "test string"); + packet_count_2++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source_2_mod->output_port("source"), sink_2); - }; + builder.make_edge(source_2_mod->output_port("source"), sink_2); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(packet_count_1, 42); - EXPECT_EQ(packet_count_2, 24); -} + EXPECT_EQ(packet_count_1, 42); + EXPECT_EQ(packet_count_2, 24); + } } // namespace mrc diff --git a/python/mrc/_pymrc/include/pymrc/tracers.hpp b/python/mrc/_pymrc/include/pymrc/tracers.hpp index cc63eb6a9..84eddd87d 100644 --- a/python/mrc/_pymrc/include/pymrc/tracers.hpp +++ b/python/mrc/_pymrc/include/pymrc/tracers.hpp @@ -22,6 +22,6 @@ #include // for object, dict namespace mrc::pymrc { - using latency_tracer_t = mrc::benchmarking::TracerEnsemble; - using throughput_tracer_t = mrc::benchmarking::TracerEnsemble; +using latency_tracer_t = mrc::benchmarking::TracerEnsemble; +using throughput_tracer_t = mrc::benchmarking::TracerEnsemble; } diff --git a/python/mrc/_pymrc/include/pymrc/watchers.hpp b/python/mrc/_pymrc/include/pymrc/watchers.hpp index d3507e44b..4f0464228 100644 --- a/python/mrc/_pymrc/include/pymrc/watchers.hpp +++ b/python/mrc/_pymrc/include/pymrc/watchers.hpp @@ -18,6 +18,7 @@ #pragma once #include "pymrc/tracers.hpp" + #include "mrc/benchmarking/segment_watcher.hpp" #include // for object, dict @@ -27,13 +28,13 @@ #include namespace mrc::segment { - class Builder; +class Builder; - struct ObjectProperties; +struct ObjectProperties; } // namespace mrc::segment namespace mrc::pymrc { - class Executor; +class Executor; } namespace mrc::pymrc { @@ -41,69 +42,69 @@ namespace mrc::pymrc { // Export everything in the mrc::pymrc namespace by default since we compile with -fvisibility=hidden #pragma GCC visibility push(default) - using latency_ensemble_t = mrc::benchmarking::TracerEnsemble; - using latency_watcher_t = mrc::benchmarking::SegmentWatcher; +using latency_ensemble_t = mrc::benchmarking::TracerEnsemble; +using latency_watcher_t = mrc::benchmarking::SegmentWatcher; - using throughput_ensemble_t = mrc::benchmarking::TracerEnsemble; - using throughput_watcher_t = mrc::benchmarking::SegmentWatcher; +using throughput_ensemble_t = mrc::benchmarking::TracerEnsemble; +using throughput_watcher_t = mrc::benchmarking::SegmentWatcher; - class LatencyWatcher : public latency_watcher_t { - public: - LatencyWatcher(std::shared_ptr executor); +class LatencyWatcher : public latency_watcher_t { +public: + LatencyWatcher(std::shared_ptr executor); - LatencyWatcher(std::shared_ptr executor, - std::function payload_init); + LatencyWatcher(std::shared_ptr executor, + std::function payload_init); - void make_segment(const std::string &name, - const std::function &init); + void make_segment(const std::string &name, + const std::function &init); - std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, - const std::string &name, - bool force_sequential = false); + std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, + const std::string &name, + bool force_sequential = false); - std::shared_ptr make_traced_node( - mrc::segment::Builder &seg, - const std::string &name, - std::function map_f); + std::shared_ptr make_traced_node( + mrc::segment::Builder &seg, + const std::string &name, + std::function map_f); - std::shared_ptr make_tracer_sink( - mrc::segment::Builder &seg, const std::string &name, - std::function sink_f); + std::shared_ptr make_tracer_sink( + mrc::segment::Builder &seg, const std::string &name, + std::function sink_f); - pybind11::dict aggregate_tracers_as_pydict(); + pybind11::dict aggregate_tracers_as_pydict(); - private: - std::shared_ptr m_executor; - }; +private: + std::shared_ptr m_executor; +}; - class ThroughputWatcher : public throughput_watcher_t { - public: - ThroughputWatcher(std::shared_ptr executor); +class ThroughputWatcher : public throughput_watcher_t { +public: + ThroughputWatcher(std::shared_ptr executor); - ThroughputWatcher(std::shared_ptr executor, - std::function payload_init); + ThroughputWatcher(std::shared_ptr executor, + std::function payload_init); - void make_segment(const std::string &name, - const std::function &init); + void make_segment(const std::string &name, + const std::function &init); - std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, - const std::string &name, - bool force_sequential = false); + std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, + const std::string &name, + bool force_sequential = false); - std::shared_ptr make_traced_node( - mrc::segment::Builder &seg, - const std::string &name, - std::function map_f); + std::shared_ptr make_traced_node( + mrc::segment::Builder &seg, + const std::string &name, + std::function map_f); - std::shared_ptr make_tracer_sink( - mrc::segment::Builder &seg, const std::string &name, - std::function sink_f); + std::shared_ptr make_tracer_sink( + mrc::segment::Builder &seg, const std::string &name, + std::function sink_f); - pybind11::dict aggregate_tracers_as_pydict(); + pybind11::dict aggregate_tracers_as_pydict(); - private: - std::shared_ptr m_executor; - }; +private: + std::shared_ptr m_executor; +}; #pragma GCC visibility pop } // namespace mrc::pymrc diff --git a/python/mrc/_pymrc/src/watchers.cpp b/python/mrc/_pymrc/src/watchers.cpp index c5b406747..63285a169 100644 --- a/python/mrc/_pymrc/src/watchers.cpp +++ b/python/mrc/_pymrc/src/watchers.cpp @@ -44,10 +44,9 @@ namespace mrc::pymrc { namespace py = pybind11; LatencyWatcher::LatencyWatcher(std::shared_ptr executor) : - latency_watcher_t(executor->get_executor()), - m_executor(executor) -{ - auto payload_initializer = [](latency_ensemble_t& latency_ensemble) { + latency_watcher_t(executor->get_executor()), + m_executor(executor) { + auto payload_initializer = [](latency_ensemble_t &latency_ensemble) { py::gil_scoped_acquire gil; latency_ensemble = py::none(); }; @@ -56,30 +55,26 @@ LatencyWatcher::LatencyWatcher(std::shared_ptr executor) : } LatencyWatcher::LatencyWatcher(std::shared_ptr executor, - std::function payload_init) : - latency_watcher_t(executor->get_executor(), payload_init), - m_executor(executor) -{} - -void LatencyWatcher::make_segment(const std::string& name, - const std::function& init) -{ + std::function payload_init) : + latency_watcher_t(executor->get_executor(), payload_init), + m_executor(executor) {} + +void LatencyWatcher::make_segment(const std::string &name, + const std::function &init) { pymrc::Pipeline pipeline; - auto tracer_init_wrapper = [this, init](mrc::segment::Builder& seg) { init(seg, *this); }; + auto tracer_init_wrapper = [this, init](mrc::segment::Builder &seg) { init(seg, *this); }; pipeline.make_segment(name, tracer_init_wrapper); m_executor->register_pipeline(pipeline); } -std::shared_ptr LatencyWatcher::make_tracer_source(mrc::segment::Builder& seg, - const std::string& name, - bool force_sequential) -{ +std::shared_ptr LatencyWatcher::make_tracer_source(mrc::segment::Builder &seg, + const std::string &name, + bool force_sequential) { using data_type_t = std::shared_ptr; - if (force_sequential) - { + if (force_sequential) { return seg.make_source(name, this->create_rx_tracer_source(name)); } @@ -87,54 +82,50 @@ std::shared_ptr LatencyWatcher::make_tracer_sour } std::shared_ptr LatencyWatcher::make_traced_node( - mrc::segment::Builder& seg, const std::string& name, std::function map_f) -{ + mrc::segment::Builder &seg, const std::string &name, std::function map_f) { using data_type_t = std::shared_ptr; auto internal_idx = this->get_or_create_node_entry(name); auto trace_node = seg.make_node( - name, - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), - rxcpp::operators::map([map_f](data_type_t tracer) { - py::gil_scoped_acquire gil; - *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's + name, + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), + rxcpp::operators::map([map_f](data_type_t tracer) { + py::gil_scoped_acquire gil; + *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's - return tracer; - }), - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); + return tracer; + }), + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); return trace_node; // std::static_pointer_cast(trace_node); } std::shared_ptr LatencyWatcher::make_tracer_sink( - mrc::segment::Builder& seg, const std::string& name, std::function sink_f) -{ - using data_type_t = std::shared_ptr; - auto compound_sink_f = [sink_f](pymrc::latency_ensemble_t& data) { + mrc::segment::Builder &seg, const std::string &name, std::function sink_f) { + using data_type_t = std::shared_ptr; + auto compound_sink_f = [sink_f](pymrc::latency_ensemble_t &data) { py::gil_scoped_acquire gil; sink_f(data); }; auto tracer_sink_f = this->create_tracer_sink_lambda(name, compound_sink_f); - auto tracer_sink = seg.make_sink(name, tracer_sink_f); + auto tracer_sink = seg.make_sink(name, tracer_sink_f); return tracer_sink; } -py::dict LatencyWatcher::aggregate_tracers_as_pydict() -{ +py::dict LatencyWatcher::aggregate_tracers_as_pydict() { nlohmann::json j = latency_watcher_t::aggregate_tracers()->to_json(); return pymrc::cast_from_json(j); } ThroughputWatcher::ThroughputWatcher(std::shared_ptr executor) : - throughput_watcher_t(executor->get_executor()), - m_executor(executor) -{ + throughput_watcher_t(executor->get_executor()), + m_executor(executor) { using throughput_ensemble_t = - mrc::benchmarking::TracerEnsemble; + mrc::benchmarking::TracerEnsemble; - auto payload_initializer = [](throughput_ensemble_t& le) { + auto payload_initializer = [](throughput_ensemble_t &le) { py::gil_scoped_acquire gil; le = py::none(); }; @@ -143,30 +134,27 @@ ThroughputWatcher::ThroughputWatcher(std::shared_ptr executor) } ThroughputWatcher::ThroughputWatcher(std::shared_ptr executor, - std::function payload_init) : - throughput_watcher_t(executor->get_executor(), payload_init), - m_executor(executor) -{} - -void ThroughputWatcher::make_segment(const std::string& name, - const std::function& init) -{ + std::function payload_init) : + throughput_watcher_t(executor->get_executor(), payload_init), + m_executor(executor) {} + +void ThroughputWatcher::make_segment(const std::string &name, + const std::function &init) { pymrc::Pipeline pipeline; - auto tracer_init_wrapper = [this, init](mrc::segment::Builder& seg) { init(seg, *this); }; + auto tracer_init_wrapper = [this, init](mrc::segment::Builder &seg) { init(seg, *this); }; pipeline.make_segment(name, tracer_init_wrapper); m_executor->register_pipeline(pipeline); } -std::shared_ptr ThroughputWatcher::make_tracer_source(mrc::segment::Builder& seg, - const std::string& name, - bool force_sequential) -{ +std::shared_ptr ThroughputWatcher::make_tracer_source(mrc::segment::Builder &seg, + const std::string &name, + bool force_sequential) { using data_type_t = std::shared_ptr; - if (force_sequential) - { + if (force_sequential) { return seg.make_source(name, this->create_rx_tracer_source(name)); } @@ -174,41 +162,38 @@ std::shared_ptr ThroughputWatcher::make_tracer_s } std::shared_ptr ThroughputWatcher::make_traced_node( - mrc::segment::Builder& seg, const std::string& name, std::function map_f) -{ + mrc::segment::Builder &seg, const std::string &name, std::function map_f) { using data_type_t = std::shared_ptr; auto internal_idx = this->get_or_create_node_entry(name); auto trace_node = seg.make_node( - name, - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), - rxcpp::operators::map([map_f](data_type_t tracer) { - py::gil_scoped_acquire gil; - *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's + name, + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), + rxcpp::operators::map([map_f](data_type_t tracer) { + py::gil_scoped_acquire gil; + *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's - return tracer; - }), - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); + return tracer; + }), + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); return trace_node; } std::shared_ptr ThroughputWatcher::make_tracer_sink( - mrc::segment::Builder& seg, const std::string& name, std::function sink_f) -{ - using data_type_t = std::shared_ptr; - auto compound_sink_f = [sink_f](pymrc::throughput_ensemble_t& data) { + mrc::segment::Builder &seg, const std::string &name, std::function sink_f) { + using data_type_t = std::shared_ptr; + auto compound_sink_f = [sink_f](pymrc::throughput_ensemble_t &data) { py::gil_scoped_acquire gil; sink_f(data); }; auto tracer_sink_f = this->create_tracer_sink_lambda(name, compound_sink_f); - auto tracer_sink = seg.make_sink(name, tracer_sink_f); + auto tracer_sink = seg.make_sink(name, tracer_sink_f); return tracer_sink; } -py::dict ThroughputWatcher::aggregate_tracers_as_pydict() -{ +py::dict ThroughputWatcher::aggregate_tracers_as_pydict() { nlohmann::json j = throughput_watcher_t::aggregate_tracers()->to_json(); return pymrc::cast_from_json(j); From 8ed73f014a7fa1a05797754b84e63c851e1f7543 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Mon, 9 Jan 2023 11:56:04 -0700 Subject: [PATCH 46/55] CI testing --- ci/scripts/github/build.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/scripts/github/build.sh b/ci/scripts/github/build.sh index 9dab47bca..7e6db5e6a 100755 --- a/ci/scripts/github/build.sh +++ b/ci/scripts/github/build.sh @@ -48,6 +48,7 @@ fi show_conda_info rapids-logger "Configuring for build and test" +git submodule update --init --recursive cmake -B build -G Ninja ${CMAKE_FLAGS} . rapids-logger "Building MRC" From 111bc24677390b17027b76adfbefeb32b837d118 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 10 Jan 2023 15:33:38 -0700 Subject: [PATCH 47/55] Formatting fixes and CI updates --- ci/scripts/github/docs.sh | 2 +- ci/scripts/github/test.sh | 1 + .../tests/modules/test_segment_modules.cpp | 694 +++++++++--------- python/mrc/_pymrc/include/pymrc/tracers.hpp | 4 +- python/mrc/_pymrc/src/watchers.cpp | 2 +- python/mrc/benchmarking/watchers.cpp | 201 +++-- 6 files changed, 453 insertions(+), 451 deletions(-) diff --git a/ci/scripts/github/docs.sh b/ci/scripts/github/docs.sh index 8e8c78ee3..b98b22f5d 100755 --- a/ci/scripts/github/docs.sh +++ b/ci/scripts/github/docs.sh @@ -29,9 +29,9 @@ doxygen --version show_conda_info rapids-logger "Configuring for docs" +git submodule update --init --recursive cmake -B build -G Ninja ${CMAKE_BUILD_ALL_FEATURES} -DMRC_BUILD_DOCS=ON . - rapids-logger "Building docs" cmake --build build --target mrc_docs diff --git a/ci/scripts/github/test.sh b/ci/scripts/github/test.sh index 5cccec867..4cb5bdcf5 100755 --- a/ci/scripts/github/test.sh +++ b/ci/scripts/github/test.sh @@ -35,6 +35,7 @@ rapids-logger "Installing MRC" cmake -P ${MRC_ROOT}/build/cmake_install.cmake pip install ${MRC_ROOT}/build/python +git submodule update --init --recursive cmake -B build -G Ninja ${CMAKE_BUILD_ALL_FEATURES} . diff --git a/cpp/mrc/tests/modules/test_segment_modules.cpp b/cpp/mrc/tests/modules/test_segment_modules.cpp index 333ce90ff..187ce40d5 100644 --- a/cpp/mrc/tests/modules/test_segment_modules.cpp +++ b/cpp/mrc/tests/modules/test_segment_modules.cpp @@ -44,423 +44,435 @@ namespace mrc { - TEST_F(TestSegmentModules, ModuleConstructorTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleConstructorTest) +{ + using namespace modules; - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); - config_2["config_key_1"] = true; - - auto mod1 = SimpleModule("InitModuleTest_mod1"); - auto mod2 = ConfigurableModule("InitModuleTest_2"); - auto mod3 = ConfigurableModule("InitModuleTest_3", config_1); - auto mod4 = ConfigurableModule("InitModuleTest_4", config_2); - - ASSERT_EQ(mod4.config().contains("config_key_1"), true); - - ASSERT_THROW(SimpleModule("bad/module/name"), std::invalid_argument); - } - - TEST_F(TestSegmentModules, ModuleInitializationTest) { - using namespace modules; - - auto init_wrapper = [](segment::Builder &builder) { - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); - config_2["config_key_1"] = true; - - auto simple_mod = builder.make_module("ModuleInitializationTest_mod1"); - auto configurable_1_mod = builder.make_module("ModuleInitializationTest_mod2", - config_1); - auto configurable_2_mod = builder.make_module("ModuleInitializationTest_mod3", - config_2); - auto configurable_mod_3 = ConfigurableModule("ModuleInitializationTest_mod4", config_2); - - configurable_mod_3(builder); - - EXPECT_EQ(simple_mod->input_ids().size(), 2); - EXPECT_EQ(simple_mod->output_ids().size(), 2); - EXPECT_EQ(simple_mod->input_ports().size(), 2); - EXPECT_EQ(simple_mod->output_ports().size(), 2); - EXPECT_EQ(simple_mod->input_ports().find("input1") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->input_ports().find("input2") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->input_port_type_id("input1"), typeid(bool)); - EXPECT_EQ(simple_mod->input_port_type_id("input2"), typeid(bool)); - EXPECT_EQ(simple_mod->input_port_type_ids().find("input1")->second, typeid(bool)); - EXPECT_EQ(simple_mod->input_port_type_ids().find("input2")->second, typeid(bool)); - EXPECT_EQ(simple_mod->output_ports().find("output1") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->output_ports().find("output2") != simple_mod->input_ports().end(), true); - EXPECT_EQ(simple_mod->output_port_type_id("output1"), typeid(std::string)); - EXPECT_EQ(simple_mod->output_port_type_id("output2"), typeid(std::string)); - EXPECT_EQ(simple_mod->output_port_type_ids().find("output1")->second, typeid(std::string)); - EXPECT_EQ(simple_mod->output_port_type_ids().find("output2")->second, typeid(std::string)); - - EXPECT_THROW(simple_mod->input_port("DOES_NOT_EXIST"), std::invalid_argument); - EXPECT_THROW(simple_mod->output_port("DOES_NOT_EXIST"), std::invalid_argument); - EXPECT_THROW(simple_mod->input_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); - EXPECT_THROW(simple_mod->output_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); - - EXPECT_EQ(configurable_1_mod->input_ports().size(), 1); - EXPECT_EQ(configurable_1_mod->output_ports().size(), 1); - EXPECT_EQ(configurable_1_mod->m_was_configured, false); - - EXPECT_EQ(configurable_2_mod->input_ports().size(), 1); - EXPECT_EQ(configurable_2_mod->output_ports().size(), 1); - EXPECT_EQ(configurable_2_mod->m_was_configured, true); - }; - - m_pipeline->make_segment("Initialization_Segment", init_wrapper); - - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); - - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.stop(); - executor.join(); - } - - TEST_F(TestSegmentModules, ModuleEndToEndTest) { - using namespace modules; - unsigned int packets_1{0}; - unsigned int packets_2{0}; - unsigned int packets_3{0}; - - auto init_wrapper = [&packets_1, &packets_2, &packets_3](segment::Builder &builder) { - auto simple_mod = builder.make_module("ModuleEndToEndTest_mod1"); - auto configurable_mod = builder.make_module("ModuleEndToEndTest_mod2"); - - auto source1 = builder.make_source("src1", [](rxcpp::subscriber &sub) { - if (sub.is_subscribed()) { - sub.on_next(true); - sub.on_next(false); - sub.on_next(true); - sub.on_next(true); - } - - sub.on_completed(); - }); - - // Ex1. Partially dynamic edge construction - builder.make_edge(source1, simple_mod->input_port("input1")); - - auto source2 = builder.make_source("src2", [](rxcpp::subscriber &sub) { - if (sub.is_subscribed()) { - sub.on_next(true); - sub.on_next(false); - sub.on_next(false); - sub.on_next(false); - sub.on_next(true); - sub.on_next(false); - } - - sub.on_completed(); - }); - - // Ex2. Dynamic edge construction -- requires type specification - builder.make_dynamic_edge(source2, simple_mod->input_port("input2")); - - auto sink1 = builder.make_sink("sink1", [&packets_1](std::string input) { - packets_1++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(simple_mod->output_port("output1"), sink1); - - auto sink2 = builder.make_sink("sink2", [&packets_2](std::string input) { - packets_2++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(simple_mod->output_port("output2"), sink2); + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); + config_2["config_key_1"] = true; - auto source3 = builder.make_source("src3", [](rxcpp::subscriber &sub) { - if (sub.is_subscribed()) { - sub.on_next(true); - sub.on_next(false); - sub.on_next(true); - sub.on_next(true); - } - - sub.on_completed(); - }); - - builder.make_edge(source3, configurable_mod->input_port("configurable_input_a")); - - auto sink3 = builder.make_sink("sink3", [&packets_3](std::string input) { - packets_3++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(configurable_mod->output_port("configurable_output_x"), sink3); - }; - - m_pipeline->make_segment("EndToEnd_Segment", init_wrapper); - - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto mod1 = SimpleModule("InitModuleTest_mod1"); + auto mod2 = ConfigurableModule("InitModuleTest_2"); + auto mod3 = ConfigurableModule("InitModuleTest_3", config_1); + auto mod4 = ConfigurableModule("InitModuleTest_4", config_2); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + ASSERT_EQ(mod4.config().contains("config_key_1"), true); - EXPECT_EQ(packets_1, 4); - EXPECT_EQ(packets_2, 6); - EXPECT_EQ(packets_3, 4); - } + ASSERT_THROW(SimpleModule("bad/module/name"), std::invalid_argument); +} - TEST_F(TestSegmentModules, ModuleAsSourceTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleInitializationTest) +{ + using namespace modules; - unsigned int packet_count{0}; - - auto init_wrapper = [&packet_count](segment::Builder &builder) { - auto config = nlohmann::json(); - unsigned int source_count{42}; - config["source_count"] = source_count; - - auto source_mod = builder.make_module("ModuleSourceTest_mod1", config); - - auto sink = builder.make_sink("sink", [&packet_count](bool input) { - packet_count++; - VLOG(10) << "Sinking " << input << std::endl; - }); - - builder.make_edge(source_mod->output_port("source"), sink); - }; + auto init_wrapper = [](segment::Builder& builder) { + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); + config_2["config_key_1"] = true; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + auto simple_mod = builder.make_module("ModuleInitializationTest_mod1"); + auto configurable_1_mod = builder.make_module("ModuleInitializationTest_mod2", config_1); + auto configurable_2_mod = builder.make_module("ModuleInitializationTest_mod3", config_2); + auto configurable_mod_3 = ConfigurableModule("ModuleInitializationTest_mod4", config_2); + + configurable_mod_3(builder); + + EXPECT_EQ(simple_mod->input_ids().size(), 2); + EXPECT_EQ(simple_mod->output_ids().size(), 2); + EXPECT_EQ(simple_mod->input_ports().size(), 2); + EXPECT_EQ(simple_mod->output_ports().size(), 2); + EXPECT_EQ(simple_mod->input_ports().find("input1") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->input_ports().find("input2") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->input_port_type_id("input1"), typeid(bool)); + EXPECT_EQ(simple_mod->input_port_type_id("input2"), typeid(bool)); + EXPECT_EQ(simple_mod->input_port_type_ids().find("input1")->second, typeid(bool)); + EXPECT_EQ(simple_mod->input_port_type_ids().find("input2")->second, typeid(bool)); + EXPECT_EQ(simple_mod->output_ports().find("output1") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->output_ports().find("output2") != simple_mod->input_ports().end(), true); + EXPECT_EQ(simple_mod->output_port_type_id("output1"), typeid(std::string)); + EXPECT_EQ(simple_mod->output_port_type_id("output2"), typeid(std::string)); + EXPECT_EQ(simple_mod->output_port_type_ids().find("output1")->second, typeid(std::string)); + EXPECT_EQ(simple_mod->output_port_type_ids().find("output2")->second, typeid(std::string)); + + EXPECT_THROW(simple_mod->input_port("DOES_NOT_EXIST"), std::invalid_argument); + EXPECT_THROW(simple_mod->output_port("DOES_NOT_EXIST"), std::invalid_argument); + EXPECT_THROW(simple_mod->input_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); + EXPECT_THROW(simple_mod->output_port_type_id("DOES_NOT_EXIST"), std::invalid_argument); + + EXPECT_EQ(configurable_1_mod->input_ports().size(), 1); + EXPECT_EQ(configurable_1_mod->output_ports().size(), 1); + EXPECT_EQ(configurable_1_mod->m_was_configured, false); + + EXPECT_EQ(configurable_2_mod->input_ports().size(), 1); + EXPECT_EQ(configurable_2_mod->output_ports().size(), 1); + EXPECT_EQ(configurable_2_mod->m_was_configured, true); + }; + + m_pipeline->make_segment("Initialization_Segment", init_wrapper); + + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); + + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.stop(); + executor.join(); +} + +TEST_F(TestSegmentModules, ModuleEndToEndTest) +{ + using namespace modules; + unsigned int packets_1{0}; + unsigned int packets_2{0}; + unsigned int packets_3{0}; + + auto init_wrapper = [&packets_1, &packets_2, &packets_3](segment::Builder& builder) { + auto simple_mod = builder.make_module("ModuleEndToEndTest_mod1"); + auto configurable_mod = builder.make_module("ModuleEndToEndTest_mod2"); + + auto source1 = builder.make_source("src1", [](rxcpp::subscriber& sub) { + if (sub.is_subscribed()) + { + sub.on_next(true); + sub.on_next(false); + sub.on_next(true); + sub.on_next(true); + } + + sub.on_completed(); + }); + + // Ex1. Partially dynamic edge construction + builder.make_edge(source1, simple_mod->input_port("input1")); + + auto source2 = builder.make_source("src2", [](rxcpp::subscriber& sub) { + if (sub.is_subscribed()) + { + sub.on_next(true); + sub.on_next(false); + sub.on_next(false); + sub.on_next(false); + sub.on_next(true); + sub.on_next(false); + } + + sub.on_completed(); + }); + + // Ex2. Dynamic edge construction -- requires type specification + builder.make_dynamic_edge(source2, simple_mod->input_port("input2")); + + auto sink1 = builder.make_sink("sink1", [&packets_1](std::string input) { + packets_1++; + VLOG(10) << "Sinking " << input << std::endl; + }); + + builder.make_edge(simple_mod->output_port("output1"), sink1); + + auto sink2 = builder.make_sink("sink2", [&packets_2](std::string input) { + packets_2++; + VLOG(10) << "Sinking " << input << std::endl; + }); + + builder.make_edge(simple_mod->output_port("output2"), sink2); + + auto source3 = builder.make_source("src3", [](rxcpp::subscriber& sub) { + if (sub.is_subscribed()) + { + sub.on_next(true); + sub.on_next(false); + sub.on_next(true); + sub.on_next(true); + } + + sub.on_completed(); + }); + + builder.make_edge(source3, configurable_mod->input_port("configurable_input_a")); + + auto sink3 = builder.make_sink("sink3", [&packets_3](std::string input) { + packets_3++; + VLOG(10) << "Sinking " << input << std::endl; + }); + + builder.make_edge(configurable_mod->output_port("configurable_output_x"), sink3); + }; + + m_pipeline->make_segment("EndToEnd_Segment", init_wrapper); + + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); + + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); + + EXPECT_EQ(packets_1, 4); + EXPECT_EQ(packets_2, 6); + EXPECT_EQ(packets_3, 4); +} + +TEST_F(TestSegmentModules, ModuleAsSourceTest) +{ + using namespace modules; + + unsigned int packet_count{0}; + + auto init_wrapper = [&packet_count](segment::Builder& builder) { + auto config = nlohmann::json(); + unsigned int source_count{42}; + config["source_count"] = source_count; + + auto source_mod = builder.make_module("ModuleSourceTest_mod1", config); + + auto sink = builder.make_sink("sink", [&packet_count](bool input) { + packet_count++; + VLOG(10) << "Sinking " << input << std::endl; + }); + + builder.make_edge(source_mod->output_port("source"), sink); + }; - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - EXPECT_EQ(packet_count, 42); - } + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); + + EXPECT_EQ(packet_count, 42); +} - TEST_F(TestSegmentModules, ModuleAsSinkTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleAsSinkTest) +{ + using namespace modules; - unsigned int packet_count{0}; + unsigned int packet_count{0}; - auto init_wrapper = [&packet_count](segment::Builder &builder) { - auto source = builder.make_source("source", [&packet_count](rxcpp::subscriber &sub) { - if (sub.is_subscribed()) { - for (unsigned int i = 0; i < 43; ++i) { - sub.on_next(true); - packet_count++; - } + auto init_wrapper = [&packet_count](segment::Builder& builder) { + auto source = builder.make_source("source", [&packet_count](rxcpp::subscriber& sub) { + if (sub.is_subscribed()) + { + for (unsigned int i = 0; i < 43; ++i) + { + sub.on_next(true); + packet_count++; } + } - sub.on_completed(); - }); + sub.on_completed(); + }); - auto sink_mod = builder.make_module("ModuleSinkTest_mod1"); + auto sink_mod = builder.make_module("ModuleSinkTest_mod1"); - builder.make_edge(source, sink_mod->input_port("sink")); - }; + builder.make_edge(source, sink_mod->input_port("sink")); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(packet_count, 43); - } + EXPECT_EQ(packet_count, 43); +} - TEST_F(TestSegmentModules, ModuleChainingTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleChainingTest) +{ + using namespace modules; - auto sink_mod = std::make_shared("ModuleChainingTest_mod2"); - auto init_wrapper = [&sink_mod](segment::Builder &builder) { - auto config = nlohmann::json(); - unsigned int source_count{42}; - config["source_count"] = source_count; + auto sink_mod = std::make_shared("ModuleChainingTest_mod2"); + auto init_wrapper = [&sink_mod](segment::Builder& builder) { + auto config = nlohmann::json(); + unsigned int source_count{42}; + config["source_count"] = source_count; - auto source_mod = builder.make_module("ModuleChainingTest_mod1", config); - builder.init_module(sink_mod); + auto source_mod = builder.make_module("ModuleChainingTest_mod1", config); + builder.init_module(sink_mod); - builder.make_dynamic_edge(source_mod->output_port("source"), sink_mod->input_port("sink")); - }; + builder.make_dynamic_edge(source_mod->output_port("source"), sink_mod->input_port("sink")); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(sink_mod->m_packet_count, 42); - } + EXPECT_EQ(sink_mod->m_packet_count, 42); +} - TEST_F(TestSegmentModules, ModuleNestingTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleNestingTest) +{ + using namespace modules; - unsigned int packet_count{0}; + unsigned int packet_count{0}; - auto init_wrapper = [&packet_count](segment::Builder &builder) { - auto nested_mod = builder.make_module("ModuleNestingTest_mod1"); + auto init_wrapper = [&packet_count](segment::Builder& builder) { + auto nested_mod = builder.make_module("ModuleNestingTest_mod1"); - auto nested_sink = builder.make_sink("nested_sink", [&packet_count](std::string input) { - packet_count++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto nested_sink = builder.make_sink("nested_sink", [&packet_count](std::string input) { + packet_count++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(nested_mod->output_port("nested_module_output"), nested_sink); - }; + builder.make_edge(nested_mod->output_port("nested_module_output"), nested_sink); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(packet_count, 4); - } + EXPECT_EQ(packet_count, 4); +} - TEST_F(TestSegmentModules, ModuleTemplateTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleTemplateTest) +{ + using namespace modules; - unsigned int packet_count_1{0}; - unsigned int packet_count_2{0}; + unsigned int packet_count_1{0}; + unsigned int packet_count_2{0}; - auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder &builder) { - using data_type_1_t = int; - using data_type_2_t = std::string; + auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder& builder) { + using data_type_1_t = int; + using data_type_2_t = std::string; - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); - unsigned int source_count_1{42}; - unsigned int source_count_2{24}; + unsigned int source_count_1{42}; + unsigned int source_count_2{24}; - config_1["source_count"] = source_count_1; - config_2["source_count"] = source_count_2; + config_1["source_count"] = source_count_1; + config_2["source_count"] = source_count_2; - auto source_1_mod = builder.make_module>("ModuleTemplateTest_mod1", config_1); + auto source_1_mod = builder.make_module>("ModuleTemplateTest_mod1", config_1); - auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { - packet_count_1++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { + packet_count_1++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source_1_mod->output_port("source"), sink_1); + builder.make_edge(source_1_mod->output_port("source"), sink_1); - auto source_2_mod = builder.make_module>("ModuleTemplateTest_mod2", config_2); + auto source_2_mod = builder.make_module>("ModuleTemplateTest_mod2", config_2); - auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { - packet_count_2++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { + packet_count_2++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source_2_mod->output_port("source"), sink_2); - }; + builder.make_edge(source_2_mod->output_port("source"), sink_2); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(packet_count_1, 42); - EXPECT_EQ(packet_count_2, 24); - } + EXPECT_EQ(packet_count_1, 42); + EXPECT_EQ(packet_count_2, 24); +} #if !defined(__clang__) && defined(__GNUC__) -// Work around for GCC : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83258 + // Work around for GCC : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83258 #pragma GCC visibility push(default) - auto F_1 = []() -> int { return 15; }; - auto F_2 = []() -> std::string { return "test string"; }; +auto F_1 = []() -> int { return 15; }; +auto F_2 = []() -> std::string { return "test string"; }; #pragma GCC visibility pop #endif - TEST_F(TestSegmentModules, ModuleTemplateWithInitTest) { - using namespace modules; +TEST_F(TestSegmentModules, ModuleTemplateWithInitTest) +{ + using namespace modules; - unsigned int packet_count_1{0}; - unsigned int packet_count_2{0}; + unsigned int packet_count_1{0}; + unsigned int packet_count_2{0}; - auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder &builder) { - using data_type_1_t = int; - using data_type_2_t = std::string; + auto init_wrapper = [&packet_count_1, &packet_count_2](segment::Builder& builder) { + using data_type_1_t = int; + using data_type_2_t = std::string; - auto config_1 = nlohmann::json(); - auto config_2 = nlohmann::json(); + auto config_1 = nlohmann::json(); + auto config_2 = nlohmann::json(); - unsigned int source_count_1{42}; - unsigned int source_count_2{24}; + unsigned int source_count_1{42}; + unsigned int source_count_2{24}; - config_1["source_count"] = source_count_1; - config_2["source_count"] = source_count_2; + config_1["source_count"] = source_count_1; + config_2["source_count"] = source_count_2; #if defined(__clang__) - auto F_1 = []() -> int { return 15; }; - auto F_2 = []() -> std::string { return "test string"; }; + auto F_1 = []() -> int { return 15; }; + auto F_2 = []() -> std::string { return "test string"; }; #endif - auto source_1_mod = builder.make_module>( - "ModuleTemplateWithInitTest_mod1", config_1); + auto source_1_mod = builder.make_module>( + "ModuleTemplateWithInitTest_mod1", config_1); - auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { - assert(input == 15); - packet_count_1++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto sink_1 = builder.make_sink("sink_1", [&packet_count_1](data_type_1_t input) { + assert(input == 15); + packet_count_1++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source_1_mod->output_port("source"), sink_1); + builder.make_edge(source_1_mod->output_port("source"), sink_1); - auto source_2_mod = builder.make_module>( - "ModuleTemplateWithInitTest_mod2", config_2); + auto source_2_mod = builder.make_module>( + "ModuleTemplateWithInitTest_mod2", config_2); - auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { - assert(input == "test string"); - packet_count_2++; - VLOG(10) << "Sinking " << input << std::endl; - }); + auto sink_2 = builder.make_sink("sink_2", [&packet_count_2](data_type_2_t input) { + assert(input == "test string"); + packet_count_2++; + VLOG(10) << "Sinking " << input << std::endl; + }); - builder.make_edge(source_2_mod->output_port("source"), sink_2); - }; + builder.make_edge(source_2_mod->output_port("source"), sink_2); + }; - m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); + m_pipeline->make_segment("SimpleModule_Segment", init_wrapper); - auto options = std::make_shared(); - options->topology().user_cpuset("0-1"); - options->topology().restrict_gpus(true); + auto options = std::make_shared(); + options->topology().user_cpuset("0-1"); + options->topology().restrict_gpus(true); - Executor executor(options); - executor.register_pipeline(std::move(m_pipeline)); - executor.start(); - executor.join(); + Executor executor(options); + executor.register_pipeline(std::move(m_pipeline)); + executor.start(); + executor.join(); - EXPECT_EQ(packet_count_1, 42); - EXPECT_EQ(packet_count_2, 24); - } + EXPECT_EQ(packet_count_1, 42); + EXPECT_EQ(packet_count_2, 24); +} } // namespace mrc diff --git a/python/mrc/_pymrc/include/pymrc/tracers.hpp b/python/mrc/_pymrc/include/pymrc/tracers.hpp index 84eddd87d..e01c387d2 100644 --- a/python/mrc/_pymrc/include/pymrc/tracers.hpp +++ b/python/mrc/_pymrc/include/pymrc/tracers.hpp @@ -22,6 +22,6 @@ #include // for object, dict namespace mrc::pymrc { -using latency_tracer_t = mrc::benchmarking::TracerEnsemble; +using latency_tracer_t = mrc::benchmarking::TracerEnsemble; using throughput_tracer_t = mrc::benchmarking::TracerEnsemble; -} +} // namespace mrc::pymrc diff --git a/python/mrc/_pymrc/src/watchers.cpp b/python/mrc/_pymrc/src/watchers.cpp index 63285a169..a9621438c 100644 --- a/python/mrc/_pymrc/src/watchers.cpp +++ b/python/mrc/_pymrc/src/watchers.cpp @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/python/mrc/benchmarking/watchers.cpp b/python/mrc/benchmarking/watchers.cpp index 9bbcf6671..ad154b543 100644 --- a/python/mrc/benchmarking/watchers.cpp +++ b/python/mrc/benchmarking/watchers.cpp @@ -15,11 +15,11 @@ * limitations under the License. */ -#include "pymrc/tracers.hpp" #include "pymrc/watchers.hpp" #include "pymrc/executor.hpp" // IWYU pragma: keep #include "pymrc/segment.hpp" +#include "pymrc/tracers.hpp" #include #include // IWYU pragma: keep @@ -31,109 +31,98 @@ #include namespace mrc::pymrc { - namespace py = pybind11; - - void init_tracer_stats_api(py::module_& m); - - PYBIND11_MODULE(watchers, m) { - m.doc() = R"pbdoc()pbdoc"; - - pymrc::import(m, "mrc.core.executor"); - - init_tracer_stats_api(m); - - /** - * @brief define tracer implementations for use with segment watchers - */ - // pymrc::init_tracer_api(m); - - /** - * @brief Tracer objects are packaged into tracer ensembles; we'll just support tracer's with py::object payloads - * for now. - */ - auto LatencyTracer = py::class_>(m, "LatencyTracer"); - LatencyTracer.def(py::init()); - - // TODO(devin) - // LatencyTracer.def("add_counters", &mrc::LatencyTracer::add_counters); - LatencyTracer.def_static("aggregate", [](py::object& obj_type, py::list ensemble_tracers) { - // Something is broken with calling static members - }); - LatencyTracer.def("emit", &latency_tracer_t::emit); - - /** - * @brief ThroughputTracer - */ - auto ThroughputTracer = - py::class_>(m, "ThroughputTracer"); - ThroughputTracer.def(py::init()); - - // Segment watcher allows for each tracer object to have a data payload. To simplify, for now, we'll assume - // that the payload is a py::object. - // auto SegmentWatcher = py::class_>(m, "SegmentWatcher"); - auto PyLatencyWatcher = py::class_(m, "LatencyWatcher"); - PyLatencyWatcher.def(py::init>()); - PyLatencyWatcher.def( - py::init, std::function>()); - PyLatencyWatcher.def("aggregate_tracers", &pymrc::LatencyWatcher::aggregate_tracers_as_pydict); - // PyLatencyWatcher.def("make_tracer_source", &pymrc::LatencyWatcher::create_rx_tracer_source); - PyLatencyWatcher.def("is_running", &pymrc::LatencyWatcher::is_running); - PyLatencyWatcher.def("make_segment", pymrc::wrap_segment_init_callback(&pymrc::LatencyWatcher::make_segment)); - PyLatencyWatcher.def( - "make_tracer_source", &pymrc::LatencyWatcher::make_tracer_source, - py::return_value_policy::reference_internal); - PyLatencyWatcher.def( - "make_traced_node", &pymrc::LatencyWatcher::make_traced_node, - py::return_value_policy::reference_internal); - PyLatencyWatcher.def( - "make_tracer_sink", &pymrc::LatencyWatcher::make_tracer_sink, - py::return_value_policy::reference_internal); - PyLatencyWatcher.def("reset", &pymrc::LatencyWatcher::reset, py::call_guard()); - PyLatencyWatcher.def("run", &pymrc::LatencyWatcher::run, py::call_guard()); - PyLatencyWatcher.def("shutdown", &pymrc::LatencyWatcher::shutdown, py::call_guard()); - PyLatencyWatcher.def("start_trace", &pymrc::LatencyWatcher::start_trace, - py::call_guard()); - PyLatencyWatcher.def("stop_trace", &pymrc::LatencyWatcher::stop_trace, - py::call_guard()); - PyLatencyWatcher.def( - "trace_until_notified", &pymrc::LatencyWatcher::trace_until_notified, - py::call_guard()); - PyLatencyWatcher.def("tracer_count", py::overload_cast(&pymrc::LatencyWatcher::tracer_count)); - PyLatencyWatcher.def("tracing", &pymrc::LatencyWatcher::tracing); - - /** Throughput Watcher Begin **/ - auto PyThroughputWatcher = py::class_(m, "ThroughputWatcher"); - - PyThroughputWatcher.def(py::init>()); - PyThroughputWatcher.def( - py::init, std::function>()); - PyThroughputWatcher.def("aggregate_tracers", &pymrc::ThroughputWatcher::aggregate_tracers_as_pydict); - // PyThroughputWatcher.def("make_tracer_source", &pymrc::ThroughputWatcher::create_rx_tracer_source); - PyThroughputWatcher.def("is_running", &pymrc::ThroughputWatcher::is_running); - PyThroughputWatcher.def("make_segment", - pymrc::wrap_segment_init_callback(&pymrc::ThroughputWatcher::make_segment)); - PyThroughputWatcher.def("make_tracer_source", - &pymrc::ThroughputWatcher::make_tracer_source, - py::return_value_policy::reference_internal); - PyThroughputWatcher.def( - "make_traced_node", &pymrc::ThroughputWatcher::make_traced_node, - py::return_value_policy::reference_internal); - PyThroughputWatcher.def( - "make_tracer_sink", &pymrc::ThroughputWatcher::make_tracer_sink, - py::return_value_policy::reference_internal); - PyThroughputWatcher.def("reset", &pymrc::ThroughputWatcher::reset, py::call_guard()); - PyThroughputWatcher.def("run", &pymrc::ThroughputWatcher::run, py::call_guard()); - PyThroughputWatcher.def("shutdown", &pymrc::ThroughputWatcher::shutdown, - py::call_guard()); - PyThroughputWatcher.def( - "start_trace", &pymrc::ThroughputWatcher::start_trace, py::call_guard()); - PyThroughputWatcher.def( - "stop_trace", &pymrc::ThroughputWatcher::stop_trace, py::call_guard()); - PyThroughputWatcher.def("trace_until_notified", - &pymrc::ThroughputWatcher::trace_until_notified, - py::call_guard()); - PyThroughputWatcher.def("tracer_count", - py::overload_cast(&pymrc::ThroughputWatcher::tracer_count)); - PyThroughputWatcher.def("tracing", &pymrc::ThroughputWatcher::tracing); - } +namespace py = pybind11; + +void init_tracer_stats_api(py::module_& m); + +PYBIND11_MODULE(watchers, m) +{ + m.doc() = R"pbdoc()pbdoc"; + + pymrc::import(m, "mrc.core.executor"); + + init_tracer_stats_api(m); + + /** + * @brief define tracer implementations for use with segment watchers + */ + // pymrc::init_tracer_api(m); + + /** + * @brief Tracer objects are packaged into tracer ensembles; we'll just support tracer's with py::object payloads + * for now. + */ + auto LatencyTracer = py::class_>(m, "LatencyTracer"); + LatencyTracer.def(py::init()); + + // TODO(devin) + // LatencyTracer.def("add_counters", &mrc::LatencyTracer::add_counters); + LatencyTracer.def_static("aggregate", [](py::object& obj_type, py::list ensemble_tracers) { + // Something is broken with calling static members + }); + LatencyTracer.def("emit", &latency_tracer_t::emit); + + /** + * @brief ThroughputTracer + */ + auto ThroughputTracer = + py::class_>(m, "ThroughputTracer"); + ThroughputTracer.def(py::init()); + + // Segment watcher allows for each tracer object to have a data payload. To simplify, for now, we'll assume + // that the payload is a py::object. + // auto SegmentWatcher = py::class_>(m, "SegmentWatcher"); + auto PyLatencyWatcher = py::class_(m, "LatencyWatcher"); + PyLatencyWatcher.def(py::init>()); + PyLatencyWatcher.def(py::init, std::function>()); + PyLatencyWatcher.def("aggregate_tracers", &pymrc::LatencyWatcher::aggregate_tracers_as_pydict); + // PyLatencyWatcher.def("make_tracer_source", &pymrc::LatencyWatcher::create_rx_tracer_source); + PyLatencyWatcher.def("is_running", &pymrc::LatencyWatcher::is_running); + PyLatencyWatcher.def("make_segment", pymrc::wrap_segment_init_callback(&pymrc::LatencyWatcher::make_segment)); + PyLatencyWatcher.def( + "make_tracer_source", &pymrc::LatencyWatcher::make_tracer_source, py::return_value_policy::reference_internal); + PyLatencyWatcher.def( + "make_traced_node", &pymrc::LatencyWatcher::make_traced_node, py::return_value_policy::reference_internal); + PyLatencyWatcher.def( + "make_tracer_sink", &pymrc::LatencyWatcher::make_tracer_sink, py::return_value_policy::reference_internal); + PyLatencyWatcher.def("reset", &pymrc::LatencyWatcher::reset, py::call_guard()); + PyLatencyWatcher.def("run", &pymrc::LatencyWatcher::run, py::call_guard()); + PyLatencyWatcher.def("shutdown", &pymrc::LatencyWatcher::shutdown, py::call_guard()); + PyLatencyWatcher.def("start_trace", &pymrc::LatencyWatcher::start_trace, py::call_guard()); + PyLatencyWatcher.def("stop_trace", &pymrc::LatencyWatcher::stop_trace, py::call_guard()); + PyLatencyWatcher.def( + "trace_until_notified", &pymrc::LatencyWatcher::trace_until_notified, py::call_guard()); + PyLatencyWatcher.def("tracer_count", py::overload_cast(&pymrc::LatencyWatcher::tracer_count)); + PyLatencyWatcher.def("tracing", &pymrc::LatencyWatcher::tracing); + + /** Throughput Watcher Begin **/ + auto PyThroughputWatcher = py::class_(m, "ThroughputWatcher"); + + PyThroughputWatcher.def(py::init>()); + PyThroughputWatcher.def( + py::init, std::function>()); + PyThroughputWatcher.def("aggregate_tracers", &pymrc::ThroughputWatcher::aggregate_tracers_as_pydict); + // PyThroughputWatcher.def("make_tracer_source", &pymrc::ThroughputWatcher::create_rx_tracer_source); + PyThroughputWatcher.def("is_running", &pymrc::ThroughputWatcher::is_running); + PyThroughputWatcher.def("make_segment", pymrc::wrap_segment_init_callback(&pymrc::ThroughputWatcher::make_segment)); + PyThroughputWatcher.def("make_tracer_source", + &pymrc::ThroughputWatcher::make_tracer_source, + py::return_value_policy::reference_internal); + PyThroughputWatcher.def( + "make_traced_node", &pymrc::ThroughputWatcher::make_traced_node, py::return_value_policy::reference_internal); + PyThroughputWatcher.def( + "make_tracer_sink", &pymrc::ThroughputWatcher::make_tracer_sink, py::return_value_policy::reference_internal); + PyThroughputWatcher.def("reset", &pymrc::ThroughputWatcher::reset, py::call_guard()); + PyThroughputWatcher.def("run", &pymrc::ThroughputWatcher::run, py::call_guard()); + PyThroughputWatcher.def("shutdown", &pymrc::ThroughputWatcher::shutdown, py::call_guard()); + PyThroughputWatcher.def( + "start_trace", &pymrc::ThroughputWatcher::start_trace, py::call_guard()); + PyThroughputWatcher.def( + "stop_trace", &pymrc::ThroughputWatcher::stop_trace, py::call_guard()); + PyThroughputWatcher.def("trace_until_notified", + &pymrc::ThroughputWatcher::trace_until_notified, + py::call_guard()); + PyThroughputWatcher.def("tracer_count", py::overload_cast(&pymrc::ThroughputWatcher::tracer_count)); + PyThroughputWatcher.def("tracing", &pymrc::ThroughputWatcher::tracing); +} } // namespace mrc::pymrc From aa51935449160c478b46f15c5fd93c214e56b62b Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 10 Jan 2023 15:47:16 -0700 Subject: [PATCH 48/55] Formatting fixes --- ci/conda/recipes/libmrc/build.sh | 3 +- python/mrc/_pymrc/include/pymrc/watchers.hpp | 57 ++++++++++---------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/ci/conda/recipes/libmrc/build.sh b/ci/conda/recipes/libmrc/build.sh index da1e05a1a..34246be6f 100644 --- a/ci/conda/recipes/libmrc/build.sh +++ b/ci/conda/recipes/libmrc/build.sh @@ -87,8 +87,7 @@ fi echo "PYTHON: ${PYTHON}" echo "which python: $(which python)" -git submodule init -git submodule update +git submodule update --init --recursive # Run configure cmake -B ${BUILD_DIR} \ diff --git a/python/mrc/_pymrc/include/pymrc/watchers.hpp b/python/mrc/_pymrc/include/pymrc/watchers.hpp index 4f0464228..e6ecccbe9 100644 --- a/python/mrc/_pymrc/include/pymrc/watchers.hpp +++ b/python/mrc/_pymrc/include/pymrc/watchers.hpp @@ -43,66 +43,65 @@ namespace mrc::pymrc { #pragma GCC visibility push(default) using latency_ensemble_t = mrc::benchmarking::TracerEnsemble; -using latency_watcher_t = mrc::benchmarking::SegmentWatcher; +using latency_watcher_t = mrc::benchmarking::SegmentWatcher; using throughput_ensemble_t = mrc::benchmarking::TracerEnsemble; -using throughput_watcher_t = mrc::benchmarking::SegmentWatcher; +using throughput_watcher_t = mrc::benchmarking::SegmentWatcher; -class LatencyWatcher : public latency_watcher_t { -public: +class LatencyWatcher : public latency_watcher_t +{ + public: LatencyWatcher(std::shared_ptr executor); - LatencyWatcher(std::shared_ptr executor, - std::function payload_init); + LatencyWatcher(std::shared_ptr executor, std::function payload_init); - void make_segment(const std::string &name, - const std::function &init); + void make_segment(const std::string& name, + const std::function& init); - std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, - const std::string &name, + std::shared_ptr make_tracer_source(mrc::segment::Builder& seg, + const std::string& name, bool force_sequential = false); std::shared_ptr make_traced_node( - mrc::segment::Builder &seg, - const std::string &name, - std::function map_f); + mrc::segment::Builder& seg, + const std::string& name, + std::function map_f); std::shared_ptr make_tracer_sink( - mrc::segment::Builder &seg, const std::string &name, - std::function sink_f); + mrc::segment::Builder& seg, const std::string& name, std::function sink_f); pybind11::dict aggregate_tracers_as_pydict(); -private: + private: std::shared_ptr m_executor; }; -class ThroughputWatcher : public throughput_watcher_t { -public: +class ThroughputWatcher : public throughput_watcher_t +{ + public: ThroughputWatcher(std::shared_ptr executor); ThroughputWatcher(std::shared_ptr executor, - std::function payload_init); + std::function payload_init); - void make_segment(const std::string &name, - const std::function &init); + void make_segment(const std::string& name, + const std::function& init); - std::shared_ptr make_tracer_source(mrc::segment::Builder &seg, - const std::string &name, + std::shared_ptr make_tracer_source(mrc::segment::Builder& seg, + const std::string& name, bool force_sequential = false); std::shared_ptr make_traced_node( - mrc::segment::Builder &seg, - const std::string &name, - std::function map_f); + mrc::segment::Builder& seg, + const std::string& name, + std::function map_f); std::shared_ptr make_tracer_sink( - mrc::segment::Builder &seg, const std::string &name, - std::function sink_f); + mrc::segment::Builder& seg, const std::string& name, std::function sink_f); pybind11::dict aggregate_tracers_as_pydict(); -private: + private: std::shared_ptr m_executor; }; From 557e0ea6f66dc51bcd6e892ce8b6452acaf14e91 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 10 Jan 2023 16:20:20 -0700 Subject: [PATCH 49/55] Formatting fixes --- python/mrc/_pymrc/src/watchers.cpp | 131 ++++++++++++++++------------- 1 file changed, 73 insertions(+), 58 deletions(-) diff --git a/python/mrc/_pymrc/src/watchers.cpp b/python/mrc/_pymrc/src/watchers.cpp index a9621438c..cc20c1993 100644 --- a/python/mrc/_pymrc/src/watchers.cpp +++ b/python/mrc/_pymrc/src/watchers.cpp @@ -44,9 +44,10 @@ namespace mrc::pymrc { namespace py = pybind11; LatencyWatcher::LatencyWatcher(std::shared_ptr executor) : - latency_watcher_t(executor->get_executor()), - m_executor(executor) { - auto payload_initializer = [](latency_ensemble_t &latency_ensemble) { + latency_watcher_t(executor->get_executor()), + m_executor(executor) +{ + auto payload_initializer = [](latency_ensemble_t& latency_ensemble) { py::gil_scoped_acquire gil; latency_ensemble = py::none(); }; @@ -55,26 +56,30 @@ LatencyWatcher::LatencyWatcher(std::shared_ptr executor) : } LatencyWatcher::LatencyWatcher(std::shared_ptr executor, - std::function payload_init) : - latency_watcher_t(executor->get_executor(), payload_init), - m_executor(executor) {} - -void LatencyWatcher::make_segment(const std::string &name, - const std::function &init) { + std::function payload_init) : + latency_watcher_t(executor->get_executor(), payload_init), + m_executor(executor) +{} + +void LatencyWatcher::make_segment(const std::string& name, + const std::function& init) +{ pymrc::Pipeline pipeline; - auto tracer_init_wrapper = [this, init](mrc::segment::Builder &seg) { init(seg, *this); }; + auto tracer_init_wrapper = [this, init](mrc::segment::Builder& seg) { init(seg, *this); }; pipeline.make_segment(name, tracer_init_wrapper); m_executor->register_pipeline(pipeline); } -std::shared_ptr LatencyWatcher::make_tracer_source(mrc::segment::Builder &seg, - const std::string &name, - bool force_sequential) { +std::shared_ptr LatencyWatcher::make_tracer_source(mrc::segment::Builder& seg, + const std::string& name, + bool force_sequential) +{ using data_type_t = std::shared_ptr; - if (force_sequential) { + if (force_sequential) + { return seg.make_source(name, this->create_rx_tracer_source(name)); } @@ -82,50 +87,54 @@ std::shared_ptr LatencyWatcher::make_tracer_sour } std::shared_ptr LatencyWatcher::make_traced_node( - mrc::segment::Builder &seg, const std::string &name, std::function map_f) { + mrc::segment::Builder& seg, const std::string& name, std::function map_f) +{ using data_type_t = std::shared_ptr; auto internal_idx = this->get_or_create_node_entry(name); auto trace_node = seg.make_node( - name, - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), - rxcpp::operators::map([map_f](data_type_t tracer) { - py::gil_scoped_acquire gil; - *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's + name, + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), + rxcpp::operators::map([map_f](data_type_t tracer) { + py::gil_scoped_acquire gil; + *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's - return tracer; - }), - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); + return tracer; + }), + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); return trace_node; // std::static_pointer_cast(trace_node); } std::shared_ptr LatencyWatcher::make_tracer_sink( - mrc::segment::Builder &seg, const std::string &name, std::function sink_f) { - using data_type_t = std::shared_ptr; - auto compound_sink_f = [sink_f](pymrc::latency_ensemble_t &data) { + mrc::segment::Builder& seg, const std::string& name, std::function sink_f) +{ + using data_type_t = std::shared_ptr; + auto compound_sink_f = [sink_f](pymrc::latency_ensemble_t& data) { py::gil_scoped_acquire gil; sink_f(data); }; auto tracer_sink_f = this->create_tracer_sink_lambda(name, compound_sink_f); - auto tracer_sink = seg.make_sink(name, tracer_sink_f); + auto tracer_sink = seg.make_sink(name, tracer_sink_f); return tracer_sink; } -py::dict LatencyWatcher::aggregate_tracers_as_pydict() { +py::dict LatencyWatcher::aggregate_tracers_as_pydict() +{ nlohmann::json j = latency_watcher_t::aggregate_tracers()->to_json(); return pymrc::cast_from_json(j); } ThroughputWatcher::ThroughputWatcher(std::shared_ptr executor) : - throughput_watcher_t(executor->get_executor()), - m_executor(executor) { + throughput_watcher_t(executor->get_executor()), + m_executor(executor) +{ using throughput_ensemble_t = - mrc::benchmarking::TracerEnsemble; + mrc::benchmarking::TracerEnsemble; - auto payload_initializer = [](throughput_ensemble_t &le) { + auto payload_initializer = [](throughput_ensemble_t& le) { py::gil_scoped_acquire gil; le = py::none(); }; @@ -134,27 +143,30 @@ ThroughputWatcher::ThroughputWatcher(std::shared_ptr executor) } ThroughputWatcher::ThroughputWatcher(std::shared_ptr executor, - std::function payload_init) : - throughput_watcher_t(executor->get_executor(), payload_init), - m_executor(executor) {} - -void ThroughputWatcher::make_segment(const std::string &name, - const std::function &init) { + std::function payload_init) : + throughput_watcher_t(executor->get_executor(), payload_init), + m_executor(executor) +{} + +void ThroughputWatcher::make_segment(const std::string& name, + const std::function& init) +{ pymrc::Pipeline pipeline; - auto tracer_init_wrapper = [this, init](mrc::segment::Builder &seg) { init(seg, *this); }; + auto tracer_init_wrapper = [this, init](mrc::segment::Builder& seg) { init(seg, *this); }; pipeline.make_segment(name, tracer_init_wrapper); m_executor->register_pipeline(pipeline); } -std::shared_ptr ThroughputWatcher::make_tracer_source(mrc::segment::Builder &seg, - const std::string &name, - bool force_sequential) { +std::shared_ptr ThroughputWatcher::make_tracer_source(mrc::segment::Builder& seg, + const std::string& name, + bool force_sequential) +{ using data_type_t = std::shared_ptr; - if (force_sequential) { + if (force_sequential) + { return seg.make_source(name, this->create_rx_tracer_source(name)); } @@ -162,38 +174,41 @@ std::shared_ptr ThroughputWatcher::make_tracer_s } std::shared_ptr ThroughputWatcher::make_traced_node( - mrc::segment::Builder &seg, const std::string &name, std::function map_f) { + mrc::segment::Builder& seg, const std::string& name, std::function map_f) +{ using data_type_t = std::shared_ptr; auto internal_idx = this->get_or_create_node_entry(name); auto trace_node = seg.make_node( - name, - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), - rxcpp::operators::map([map_f](data_type_t tracer) { - py::gil_scoped_acquire gil; - *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's + name, + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->receive(internal_idx); }), + rxcpp::operators::map([map_f](data_type_t tracer) { + py::gil_scoped_acquire gil; + *tracer = map_f(*tracer); // Implicit operator conversion, operates on tracer's - return tracer; - }), - rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); + return tracer; + }), + rxcpp::operators::tap([internal_idx](data_type_t tracer) { tracer->emit(internal_idx); })); return trace_node; } std::shared_ptr ThroughputWatcher::make_tracer_sink( - mrc::segment::Builder &seg, const std::string &name, std::function sink_f) { - using data_type_t = std::shared_ptr; - auto compound_sink_f = [sink_f](pymrc::throughput_ensemble_t &data) { + mrc::segment::Builder& seg, const std::string& name, std::function sink_f) +{ + using data_type_t = std::shared_ptr; + auto compound_sink_f = [sink_f](pymrc::throughput_ensemble_t& data) { py::gil_scoped_acquire gil; sink_f(data); }; auto tracer_sink_f = this->create_tracer_sink_lambda(name, compound_sink_f); - auto tracer_sink = seg.make_sink(name, tracer_sink_f); + auto tracer_sink = seg.make_sink(name, tracer_sink_f); return tracer_sink; } -py::dict ThroughputWatcher::aggregate_tracers_as_pydict() { +py::dict ThroughputWatcher::aggregate_tracers_as_pydict() +{ nlohmann::json j = throughput_watcher_t::aggregate_tracers()->to_json(); return pymrc::cast_from_json(j); From 6a5b712288b0cf0e9b62171357170f8fd7e8adea Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Tue, 10 Jan 2023 16:50:44 -0700 Subject: [PATCH 50/55] Update copyright dates --- ci/scripts/github/docs.sh | 2 +- ci/scripts/github/test.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/scripts/github/docs.sh b/ci/scripts/github/docs.sh index b98b22f5d..2e0a1f64c 100755 --- a/ci/scripts/github/docs.sh +++ b/ci/scripts/github/docs.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ci/scripts/github/test.sh b/ci/scripts/github/test.sh index 4cb5bdcf5..0aab525a0 100755 --- a/ci/scripts/github/test.sh +++ b/ci/scripts/github/test.sh @@ -1,5 +1,5 @@ #!/usr/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); From 6ab2781acd9d6818c107ce50718087c253e92519 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 12 Jan 2023 19:48:32 -0700 Subject: [PATCH 51/55] Update .gitmodules Co-authored-by: Michael Demoret <42954918+mdemoret-nv@users.noreply.github.com> --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 10b4ee8b5..42fbfe928 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "morpheus_utils"] path = external/utilities - url = https://github.com/nv-morpheus/utilities.git + url = ../utilities.git branch = branch-23.01 From 51abcdcbce585d4ca699fc6d7ad50e1660d4e1bd Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Thu, 12 Jan 2023 19:54:51 -0700 Subject: [PATCH 52/55] PR Feedback updates --- CMakeLists.txt | 1 - ci/scripts/github/checks.sh | 3 +-- python/mrc/_pymrc/src/tracers.cpp | 1 - python/mrc/benchmarking/CMakeLists.txt | 1 - 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e93e1dff9..207f6e4ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,6 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -allow-unsupported-compiler") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts") - #add_compile_options(-fcoroutines-ts) # Required for clang to use the coroutines libraries endif() # Now enable CUDA diff --git a/ci/scripts/github/checks.sh b/ci/scripts/github/checks.sh index 5d3f01c40..34d1aca95 100755 --- a/ci/scripts/github/checks.sh +++ b/ci/scripts/github/checks.sh @@ -23,8 +23,7 @@ fetch_base_branch update_conda_env rapids-logger "Configuring CMake" -git submodule init -git submodule update +git submodule update --init --recursive cmake -B build -G Ninja ${CMAKE_BUILD_ALL_FEATURES} . rapids-logger "Building targets that generate source code" diff --git a/python/mrc/_pymrc/src/tracers.cpp b/python/mrc/_pymrc/src/tracers.cpp index 5956b749d..21aad6c87 100644 --- a/python/mrc/_pymrc/src/tracers.cpp +++ b/python/mrc/_pymrc/src/tracers.cpp @@ -15,5 +15,4 @@ * limitations under the License. */ -// TODO(Devin) #include "pymrc/tracers.hpp" \ No newline at end of file diff --git a/python/mrc/benchmarking/CMakeLists.txt b/python/mrc/benchmarking/CMakeLists.txt index d98203c40..ebe1278c7 100644 --- a/python/mrc/benchmarking/CMakeLists.txt +++ b/python/mrc/benchmarking/CMakeLists.txt @@ -15,6 +15,5 @@ list(APPEND CMAKE_MESSAGE_CONTEXT "benchmarking") mrc_add_pybind11_module(watchers SOURCE_FILES watchers.cpp trace_statistics.cpp) -#mrc_add_pybind11_module(tracers SOURCE_FILES tracers.cpp trace_statistics.cpp) list(POP_BACK CMAKE_MESSAGE_CONTEXT) From d5e998f3de11a83629bcbaafd94bb73f15cd6da3 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 13 Jan 2023 12:40:23 -0700 Subject: [PATCH 53/55] Formatting fixes --- cpp/mrc/tests/modules/test_segment_modules.cpp | 8 ++++++-- python/mrc/benchmarking/watchers.cpp | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/cpp/mrc/tests/modules/test_segment_modules.cpp b/cpp/mrc/tests/modules/test_segment_modules.cpp index a65dc4d06..d9a9bc902 100644 --- a/cpp/mrc/tests/modules/test_segment_modules.cpp +++ b/cpp/mrc/tests/modules/test_segment_modules.cpp @@ -408,8 +408,12 @@ TEST_F(TestSegmentModules, ModuleTemplateTest) #if !defined(__clang__) && defined(__GNUC__) // Work around for GCC : https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83258 #pragma GCC visibility push(default) -auto F_1 = []() -> int { return 15; }; -auto F_2 = []() -> std::string { return "test string"; }; +auto F_1 = []() -> int { + return 15; +}; +auto F_2 = []() -> std::string { + return "test string"; +}; #pragma GCC visibility pop #endif diff --git a/python/mrc/benchmarking/watchers.cpp b/python/mrc/benchmarking/watchers.cpp index 0a573e347..26de6d60e 100644 --- a/python/mrc/benchmarking/watchers.cpp +++ b/python/mrc/benchmarking/watchers.cpp @@ -65,8 +65,8 @@ PYBIND11_MODULE(watchers, m) /** * @brief ThroughputTracer */ - auto ThroughputTracer = - py::class_>(m, "ThroughputTracer"); + auto ThroughputTracer = py::class_>(m, + "ThroughputTracer"); ThroughputTracer.def(py::init()); // Segment watcher allows for each tracer object to have a data payload. To simplify, for now, we'll assume From 46e7a48210ca866c9378aef2ab8597368a6abf7a Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 13 Jan 2023 14:50:24 -0700 Subject: [PATCH 54/55] Update to copy pytest files into build dir --- python/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index e9b846a36..79676a206 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -35,7 +35,13 @@ morpheus_utils_print_python_info() morpheus_utils_create_python_package(mrc) # Add a few additional files to be copied -morpheus_utils_add_python_sources("pytest.ini" "tests/string_reader_input.txt") +file(GLOB pymrc_test_files "${CMAKE_CURRENT_SOURCE_DIR}/tests/*.py") +morpheus_utils_add_python_sources( + "pytest.ini" + "tests/string_reader_input.txt" + ${pymrc_test_files} +) + # Save the root of the python for relative paths set(MRC_PY_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) From e83397ea46b88631a8ad59349ded0cba08cc37d7 Mon Sep 17 00:00:00 2001 From: Devin Robison Date: Fri, 13 Jan 2023 16:48:35 -0700 Subject: [PATCH 55/55] Roll to updated utilities, fix missing test copies --- ci/scripts/github/common.sh | 3 +-- external/utilities | 2 +- python/mrc/_pymrc/CMakeLists.txt | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ci/scripts/github/common.sh b/ci/scripts/github/common.sh index fae327469..ccd36ab71 100644 --- a/ci/scripts/github/common.sh +++ b/ci/scripts/github/common.sh @@ -96,8 +96,7 @@ function fetch_base_branch() { # Change target is the branch name we are merging into but due to the weird way jenkins does # the checkout it isn't recognized by git without the origin/ prefix export CHANGE_TARGET="origin/${BASE_BRANCH}" - git submodule init - git submodule update + git submodule update --init --recursive rapids-logger "Base branch: ${BASE_BRANCH}" } diff --git a/external/utilities b/external/utilities index a83eb0ff3..ea948b427 160000 --- a/external/utilities +++ b/external/utilities @@ -1 +1 @@ -Subproject commit a83eb0ff3281013a886a0f8ab5304d55094ae8ee +Subproject commit ea948b427cda4aec0b583dec2e3ff5f696a6d941 diff --git a/python/mrc/_pymrc/CMakeLists.txt b/python/mrc/_pymrc/CMakeLists.txt index b2d6de068..a215f0113 100644 --- a/python/mrc/_pymrc/CMakeLists.txt +++ b/python/mrc/_pymrc/CMakeLists.txt @@ -33,7 +33,6 @@ add_library(pymrc src/segment_modules.cpp src/subscriber.cpp src/system.cpp - src/tracers.cpp src/types.cpp src/utilities/deserializers.cpp src/utilities/object_cache.cpp