From 682ed36fe68d48dbf12c533ed6fe9cf613a4a909 Mon Sep 17 00:00:00 2001 From: Atul Kulkarni Date: Tue, 10 Jun 2025 12:12:36 -0500 Subject: [PATCH] Added new ENABLE_CODE_COVERAGE option. (#1664) Modified install.sh script to add this new option --- CMakeLists.txt | 41 +++++++++++++++++++++++++++++++++-- install.sh | 10 ++++++++- test/CMakeLists.txt | 10 ++++++++- test/_RecorderTests.cpp | 4 ++-- test/common/RcclMockFuncs.hpp | 6 ++++- 5 files changed, 64 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6e8da94ef..a93c1c0c19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(BUILD_LOCAL_GPU_TARGET_ONLY "Build only for GPUs detected on option(BUILD_SHARED_LIBS "Build as shared library" ON) option(BUILD_TESTS "Build unit test programs" OFF) option(COLLTRACE "Collective Trace Option" ON) +option(ENABLE_CODE_COVERAGE "Enable code coverage" OFF) option(ENABLE_MSCCL_KERNEL "Enable MSCCL while compiling" ON) option(ENABLE_MSCCLPP "Enable MSCCL++" ON) option(ENABLE_MSCCLPP_CLIP "Enable MSCCL++" OFF) @@ -832,8 +833,44 @@ target_compile_options(rccl PRIVATE -Werror=uninitialized) target_compile_options(rccl PRIVATE -Werror=sometimes-uninitialized) target_compile_options(rccl PRIVATE -Wall) target_compile_options(rccl PRIVATE -Wno-format-nonliteral) -target_compile_options(rccl PRIVATE -fgpu-rdc) # Generate relocatable device code (required for extern __shared__) -target_compile_options(rccl PRIVATE -fvisibility=hidden) # Set symbol visibility to hidden by default +target_compile_options(rccl PRIVATE -fgpu-rdc) + +## Set RCCL compile and linker options for unit tests and code coverage +if(ENABLE_CODE_COVERAGE) + if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + message(FATAL_ERROR "Code coverage is enabled, but the build type is '${CMAKE_BUILD_TYPE}'. " + "Code coverage requires 'Debug' build types to expose internal symbols. " + "Please set CMAKE_BUILD_TYPE to 'Debug' and reconfigure.") + endif() + + message(STATUS "Code coverage is enabled with build type '${CMAKE_BUILD_TYPE}'.") + + target_compile_options(rccl PRIVATE + -fvisibility=default -Xarch_host -fprofile-instr-generate + -Xarch_host -fcoverage-mapping) + + set(COVERAGE_SHARED_LINKER_FLAGS + -fprofile-generate + -Wl,--enable-new-dtags,--build-id=sha1,--rpath,$ORIGIN + ) + + set(COVERAGE_EXE_LINKER_FLAGS + -fprofile-generate + -Wl,--enable-new-dtags,--build-id=sha1,--rpath,$ORIGIN/../lib + ) + + target_link_options(rccl PRIVATE ${COVERAGE_SHARED_LINKER_FLAGS}) + target_link_options(rccl PRIVATE ${COVERAGE_EXE_LINKER_FLAGS}) +elseif(BUILD_TESTS) # Enable default/hidden visibility based on build type and ROCM_VERSION + if (ROCM_VERSION VERSION_GREATER_EQUAL "60400" AND CMAKE_BUILD_TYPE MATCHES "Debug") + target_compile_options(rccl PRIVATE -fvisibility=default) + else() + target_compile_options(rccl PRIVATE -fvisibility=hidden) + endif() +else() # Enable hidden visibility for library without tests/code coverage enabled + target_compile_options(rccl PRIVATE -fvisibility=hidden) +endif() + if (HAVE_KERNARG_PRELOAD) target_compile_options(rccl PRIVATE -mllvm --amdgpu-kernarg-preload-count=16) endif() diff --git a/install.sh b/install.sh index b72c2eaf97..bdab6c527f 100755 --- a/install.sh +++ b/install.sh @@ -19,6 +19,7 @@ build_tests=false build_verbose=false clean_build=true collective_trace=true +enable_code_coverage=false enable_ninja="" install_dependencies=false install_library=false @@ -43,6 +44,7 @@ function display_help() echo "RCCL build & installation helper script" echo " Options:" echo " --address-sanitizer Build with address sanitizer enabled" + echo " -c|--enable-code-coverage Enable Code Coverage" echo " -d|--dependencies Install RCCL dependencies" echo " --debug Build debug library" echo " --enable_backtrace Build with custom backtrace support" @@ -79,7 +81,7 @@ function display_help() # check if we have a modern version of getopt that can handle whitespace and long parameters getopt -T if [[ "$?" -eq 4 ]]; then - GETOPT_PARSE=$(getopt --name "${0}" --options dfhij:lprt --longoptions address-sanitizer,dependencies,debug,enable_backtrace,disable-colltrace,disable-msccl-kernel,disable-mscclpp,enable-mscclpp-clip,fast,help,install,jobs:,local_gpu_only,amdgpu_targets:,no_clean,npkit-enable,log-trace,openmp-test-enable,roctx-enable,package_build,prefix:,rm-legacy-include-dir,run_tests_all,run_tests_quick,static,tests_build,time-trace,verbose -- "$@") + GETOPT_PARSE=$(getopt --name "${0}" --options cdfhij:lprt --longoptions address-sanitizer,dependencies,debug,enable-code-coverage,enable_backtrace,disable-colltrace,disable-msccl-kernel,disable-mscclpp,fast,help,install,jobs:,local_gpu_only,amdgpu_targets:,no_clean,npkit-enable,log-trace,openmp-test-enable,roctx-enable,package_build,prefix:,rm-legacy-include-dir,run_tests_all,run_tests_quick,static,tests_build,time-trace,verbose -- "$@") else echo "Need a new version of getopt" exit 1 @@ -95,6 +97,7 @@ eval set -- "${GETOPT_PARSE}" while true; do case "${1}" in --address-sanitizer) build_address_sanitizer=true; shift ;; + -c | --enable-code-coverage) enable_code_coverage=true; shift ;; -d | --dependencies) install_dependencies=true; shift ;; --debug) build_release=false; shift ;; --enable_backtrace) build_bfd=true; shift ;; @@ -208,6 +211,11 @@ if [[ "${build_address_sanitizer}" == true ]]; then cmake_common_options="${cmake_common_options} -DBUILD_ADDRESS_SANITIZER=ON" fi +# Enable code coverage +if [[ "${enable_code_coverage}" == true ]]; then + cmake_common_options="${cmake_common_options} -DENABLE_CODE_COVERAGE=ON" +fi + # Backtrace support if [[ "${build_bfd}" == true ]]; then cmake_common_options="${cmake_common_options} -DBUILD_BFD=ON" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8d70fa92e6..794dd8e9b7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -56,9 +56,17 @@ if(BUILD_TESTS) common/TestBed.cpp common/TestBedChild.cpp common/StandaloneUtils.cpp - ../src/misc/recorder.cc ) + # Append a file if BUILD_TESTS is ON and build type is not Debug + # Visibility is hidden by default, so we need to explicitly add the recorder.cc file + # to the unit tests to ensure it is included for unit test execution + if(BUILD_TESTS AND NOT CMAKE_BUILD_TYPE MATCHES "Debug") + list(APPEND TEST_SOURCE_FILES + ../src/misc/recorder.cc + ) + endif() + add_executable(rccl-UnitTests ${TEST_SOURCE_FILES}) ## Set rccl-UnitTests include directories diff --git a/test/_RecorderTests.cpp b/test/_RecorderTests.cpp index 1c6b10d1e5..c80d5b4f72 100644 --- a/test/_RecorderTests.cpp +++ b/test/_RecorderTests.cpp @@ -8,7 +8,7 @@ #include #include "RcclMockFuncs.hpp" -//#include "TestBed.hpp" +#include "comm.h" #include @@ -34,7 +34,7 @@ namespace RcclUnitTesting hipStreamCreate(&stream); int array[] = {2, 3, 5}; - ncclComm comm{.nRanks = 1, .localRank = 1, .localRankToRank = array, .opCount = 8, .planner = {.nTasksColl = 13, .nTasksP2p = 21}}; + ncclComm comm{.nRanks = 1, .localRank = 1, .localRankToRank = array, .opCount = 8, .planner = {.nTasksColl = 13, .nTasksP2p = 21}}; rccl::rcclApiCall call(rccl::rrAllToAllv, {.sendbuff = (void*)0x7f22f9600000, .recvbuff = (void*)0x7f22f9601000, .count = 0, .datatype = ncclFloat32, .comm = &comm, .stream = stream}); rccl::Recorder::instance().record(call); diff --git a/test/common/RcclMockFuncs.hpp b/test/common/RcclMockFuncs.hpp index 302f5a44ab..d19f4bb6a7 100644 --- a/test/common/RcclMockFuncs.hpp +++ b/test/common/RcclMockFuncs.hpp @@ -1,7 +1,11 @@ +#ifndef RCCL_MOCK_FUNCS_HPP +#define RCCL_MOCK_FUNCS_HPP + #include "info.h" -#include "comm.h" void ncclDebugLog(ncclDebugLogLevel, unsigned long, char const*, int, char const*, ...) {}; ncclResult_t getHostName(char* hostname, int maxlen, const char delim) { return ncclSuccess; } + +#endif // RCCL_MOCK_FUNCS_HPP