From 27b6cab8e951c86510ed5667cf4091b577903682 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 26 Oct 2024 02:45:37 +0000 Subject: [PATCH 001/120] First version of new logger --- include/rmm/logger.hpp | 310 ++++++++++++++++++++++++++---------- include/rmm/logger_impl.hpp | 149 +++++++++++++++++ 2 files changed, 373 insertions(+), 86 deletions(-) create mode 100644 include/rmm/logger_impl.hpp diff --git a/include/rmm/logger.hpp b/include/rmm/logger.hpp index eba3f122b..f5ff73f76 100644 --- a/include/rmm/logger.hpp +++ b/include/rmm/logger.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020-2024, NVIDIA CORPORATION. + * Copyright (c) 2024, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,129 +16,267 @@ #pragma once -#include +// TODO: Add RMM_EXPORT tags or equivalent +// TODO: Remove, just here so vim shows everything +#define SUPPORTS_LOGGING +#define LOGGER_NAMESPACE rmm -#include -#include -#include +// TODO: Remove this, right now it's just here so that logger() can return a +// spdlog::logger for backwards-compat testing. #include -#include -#include +#include #include -namespace RMM_NAMESPACE { +namespace LOGGER_NAMESPACE { namespace detail { /** - * @brief Returns the default log filename for the RMM global logger. - * - * If the environment variable `RMM_DEBUG_LOG_FILE` is defined, its value is used as the path and - * name of the log file. Otherwise, the file `rmm_log.txt` in the current working directory is used. - * - * @return std::string The default log file name. + * @class fake_logger_impl + * @brief The fake implementation of the logger that performs no-ops. + * This is the default behavior if real logging is not enabled. */ -inline std::string default_log_filename() -{ - auto* filename = std::getenv("RMM_DEBUG_LOG_FILE"); - return (filename == nullptr) ? std::string{"rmm_log.txt"} : std::string{filename}; -} +class fake_impl { + public: + fake_impl() = default; + + template + void log(Args&&... args) + { + } +}; + +// Forward declaration of the real implementation +struct impl; + +} // namespace detail + +// These defines must be kept in sync with spdlog or bad things will happen! +#define RMM_LEVEL_TRACE 0 +#define RMM_LEVEL_DEBUG 1 +#define RMM_LEVEL_INFO 2 +#define RMM_LEVEL_WARN 3 +#define RMM_LEVEL_ERROR 4 +#define RMM_LEVEL_CRITICAL 5 +#define RMM_LEVEL_OFF 6 + +enum class level_enum : int32_t { + trace = RMM_LEVEL_TRACE, + debug = RMM_LEVEL_DEBUG, + info = RMM_LEVEL_INFO, + warn = RMM_LEVEL_WARN, + error = RMM_LEVEL_ERROR, + critical = RMM_LEVEL_CRITICAL, + off = RMM_LEVEL_OFF, + n_levels +}; /** - * @brief Simple wrapper around a spdlog::logger that performs RMM-specific initialization + * @class logger + * @brief A logger class that either uses the real implementation (via spdlog) or performs no-ops if + * not supported. */ -struct logger_wrapper { - spdlog::logger logger_; ///< The underlying logger - - logger_wrapper() - : logger_{"RMM", - std::make_shared( - default_log_filename(), true // truncate file - )} - { - logger_.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); - logger_.flush_on(spdlog::level::warn); -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO -#ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM - logger_.info("----- RMM LOG BEGIN [PTDS ENABLED] -----"); +class logger { + public: + /** + * @brief Constructor for logger. + * Initializes the logger based on whether logging is supported. + */ +#ifdef SUPPORTS_LOGGING + logger(std::string name, std::string filename); #else - logger_.info("----- RMM LOG BEGIN [PTDS DISABLED] -----"); + logger(std::string name, std::string filename) {} #endif - logger_.flush(); + + // Not default constructible. + inline logger() = delete; + + // TODO: Remove inline, see below + /** + * @brief Destructor for logger. + */ +#ifdef SUPPORTS_LOGGING + inline ~logger(); +#else + inline ~logger() = default; #endif + + /** + * @brief Copy constructor for logger. + */ + logger(logger const&) = delete; + // delete copy assignment operator + logger& operator=(logger const&) = delete; + // TODO: These functions shouldn't be inline, but are for the moment until + // we switch over to a compiled component for the impl. + // default move constructor + inline logger(logger&&) = default; + // default move assignment operator + inline logger& operator=(logger&&) = default; + + template + void log(level_enum lvl, std::string const& format, Args&&... args) + { + auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), args...) + 1); + if (size <= 0) { throw std::runtime_error("Error during formatting."); } + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), args...); + log(lvl, {buf.get(), buf.get() + size - 1}); } -}; -/** - * @brief Represent a size in number of bytes. - */ -struct bytes { - std::size_t value; ///< The size in bytes + // TODO: Remove inline, see above. + inline void log(level_enum lvl, std::string const& message); + + template + void trace(std::string const& format, Args&&... args) + { + log(level_enum::trace, format, std::forward(args)...); + } + + template + void debug(std::string const& format, Args&&... args) + { + log(level_enum::debug, format, std::forward(args)...); + } + + template + void info(std::string const& format, Args&&... args) + { + log(level_enum::info, format, std::forward(args)...); + } + + template + void warn(std::string const& format, Args&&... args) + { + log(level_enum::warn, format, std::forward(args)...); + } + + template + void error(std::string const& format, Args&&... args) + { + log(level_enum::error, format, std::forward(args)...); + } + + template + void critical(std::string const& format, Args&&... args) + { + log(level_enum::critical, format, std::forward(args)...); + } /** - * @brief Construct a new bytes object - * - * @param os The output stream - * @param value The size in bytes + * @brief Check at compile-time whether logging is supported. + * @return `true` if logging is supported, `false` otherwise. */ - friend std::ostream& operator<<(std::ostream& os, bytes const& value) + static constexpr bool supports_logging() { - static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; - - int index = 0; - auto size = static_cast(value.value); - while (size > 1024) { - size /= 1024; - index++; - } - return os << size << ' ' << units.at(index); +#ifdef SUPPORTS_LOGGING + return true; +#else + return false; +#endif } + +// TODO: Make this private once we don't need to access the impl for +// backwards-compat with legacy rmm. +// private: +// TODO: Support args to the impl constructor +#ifdef SUPPORTS_LOGGING + std::unique_ptr pImpl{}; +#else + std::unique_ptr pImpl{}; +#endif }; +namespace detail { + +#ifdef SUPPORTS_LOGGING +inline logger& default_logger(); +#else +inline logger& default_logger() +{ + // This is a no-op so pass empty args. + static class logger logger { + "", "" + }; + return logger; +} +#endif + +// TODO: This only exists for backwards compat and should eventually be removed. +#ifdef SUPPORTS_LOGGING +inline spdlog::logger& logger(); +#else inline spdlog::logger& logger() { - static detail::logger_wrapper wrapped{}; - return wrapped.logger_; + // This branch won't compile. It's not worth supporting since it's not a + // real backwards-compat path. } +#endif + } // namespace detail -/** - * @brief Returns the global RMM logger - * - * @ingroup logging - * - * This is a spdlog logger. The easiest way to log messages is to use the `RMM_LOG_*` macros. - * - * @return spdlog::logger& The logger. - */ +inline logger& default_logger() { return detail::default_logger(); } + [[deprecated( "Support for direct access to spdlog loggers in rmm is planned for " - "removal")]] RMM_EXPORT inline spdlog::logger& + "removal")]] inline spdlog::logger& logger() { return detail::logger(); } -//! @cond Doxygen_Suppress -// -// The default is INFO, but it should be used sparingly, so that by default a log file is only -// output if there is important information, warnings, errors, and critical failures -// Log messages that require computation should only be used at level TRACE and DEBUG -#define RMM_LOG_TRACE(...) SPDLOG_LOGGER_TRACE(&rmm::detail::logger(), __VA_ARGS__) -#define RMM_LOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(&rmm::detail::logger(), __VA_ARGS__) -#define RMM_LOG_INFO(...) SPDLOG_LOGGER_INFO(&rmm::detail::logger(), __VA_ARGS__) -#define RMM_LOG_WARN(...) SPDLOG_LOGGER_WARN(&rmm::detail::logger(), __VA_ARGS__) -#define RMM_LOG_ERROR(...) SPDLOG_LOGGER_ERROR(&rmm::detail::logger(), __VA_ARGS__) -#define RMM_LOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(&rmm::detail::logger(), __VA_ARGS__) +// Macros for easier logging, similar to spdlog. +// TODO: Assumes that we want to respect spdlog's own logging macro settings. +// TODO: We need a way to rename these from RMM to something else. I don't know +// if that can be done in the code, though, and we might have to do it in the +// build system via configure_file. +// TODO: Should we switch this to use _LOGGER_ instead of _LOG_ to match SPDLOG +// instead of rmm? If we do that will be a breaking change for rmm. +// TODO: Should we support other signatures for log? +#define RMM_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) -//! @endcond +// TODO: Need to define our own levels to map to spdlogs. +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE +#define RMM_LOG_TRACE(...) \ + RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::trace, __VA_ARGS__) +#else +#define RMM_LOG_TRACE(...) (void)0 +#endif -} // namespace RMM_NAMESPACE +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +#define RMM_LOG_DEBUG(...) \ + RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::debug, __VA_ARGS__) +#else +#define RMM_LOG_DEBUG(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +#define RMM_LOG_INFO(...) RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::info, __VA_ARGS__) +#else +#define RMM_LOG_INFO(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN +#define RMM_LOG_WARN(...) RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::warn, __VA_ARGS__) +#else +#define RMM_LOG_WARN(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR +#define RMM_LOG_ERROR(...) \ + RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::error, __VA_ARGS__) +#else +#define RMM_LOG_ERROR(...) (void)0 +#endif + +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL +#define RMM_LOG_CRITICAL(...) \ + RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::critical, __VA_ARGS__) +#else +#define RMM_LOG_CRITICAL(...) (void)0 +#endif -// Doxygen doesn't like this because we're overloading something from fmt -//! @cond Doxygen_Suppress -template <> -struct fmt::formatter : fmt::ostream_formatter {}; +} // namespace LOGGER_NAMESPACE -//! @endcond +#include diff --git a/include/rmm/logger_impl.hpp b/include/rmm/logger_impl.hpp new file mode 100644 index 000000000..24fabb8ef --- /dev/null +++ b/include/rmm/logger_impl.hpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024, 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. + */ + +#pragma once + +// TODO: Once we move to proper impl +// #include +#define SUPPORTS_LOGGING + +#ifdef SUPPORTS_LOGGING + +#include +#include +#include +#include + +#include + +namespace LOGGER_NAMESPACE { + +namespace detail { + +/** + * @brief Returns the default log filename for the RMM global logger. + * + * If the environment variable `RAPIDS_DEBUG_LOG_FILE` is defined, its value is used as the path and + * name of the log file. Otherwise, the file `rmm_log.txt` in the current working directory is used. + * + * @return std::string The default log file name. + */ +inline std::string default_log_filename() +{ + auto* filename = std::getenv("RAPIDS_DEBUG_LOG_FILE"); + return (filename == nullptr) ? std::string{"rapids_log.txt"} : std::string{filename}; +} + +/** + * @struct impl + * @brief The real implementation of the logger using spdlog with a basic file sink. + */ +struct impl { + spdlog::logger underlying; ///< spdlog logger instance + + /** + * @brief Constructor for the real implementation of the logger. + * Initializes the logger with a basic file sink. + */ + impl(std::string name, std::string filename) + : underlying{ + name, + std::make_shared(filename, true // truncate file + )} + { + underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); + underlying.flush_on(spdlog::level::warn); + } + + void log(level_enum lvl, const std::string& message) + { + underlying.log(static_cast(static_cast(lvl)), message); + } +}; + +/** + * @brief Represent a size in number of bytes. + */ +struct bytes { + std::size_t value; ///< The size in bytes + + /** + * @brief Construct a new bytes object + * + * @param os The output stream + * @param value The size in bytes + */ + friend std::ostream& operator<<(std::ostream& os, bytes const& value) + { + static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; + + int index = 0; + auto size = static_cast(value.value); + while (size > 1024) { + size /= 1024; + index++; + } + return os << size << ' ' << units.at(index); + } +}; + +} // namespace detail + +// TODO: Probably don't want to default construct here for the underlying spdlog logger. +inline logger::logger(std::string name, std::string filename) + : pImpl{std::make_unique(name, filename)} +{ +} + +inline logger::~logger() = default; + +inline void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } + +// TODO: The detail implementations are just for backwards compat of the spdlog +// version and should be removed. +namespace detail { + +inline class logger& default_logger() +{ + static class logger logger_ = [] { + class logger logger_ { + "RAPIDS", detail::default_log_filename() + }; +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +#ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM + logger_.info("----- RAPIDS LOG BEGIN [PTDS ENABLED] -----"); +#else + logger_.info("----- RAPIDS LOG BEGIN [PTDS DISABLED] -----"); +#endif +#endif + return logger_; + }(); + return logger_; +} + +inline class spdlog::logger& logger() { return default_logger().pImpl->underlying; } + +} // namespace detail + +// TODO: We can't macro this comment, maybe another reason to use configure_file. +} // namespace LOGGER_NAMESPACE + +// Doxygen doesn't like this because we're overloading something from fmt +//! @cond Doxygen_Suppress +template <> +struct fmt::formatter : fmt::ostream_formatter {}; + +#endif From aa92779f0f58b5cf9c2065f9c84ad9c1358dc398 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 26 Oct 2024 03:02:13 +0000 Subject: [PATCH 002/120] Make rmm backwards compat layers explicit --- include/rmm/logger.hpp | 46 ++++++++++++++++++++++++------------- include/rmm/logger_impl.hpp | 18 +++++++++++---- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/include/rmm/logger.hpp b/include/rmm/logger.hpp index f5ff73f76..2129129cc 100644 --- a/include/rmm/logger.hpp +++ b/include/rmm/logger.hpp @@ -14,16 +14,19 @@ * limitations under the License. */ +// TODO: Add RMM_EXPORT tags or equivalent + #pragma once -// TODO: Add RMM_EXPORT tags or equivalent -// TODO: Remove, just here so vim shows everything +// TODO: For convenience, I'm defining all the macros here that we need for vim +// to render the desired bits of code. #define SUPPORTS_LOGGING #define LOGGER_NAMESPACE rmm +#define RMM_BACKWARDS_COMPATIBILITY -// TODO: Remove this, right now it's just here so that logger() can return a -// spdlog::logger for backwards-compat testing. +#ifdef RMM_BACKWARDS_COMPATIBILITY #include +#endif #include #include @@ -90,16 +93,19 @@ class logger { #endif // Not default constructible. - inline logger() = delete; + logger() = delete; - // TODO: Remove inline, see below /** * @brief Destructor for logger. */ #ifdef SUPPORTS_LOGGING +#ifdef RMM_BACKWARDS_COMPATIBILITY inline ~logger(); #else - inline ~logger() = default; + ~logger(); +#endif +#else + ~logger() = default; #endif /** @@ -108,12 +114,10 @@ class logger { logger(logger const&) = delete; // delete copy assignment operator logger& operator=(logger const&) = delete; - // TODO: These functions shouldn't be inline, but are for the moment until - // we switch over to a compiled component for the impl. // default move constructor - inline logger(logger&&) = default; + logger(logger&&) = default; // default move assignment operator - inline logger& operator=(logger&&) = default; + logger& operator=(logger&&) = default; template void log(level_enum lvl, std::string const& format, Args&&... args) @@ -125,8 +129,11 @@ class logger { log(lvl, {buf.get(), buf.get() + size - 1}); } - // TODO: Remove inline, see above. +#ifdef RMM_BACKWARDS_COMPATIBILITY inline void log(level_enum lvl, std::string const& message); +#else + void log(level_enum lvl, std::string const& message); +#endif template void trace(std::string const& format, Args&&... args) @@ -177,9 +184,9 @@ class logger { #endif } -// TODO: Make this private once we don't need to access the impl for -// backwards-compat with legacy rmm. -// private: +#ifndef RMM_BACKWARDS_COMPATIBILITY + private: +#endif // TODO: Support args to the impl constructor #ifdef SUPPORTS_LOGGING std::unique_ptr pImpl{}; @@ -190,6 +197,7 @@ class logger { namespace detail { +#ifdef RMM_BACKWARDS_COMPATIBILITY #ifdef SUPPORTS_LOGGING inline logger& default_logger(); #else @@ -203,7 +211,6 @@ inline logger& default_logger() } #endif -// TODO: This only exists for backwards compat and should eventually be removed. #ifdef SUPPORTS_LOGGING inline spdlog::logger& logger(); #else @@ -213,9 +220,11 @@ inline spdlog::logger& logger() // real backwards-compat path. } #endif +#endif } // namespace detail +#ifdef RMM_BACKWARDS_COMPATIBILITY inline logger& default_logger() { return detail::default_logger(); } [[deprecated( @@ -225,6 +234,9 @@ logger() { return detail::logger(); } +#else +// TODO: Move the detail implementation of default_logger here. +#endif // Macros for easier logging, similar to spdlog. // TODO: Assumes that we want to respect spdlog's own logging macro settings. @@ -279,4 +291,6 @@ logger() } // namespace LOGGER_NAMESPACE +#ifdef RMM_BACKWARDS_COMPATIBILITY #include +#endif diff --git a/include/rmm/logger_impl.hpp b/include/rmm/logger_impl.hpp index 24fabb8ef..f23d0500f 100644 --- a/include/rmm/logger_impl.hpp +++ b/include/rmm/logger_impl.hpp @@ -16,10 +16,19 @@ #pragma once -// TODO: Once we move to proper impl -// #include +// TODO: For convenience, I'm defining all the macros here that we need for vim +// to render the desired bits of code. #define SUPPORTS_LOGGING +#define LOGGER_NAMESPACE rmm +#define RMM_BACKWARDS_COMPATIBILITY +// We'll flip the include once this +#ifndef RMM_BACKWARDS_COMPATIBILITY +#include +#endif + +// In the long run this shouldn't be necessary because the file will only be +// compiled if SUPPORTS_LOGGING is enabled. #ifdef SUPPORTS_LOGGING #include @@ -102,7 +111,6 @@ struct bytes { } // namespace detail -// TODO: Probably don't want to default construct here for the underlying spdlog logger. inline logger::logger(std::string name, std::string filename) : pImpl{std::make_unique(name, filename)} { @@ -112,8 +120,7 @@ inline logger::~logger() = default; inline void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } -// TODO: The detail implementations are just for backwards compat of the spdlog -// version and should be removed. +#ifdef RMM_BACKWARDS_COMPATIBILITY namespace detail { inline class logger& default_logger() @@ -137,6 +144,7 @@ inline class logger& default_logger() inline class spdlog::logger& logger() { return default_logger().pImpl->underlying; } } // namespace detail +#endif // TODO: We can't macro this comment, maybe another reason to use configure_file. } // namespace LOGGER_NAMESPACE From 812b2bc78502a3c659a4d89ae1e29868c6a7a286 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 26 Oct 2024 16:23:55 +0000 Subject: [PATCH 003/120] Move logger to its own directory --- include/rmm/logger.hpp => rapids_logger/logger.hpp.in | 0 include/rmm/logger_impl.hpp => rapids_logger/logger_impl.hpp.in | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename include/rmm/logger.hpp => rapids_logger/logger.hpp.in (100%) rename include/rmm/logger_impl.hpp => rapids_logger/logger_impl.hpp.in (100%) diff --git a/include/rmm/logger.hpp b/rapids_logger/logger.hpp.in similarity index 100% rename from include/rmm/logger.hpp rename to rapids_logger/logger.hpp.in diff --git a/include/rmm/logger_impl.hpp b/rapids_logger/logger_impl.hpp.in similarity index 100% rename from include/rmm/logger_impl.hpp rename to rapids_logger/logger_impl.hpp.in From 956fa3f8742814390a44b2449b8e020938143bdc Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 26 Oct 2024 17:12:18 +0000 Subject: [PATCH 004/120] Set up basics of file generation --- CMakeLists.txt | 13 ++++++++-- rapids_logger/CMakeLists.txt | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 rapids_logger/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 26fcf1fd0..654e9dd12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,11 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) +if(NOT RMM_GENERATED_INCLUDE_DIR) + set(RMM_GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") +endif() +add_subdirectory(rapids_logger) + # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- @@ -84,8 +89,12 @@ include(cmake/thirdparty/get_nvtx.cmake) add_library(rmm INTERFACE) add_library(rmm::rmm ALIAS rmm) -target_include_directories(rmm INTERFACE "$" - "$") +target_include_directories( + rmm + INTERFACE "$" + # TODO: This should be handled by the generated target. + "$" + "$") if(CUDA_STATIC_RUNTIME) message(STATUS "RMM: Enabling static linking of cudart") diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt new file mode 100644 index 000000000..d7c63d21d --- /dev/null +++ b/rapids_logger/CMakeLists.txt @@ -0,0 +1,48 @@ +# ============================================================================= +# Copyright (c) 2024, 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: Should this have a full CMakeLists capable of being built by itself, or should it assume +# that it's always being called from another CMakeLists? cmake_minimum_required(VERSION 3.26.4 +# FATAL_ERROR) +# +# include(../rapids_config.cmake) +# +# include(rapids-cmake) include(rapids-cpm) +# +# project( RAPIDS_LOGGER VERSION 0.0.1 LANGUAGES CXX) +# +# rapids_cmake_write_version_file(include/rmm/version_config.hpp) rapids_cmake_build_type(Release) +# +# option(SUPPORTS_LOGGING "Whether to build with real logging support or not" OFF) +# option(RMM_BACKWARDS_COMPATIBILITY "Enable backwards compatibility with the legacy RMM logger" +# OFF) TODO: Change the default to rapids set(LOGGER_NAMESPACE rmm CACHE STRING "The namespace to +# use for the logger") +# +# message(VERBOSE "RMM: Build with NVTX support: ${RMM_NVTX}") +# +# rapids_cpm_init() +# +# Make sure install logic is handled correctly, namely that nothing is installed from these. I think +# we'll need to both not specify an export set and EXCLUDE_FROM_ALL. +# include(../cmake/thirdparty/get_fmt.cmake) include(../cmake/thirdparty/get_spdlog.cmake) + +# TODO: Make the dir configurable +set(LOGGER_OUTPUT_DIR ${RMM_BINARY_DIR}/include/rmm) +set(LOGGER_OUTPUT_FILE ${LOGGER_OUTPUT_DIR}/logger.hpp) +configure_file(logger.hpp.in ${LOGGER_OUTPUT_FILE}) +install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION include/rmm) + +set(LOGGER_IMPL_OUTPUT_FILE ${LOGGER_OUTPUT_DIR}/logger_impl.hpp) +configure_file(logger_impl.hpp.in ${LOGGER_IMPL_OUTPUT_FILE}) +install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION include/rmm) From 3a6d49b4524b5c20faa2ff50d57435aa15751960 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 27 Oct 2024 15:41:58 +0000 Subject: [PATCH 005/120] Convert to a function --- CMakeLists.txt | 1 + rapids_logger/CMakeLists.txt | 27 ++++++++---- rapids_logger/logger.hpp.in | 70 +++++++++++++++----------------- rapids_logger/logger_impl.hpp.in | 6 +-- 4 files changed, 55 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 654e9dd12..2f0ff4ccd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ if(NOT RMM_GENERATED_INCLUDE_DIR) set(RMM_GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") endif() add_subdirectory(rapids_logger) +rapids_make_logger(LOGGER_HEADER_DIR include/rmm LOGGER_NAMESPACE rmm LOGGER_MACRO_PREFIX RMM) # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index d7c63d21d..35fdb8f0c 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -37,12 +37,23 @@ # we'll need to both not specify an export set and EXCLUDE_FROM_ALL. # include(../cmake/thirdparty/get_fmt.cmake) include(../cmake/thirdparty/get_spdlog.cmake) -# TODO: Make the dir configurable -set(LOGGER_OUTPUT_DIR ${RMM_BINARY_DIR}/include/rmm) -set(LOGGER_OUTPUT_FILE ${LOGGER_OUTPUT_DIR}/logger.hpp) -configure_file(logger.hpp.in ${LOGGER_OUTPUT_FILE}) -install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION include/rmm) +# Generate and install the logger files +function(rapids_make_logger) + list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") -set(LOGGER_IMPL_OUTPUT_FILE ${LOGGER_OUTPUT_DIR}/logger_impl.hpp) -configure_file(logger_impl.hpp.in ${LOGGER_IMPL_OUTPUT_FILE}) -install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION include/rmm) + set(_rapids_options) + set(_rapids_one_value LOGGER_HEADER_DIR LOGGER_NAMESPACE LOGGER_MACRO_PREFIX) + set(_rapids_multi_value) + cmake_parse_arguments(_RAPIDS "${_rapids_options}" "${_rapids_one_value}" + "${_rapids_multi_value}" ${ARGN}) + + # TODO: If we make rapids_logger its own project then PROJECT_BINARY_DIR won't be quite right, + # we'll have to get it from the top-level project. + set(LOGGER_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}/logger.hpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${LOGGER_OUTPUT_FILE}) + install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION ${_RAPIDS_LOGGER_HEADER_DIR}) + + set(LOGGER_IMPL_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}/logger_impl.hpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in ${LOGGER_IMPL_OUTPUT_FILE}) + install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION ${_RAPIDS_LOGGER_HEADER_DIR}) +endfunction() diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 2129129cc..1dc7851d4 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -21,7 +21,6 @@ // TODO: For convenience, I'm defining all the macros here that we need for vim // to render the desired bits of code. #define SUPPORTS_LOGGING -#define LOGGER_NAMESPACE rmm #define RMM_BACKWARDS_COMPATIBILITY #ifdef RMM_BACKWARDS_COMPATIBILITY @@ -31,7 +30,7 @@ #include #include -namespace LOGGER_NAMESPACE { +namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { @@ -56,22 +55,22 @@ struct impl; } // namespace detail // These defines must be kept in sync with spdlog or bad things will happen! -#define RMM_LEVEL_TRACE 0 -#define RMM_LEVEL_DEBUG 1 -#define RMM_LEVEL_INFO 2 -#define RMM_LEVEL_WARN 3 -#define RMM_LEVEL_ERROR 4 -#define RMM_LEVEL_CRITICAL 5 -#define RMM_LEVEL_OFF 6 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE 0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG 1 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_INFO 2 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_WARN 3 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_ERROR 4 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_CRITICAL 5 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_OFF 6 enum class level_enum : int32_t { - trace = RMM_LEVEL_TRACE, - debug = RMM_LEVEL_DEBUG, - info = RMM_LEVEL_INFO, - warn = RMM_LEVEL_WARN, - error = RMM_LEVEL_ERROR, - critical = RMM_LEVEL_CRITICAL, - off = RMM_LEVEL_OFF, + trace = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE, + debug = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG, + info = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_INFO, + warn = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_WARN, + error = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_ERROR, + critical = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_CRITICAL, + off = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_OFF, n_levels }; @@ -240,9 +239,6 @@ logger() // Macros for easier logging, similar to spdlog. // TODO: Assumes that we want to respect spdlog's own logging macro settings. -// TODO: We need a way to rename these from RMM to something else. I don't know -// if that can be done in the code, though, and we might have to do it in the -// build system via configure_file. // TODO: Should we switch this to use _LOGGER_ instead of _LOG_ to match SPDLOG // instead of rmm? If we do that will be a breaking change for rmm. // TODO: Should we support other signatures for log? @@ -250,47 +246,47 @@ logger() // TODO: Need to define our own levels to map to spdlogs. #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE -#define RMM_LOG_TRACE(...) \ - RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::trace, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_TRACE(...) \ + @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::trace, __VA_ARGS__) #else -#define RMM_LOG_TRACE(...) (void)0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_TRACE(...) (void)0 #endif #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG -#define RMM_LOG_DEBUG(...) \ - RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::debug, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_DEBUG(...) \ + @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::debug, __VA_ARGS__) #else -#define RMM_LOG_DEBUG(...) (void)0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_DEBUG(...) (void)0 #endif #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO -#define RMM_LOG_INFO(...) RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::info, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_INFO(...) @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::info, __VA_ARGS__) #else -#define RMM_LOG_INFO(...) (void)0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_INFO(...) (void)0 #endif #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN -#define RMM_LOG_WARN(...) RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::warn, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_WARN(...) @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::warn, __VA_ARGS__) #else -#define RMM_LOG_WARN(...) (void)0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_WARN(...) (void)0 #endif #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR -#define RMM_LOG_ERROR(...) \ - RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::error, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ERROR(...) \ + @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::error, __VA_ARGS__) #else -#define RMM_LOG_ERROR(...) (void)0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ERROR(...) (void)0 #endif #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL -#define RMM_LOG_CRITICAL(...) \ - RMM_LOGGER_CALL(rmm::default_logger(), rmm::level_enum::critical, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_CRITICAL(...) \ + @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::critical, __VA_ARGS__) #else -#define RMM_LOG_CRITICAL(...) (void)0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_CRITICAL(...) (void)0 #endif -} // namespace LOGGER_NAMESPACE +} // namespace @_RAPIDS_LOGGER_NAMESPACE@ -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY #include #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index f23d0500f..12a0db0a6 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -19,7 +19,6 @@ // TODO: For convenience, I'm defining all the macros here that we need for vim // to render the desired bits of code. #define SUPPORTS_LOGGING -#define LOGGER_NAMESPACE rmm #define RMM_BACKWARDS_COMPATIBILITY // We'll flip the include once this @@ -38,7 +37,7 @@ #include -namespace LOGGER_NAMESPACE { +namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { @@ -146,8 +145,7 @@ inline class spdlog::logger& logger() { return default_logger().pImpl->underlyin } // namespace detail #endif -// TODO: We can't macro this comment, maybe another reason to use configure_file. -} // namespace LOGGER_NAMESPACE +} // namespace @_RAPIDS_LOGGER_NAMESPACE@ // Doxygen doesn't like this because we're overloading something from fmt //! @cond Doxygen_Suppress From c9ec22cc940941259d0780a0937cf0e8b9dadfce Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 27 Oct 2024 16:41:48 +0000 Subject: [PATCH 006/120] Switch to using a target --- CMakeLists.txt | 16 +++++------- rapids_logger/CMakeLists.txt | 47 +++++++++++++++++++++++++++++------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f0ff4ccd..445a8dbb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,11 +58,10 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -if(NOT RMM_GENERATED_INCLUDE_DIR) - set(RMM_GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include") -endif() add_subdirectory(rapids_logger) -rapids_make_logger(LOGGER_HEADER_DIR include/rmm LOGGER_NAMESPACE rmm LOGGER_MACRO_PREFIX RMM) +rapids_make_logger( + LOGGER_TARGET rmm_logger LOGGER_HEADER_DIR include/rmm LOGGER_NAMESPACE rmm LOGGER_MACRO_PREFIX + RMM BUILD_EXPORT_SET rmm-exports INSTALL_EXPORT_SET rmm-exports CMAKE_NAMESPACE rmm::) # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- @@ -90,12 +89,8 @@ include(cmake/thirdparty/get_nvtx.cmake) add_library(rmm INTERFACE) add_library(rmm::rmm ALIAS rmm) -target_include_directories( - rmm - INTERFACE "$" - # TODO: This should be handled by the generated target. - "$" - "$") +target_include_directories(rmm INTERFACE "$" + "$") if(CUDA_STATIC_RUNTIME) message(STATUS "RMM: Enabling static linking of cudart") @@ -105,6 +100,7 @@ else() target_link_libraries(rmm INTERFACE CUDA::cudart) endif() +target_link_libraries(rmm INTERFACE rmm_logger) target_link_libraries(rmm INTERFACE CCCL::CCCL) target_link_libraries(rmm INTERFACE fmt::fmt-header-only) target_link_libraries(rmm INTERFACE spdlog::spdlog_header_only) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 35fdb8f0c..18310746e 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -42,18 +42,47 @@ function(rapids_make_logger) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") set(_rapids_options) - set(_rapids_one_value LOGGER_HEADER_DIR LOGGER_NAMESPACE LOGGER_MACRO_PREFIX) + # TODO: Check for required options + set(_rapids_one_value BUILD_EXPORT_SET INSTALL_EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR + LOGGER_NAMESPACE LOGGER_MACRO_PREFIX CMAKE_NAMESPACE) set(_rapids_multi_value) cmake_parse_arguments(_RAPIDS "${_rapids_options}" "${_rapids_one_value}" "${_rapids_multi_value}" ${ARGN}) - # TODO: If we make rapids_logger its own project then PROJECT_BINARY_DIR won't be quite right, - # we'll have to get it from the top-level project. - set(LOGGER_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}/logger.hpp) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${LOGGER_OUTPUT_FILE}) - install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION ${_RAPIDS_LOGGER_HEADER_DIR}) + # All paths are computed relative to the current source/binary dir of the file from which the + # function is invoked. As a result we cannot use relative paths here because CMake will root these + # paths incorrectly for configure_file/install. + set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}) + set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${_RAPIDS_LOGGER_HEADER_DIR}) - set(LOGGER_IMPL_OUTPUT_FILE ${PROJECT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}/logger_impl.hpp) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in ${LOGGER_IMPL_OUTPUT_FILE}) - install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION ${_RAPIDS_LOGGER_HEADER_DIR}) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${BUILD_DIR}/logger.hpp) + install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}) + + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in ${BUILD_DIR}/logger_impl.hpp) + install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}) + + add_library(${_RAPIDS_LOGGER_TARGET} INTERFACE) + include(GNUInstallDirs) + # Note: The BUILD_INTERFACE setting assumes that LOGGER_HEADER_DIR is the subdirectory of + # CMAKE_INSTALL_INCLUDEDIR relative to which all includes are rooted in the C++ code files. I + # think that is a safe assumption though since if it were violated then the INSTALL_INTERFACE + # would not only be incorrect (if computed using LOGGER_HEADER_DIR), but it would also break + # consumers of the installed package who expect to be able to write `#include + # <${LOGGER_HEADER_DIR/include\//}/logger.hpp>` and have it work. + target_include_directories( + ${_RAPIDS_LOGGER_TARGET} + INTERFACE "$" + "$") + if(_RAPIDS_LOGGER_CMAKE_NAMESPACE) + set(CMAKE_NAMESPACE "NAMESPACE ${_RAPIDS_LOGGER_CMAKE_NAMESPACE}") + endif() + if(_RAPIDS_INSTALL_EXPORT_SET) + install( + TARGETS ${_RAPIDS_LOGGER_TARGET} + EXPORT ${_RAPIDS_INSTALL_EXPORT_SET} + ${CMAKE_NAMESPACE}) + endif() + if(_RAPIDS_BUILD_EXPORT_SET) + export(EXPORT ${_RAPIDS_BUILD_EXPORT_SET} ${CMAKE_NAMESPACE}) + endif() endfunction() From 2573e02915ae44310d5e1da58c27a616733a79c0 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 27 Oct 2024 17:36:45 +0000 Subject: [PATCH 007/120] Make rmm compatibility and logging support controllable via CMake --- CMakeLists.txt | 20 ++++++++++++++++++-- rapids_logger/CMakeLists.txt | 9 ++++++++- rapids_logger/logger.hpp.in | 5 ----- rapids_logger/logger_impl.hpp.in | 5 ----- 4 files changed, 26 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 445a8dbb4..a0f2ff2e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,8 +60,24 @@ option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) add_subdirectory(rapids_logger) rapids_make_logger( - LOGGER_TARGET rmm_logger LOGGER_HEADER_DIR include/rmm LOGGER_NAMESPACE rmm LOGGER_MACRO_PREFIX - RMM BUILD_EXPORT_SET rmm-exports INSTALL_EXPORT_SET rmm-exports CMAKE_NAMESPACE rmm::) + LOGGER_TARGET + rmm_logger + LOGGER_HEADER_DIR + include/rmm + LOGGER_NAMESPACE + rmm + LOGGER_MACRO_PREFIX + RMM + BUILD_EXPORT_SET + rmm-exports + INSTALL_EXPORT_SET + rmm-exports + CMAKE_NAMESPACE + rmm:: + # TODO: Make this configurable in rmm. Once we switch fully over to the new implementation, the + # default here should be off, but turning it on should activate the compilation of a separate TU. + SUPPORTS_LOGGING + RMM_BACKWARDS_COMPATIBILITY) # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 18310746e..e10a89a52 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -41,7 +41,7 @@ function(rapids_make_logger) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") - set(_rapids_options) + set(_rapids_options RMM_BACKWARDS_COMPATIBILITY SUPPORTS_LOGGING) # TODO: Check for required options set(_rapids_one_value BUILD_EXPORT_SET INSTALL_EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_NAMESPACE LOGGER_MACRO_PREFIX CMAKE_NAMESPACE) @@ -73,6 +73,13 @@ function(rapids_make_logger) ${_RAPIDS_LOGGER_TARGET} INTERFACE "$" "$") + if(_RAPIDS_RMM_BACKWARDS_COMPATIBILITY) + target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE RMM_BACKWARDS_COMPATIBILITY) + endif() + if(_RAPIDS_SUPPORTS_LOGGING) + target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE SUPPORTS_LOGGING) + endif() + if(_RAPIDS_LOGGER_CMAKE_NAMESPACE) set(CMAKE_NAMESPACE "NAMESPACE ${_RAPIDS_LOGGER_CMAKE_NAMESPACE}") endif() diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 1dc7851d4..1f4c1e8de 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -18,11 +18,6 @@ #pragma once -// TODO: For convenience, I'm defining all the macros here that we need for vim -// to render the desired bits of code. -#define SUPPORTS_LOGGING -#define RMM_BACKWARDS_COMPATIBILITY - #ifdef RMM_BACKWARDS_COMPATIBILITY #include #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 12a0db0a6..2228fb4ba 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -16,11 +16,6 @@ #pragma once -// TODO: For convenience, I'm defining all the macros here that we need for vim -// to render the desired bits of code. -#define SUPPORTS_LOGGING -#define RMM_BACKWARDS_COMPATIBILITY - // We'll flip the include once this #ifndef RMM_BACKWARDS_COMPATIBILITY #include From 917310830320e471dc36e48c450e2899f1f933a0 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 31 Oct 2024 21:51:30 +0000 Subject: [PATCH 008/120] Hide impl one level down --- rapids_logger/CMakeLists.txt | 5 +++-- rapids_logger/logger.hpp.in | 8 ++------ rapids_logger/logger_impl.hpp.in | 10 +++++----- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index e10a89a52..e4b6d9f97 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -58,8 +58,9 @@ function(rapids_make_logger) configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${BUILD_DIR}/logger.hpp) install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in ${BUILD_DIR}/logger_impl.hpp) - install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in + ${BUILD_DIR}/logger_impl/logger_impl.hpp) + install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) add_library(${_RAPIDS_LOGGER_TARGET} INTERFACE) include(GNUInstallDirs) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 1f4c1e8de..029fa51ca 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -233,13 +233,9 @@ logger() #endif // Macros for easier logging, similar to spdlog. -// TODO: Assumes that we want to respect spdlog's own logging macro settings. -// TODO: Should we switch this to use _LOGGER_ instead of _LOG_ to match SPDLOG -// instead of rmm? If we do that will be a breaking change for rmm. -// TODO: Should we support other signatures for log? +// TODO: Assumes that we want to respect spdlog's own logging macro level settings. #define RMM_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) -// TODO: Need to define our own levels to map to spdlogs. #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_TRACE(...) \ @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::trace, __VA_ARGS__) @@ -283,5 +279,5 @@ logger() } // namespace @_RAPIDS_LOGGER_NAMESPACE@ #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY -#include +#include "logger_impl/logger_impl.hpp" #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 2228fb4ba..3c7b43e21 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -18,7 +18,7 @@ // We'll flip the include once this #ifndef RMM_BACKWARDS_COMPATIBILITY -#include +#include "../logger.hpp" #endif // In the long run this shouldn't be necessary because the file will only be @@ -40,14 +40,14 @@ namespace detail { * @brief Returns the default log filename for the RMM global logger. * * If the environment variable `RAPIDS_DEBUG_LOG_FILE` is defined, its value is used as the path and - * name of the log file. Otherwise, the file `rmm_log.txt` in the current working directory is used. + * name of the log file. Otherwise, the file `@_RAPIDS_LOGGER_NAMESPACE@_log.txt` in the current working directory is used. * * @return std::string The default log file name. */ inline std::string default_log_filename() { - auto* filename = std::getenv("RAPIDS_DEBUG_LOG_FILE"); - return (filename == nullptr) ? std::string{"rapids_log.txt"} : std::string{filename}; + auto* filename = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEBUG_LOG_FILE"); + return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; } /** @@ -145,6 +145,6 @@ inline class spdlog::logger& logger() { return default_logger().pImpl->underlyin // Doxygen doesn't like this because we're overloading something from fmt //! @cond Doxygen_Suppress template <> -struct fmt::formatter : fmt::ostream_formatter {}; +struct fmt::formatter<@_RAPIDS_LOGGER_NAMESPACE@::detail::bytes> : fmt::ostream_formatter {}; #endif From d89bb82efc36913eed13c070e685aaa3eadbc058 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 00:10:42 +0000 Subject: [PATCH 009/120] Make rapids_logger a CMake package --- CMakeLists.txt | 34 ++++++++++++++---------------- rapids_logger/CMakeLists.txt | 40 ++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0f2ff2e6..8f1adf8d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,21 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) +# ################################################################################################## +# * compiler options ------------------------------------------------------------------------------- + +# find packages we depend on +rapids_find_package( + CUDAToolkit REQUIRED + BUILD_EXPORT_SET rmm-exports + INSTALL_EXPORT_SET rmm-exports) + +# ################################################################################################## +# * dependencies ----------------------------------------------------------------------------------- + +# add third party dependencies using CPM +rapids_cpm_init() + add_subdirectory(rapids_logger) rapids_make_logger( LOGGER_TARGET @@ -74,28 +89,9 @@ rapids_make_logger( rmm-exports CMAKE_NAMESPACE rmm:: - # TODO: Make this configurable in rmm. Once we switch fully over to the new implementation, the - # default here should be off, but turning it on should activate the compilation of a separate TU. SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) -# ################################################################################################## -# * compiler options ------------------------------------------------------------------------------- - -# find packages we depend on -rapids_find_package( - CUDAToolkit REQUIRED - BUILD_EXPORT_SET rmm-exports - INSTALL_EXPORT_SET rmm-exports) - -# ################################################################################################## -# * dependencies ----------------------------------------------------------------------------------- - -# add third party dependencies using CPM -rapids_cpm_init() - -include(cmake/thirdparty/get_fmt.cmake) -include(cmake/thirdparty/get_spdlog.cmake) include(cmake/thirdparty/get_cccl.cmake) include(cmake/thirdparty/get_nvtx.cmake) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index e4b6d9f97..1a1e9bff8 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -12,30 +12,26 @@ # the License. # ============================================================================= -# TODO: Should this have a full CMakeLists capable of being built by itself, or should it assume -# that it's always being called from another CMakeLists? cmake_minimum_required(VERSION 3.26.4 -# FATAL_ERROR) -# -# include(../rapids_config.cmake) -# -# include(rapids-cmake) include(rapids-cpm) -# -# project( RAPIDS_LOGGER VERSION 0.0.1 LANGUAGES CXX) -# -# rapids_cmake_write_version_file(include/rmm/version_config.hpp) rapids_cmake_build_type(Release) -# -# option(SUPPORTS_LOGGING "Whether to build with real logging support or not" OFF) -# option(RMM_BACKWARDS_COMPATIBILITY "Enable backwards compatibility with the legacy RMM logger" -# OFF) TODO: Change the default to rapids set(LOGGER_NAMESPACE rmm CACHE STRING "The namespace to -# use for the logger") -# -# message(VERBOSE "RMM: Build with NVTX support: ${RMM_NVTX}") -# -# rapids_cpm_init() -# +cmake_minimum_required(VERSION 3.26.4 FATAL_ERROR) + +include(../rapids_config.cmake) + +include(rapids-cmake) +include(rapids-cpm) + +project( + RAPIDS_LOGGER + VERSION 0.0.1 + LANGUAGES CXX) + +rapids_cmake_build_type(Release) + +rapids_cpm_init() + # Make sure install logic is handled correctly, namely that nothing is installed from these. I think # we'll need to both not specify an export set and EXCLUDE_FROM_ALL. -# include(../cmake/thirdparty/get_fmt.cmake) include(../cmake/thirdparty/get_spdlog.cmake) +include(../cmake/thirdparty/get_fmt.cmake) +include(../cmake/thirdparty/get_spdlog.cmake) # Generate and install the logger files function(rapids_make_logger) From 07dfcc569487400acf54cd2fb280f395cd083d77 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 00:30:53 +0000 Subject: [PATCH 010/120] Fix install rules --- rapids_logger/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 1a1e9bff8..042fe24ef 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -51,11 +51,12 @@ function(rapids_make_logger) set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}) set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${_RAPIDS_LOGGER_HEADER_DIR}) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${BUILD_DIR}/logger.hpp) + set(LOGGER_OUTPUT_FILE ${BUILD_DIR}/logger.hpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${LOGGER_OUTPUT_FILE}) install(FILES ${LOGGER_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in - ${BUILD_DIR}/logger_impl/logger_impl.hpp) + set(LOGGER_IMPL_OUTPUT_FILE ${BUILD_DIR}/logger_impl/logger_impl.hpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger_impl.hpp.in ${LOGGER_IMPL_OUTPUT_FILE}) install(FILES ${LOGGER_IMPL_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) add_library(${_RAPIDS_LOGGER_TARGET} INTERFACE) From 819499769a4e2dae06e402122edee94e435d08ba Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 19:01:11 +0000 Subject: [PATCH 011/120] Switch arena to delegating constructor for simplicity --- include/rmm/mr/device/arena_memory_resource.hpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/include/rmm/mr/device/arena_memory_resource.hpp b/include/rmm/mr/device/arena_memory_resource.hpp index 9b380ffb9..3428e9c8f 100644 --- a/include/rmm/mr/device/arena_memory_resource.hpp +++ b/include/rmm/mr/device/arena_memory_resource.hpp @@ -119,17 +119,9 @@ class arena_memory_resource final : public device_memory_resource { explicit arena_memory_resource(Upstream* upstream_mr, std::optional arena_size = std::nullopt, bool dump_log_on_failure = false) - : global_arena_{to_device_async_resource_ref_checked(upstream_mr), arena_size}, - dump_log_on_failure_{dump_log_on_failure} + : arena_memory_resource{ + to_device_async_resource_ref_checked(upstream_mr), arena_size, dump_log_on_failure} { - if (dump_log_on_failure_) { - logger_ = - std::make_shared("arena_memory_dump", - std::make_shared( - "rmm_arena_memory_dump.log", true /*truncate file*/)); - // Set the level to `debug` for more detailed output. - logger_->set_level(spdlog::level::info); - } } ~arena_memory_resource() override = default; From 8589c53335c7655846d9026e4cbf14ef59f18d1e Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 19:18:42 +0000 Subject: [PATCH 012/120] Clean up some conditional compilation --- rapids_logger/logger.hpp.in | 32 ++------------------------------ rapids_logger/logger_impl.hpp.in | 4 ++++ 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 029fa51ca..fb7d36b4a 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -93,11 +93,7 @@ class logger { * @brief Destructor for logger. */ #ifdef SUPPORTS_LOGGING -#ifdef RMM_BACKWARDS_COMPATIBILITY inline ~logger(); -#else - ~logger(); -#endif #else ~logger() = default; #endif @@ -109,9 +105,9 @@ class logger { // delete copy assignment operator logger& operator=(logger const&) = delete; // default move constructor - logger(logger&&) = default; + inline logger(logger&&); // default move assignment operator - logger& operator=(logger&&) = default; + inline logger& operator=(logger&&); template void log(level_enum lvl, std::string const& format, Args&&... args) @@ -123,11 +119,7 @@ class logger { log(lvl, {buf.get(), buf.get() + size - 1}); } -#ifdef RMM_BACKWARDS_COMPATIBILITY inline void log(level_enum lvl, std::string const& message); -#else - void log(level_enum lvl, std::string const& message); -#endif template void trace(std::string const& format, Args&&... args) @@ -192,28 +184,8 @@ class logger { namespace detail { #ifdef RMM_BACKWARDS_COMPATIBILITY -#ifdef SUPPORTS_LOGGING inline logger& default_logger(); -#else -inline logger& default_logger() -{ - // This is a no-op so pass empty args. - static class logger logger { - "", "" - }; - return logger; -} -#endif - -#ifdef SUPPORTS_LOGGING inline spdlog::logger& logger(); -#else -inline spdlog::logger& logger() -{ - // This branch won't compile. It's not worth supporting since it's not a - // real backwards-compat path. -} -#endif #endif } // namespace detail diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 3c7b43e21..10b168ee4 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -105,12 +105,16 @@ struct bytes { } // namespace detail +// TODO: Many of the inline and class keywords are likely unnecessary in the +// non-backwards compatibility version. inline logger::logger(std::string name, std::string filename) : pImpl{std::make_unique(name, filename)} { } inline logger::~logger() = default; +inline logger::logger(logger&&) = default; +inline class logger& logger::operator=(logger&&) = default; inline void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } From f4f83509805a7792acb710b3a8452298a45590a0 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 19:33:44 +0000 Subject: [PATCH 013/120] Move some functions out of the impl --- rapids_logger/logger.hpp.in | 58 +++++++++++++++++++++++++++++++- rapids_logger/logger_impl.hpp.in | 40 ---------------------- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index fb7d36b4a..ee643c36e 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -29,6 +29,46 @@ namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { +/** + * @brief Returns the default log filename for the RMM global logger. + * + * If the environment variable `RAPIDS_DEBUG_LOG_FILE` is defined, its value is used as the path and + * name of the log file. Otherwise, the file `@_RAPIDS_LOGGER_NAMESPACE@_log.txt` in the current working directory is used. + * + * @return std::string The default log file name. + */ +inline std::string default_log_filename() +{ + auto* filename = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEBUG_LOG_FILE"); + return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; +} + +/** + * @brief Represent a size in number of bytes. + */ +struct bytes { + std::size_t value; ///< The size in bytes + + /** + * @brief Construct a new bytes object + * + * @param os The output stream + * @param value The size in bytes + */ + friend std::ostream& operator<<(std::ostream& os, bytes const& value) + { + static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; + + int index = 0; + auto size = static_cast(value.value); + while (size > 1024) { + size /= 1024; + index++; + } + return os << size << ' ' << units.at(index); + } +}; + /** * @class fake_logger_impl * @brief The fake implementation of the logger that performs no-ops. @@ -201,7 +241,23 @@ logger() return detail::logger(); } #else -// TODO: Move the detail implementation of default_logger here. +inline logger& default_logger() +{ + static logger logger_ = [] { + logger logger_ { + "RAPIDS", detail::default_log_filename() + }; +#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +#ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM + logger_.info("----- RAPIDS LOG BEGIN [PTDS ENABLED] -----"); +#else + logger_.info("----- RAPIDS LOG BEGIN [PTDS DISABLED] -----"); +#endif +#endif + return logger_; + }(); + return logger_; +} #endif // Macros for easier logging, similar to spdlog. diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 10b168ee4..e9a16925e 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -36,20 +36,6 @@ namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { -/** - * @brief Returns the default log filename for the RMM global logger. - * - * If the environment variable `RAPIDS_DEBUG_LOG_FILE` is defined, its value is used as the path and - * name of the log file. Otherwise, the file `@_RAPIDS_LOGGER_NAMESPACE@_log.txt` in the current working directory is used. - * - * @return std::string The default log file name. - */ -inline std::string default_log_filename() -{ - auto* filename = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEBUG_LOG_FILE"); - return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; -} - /** * @struct impl * @brief The real implementation of the logger using spdlog with a basic file sink. @@ -77,32 +63,6 @@ struct impl { } }; -/** - * @brief Represent a size in number of bytes. - */ -struct bytes { - std::size_t value; ///< The size in bytes - - /** - * @brief Construct a new bytes object - * - * @param os The output stream - * @param value The size in bytes - */ - friend std::ostream& operator<<(std::ostream& os, bytes const& value) - { - static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; - - int index = 0; - auto size = static_cast(value.value); - while (size > 1024) { - size /= 1024; - index++; - } - return os << size << ' ' << units.at(index); - } -}; - } // namespace detail // TODO: Many of the inline and class keywords are likely unnecessary in the From 7da8d709ec7b3fe24ba091323fabef6007c78d10 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 22:33:35 +0000 Subject: [PATCH 014/120] Get everything compiling and running except arena tests with the new behavior --- CMakeLists.txt | 56 ++++++++++++------ .../rmm/mr/device/arena_memory_resource.hpp | 12 ++++ include/rmm/mr/device/detail/arena.hpp | 4 ++ rapids_logger/CMakeLists.txt | 22 +++++++ rapids_logger/logger.cpp.in | 17 ++++++ rapids_logger/logger.hpp.in | 57 +++++++++++++++++-- rapids_logger/logger_impl.hpp.in | 44 +++++++++++--- tests/CMakeLists.txt | 7 +++ tests/mr/device/tracking_mr_tests.cpp | 14 +++++ 9 files changed, 204 insertions(+), 29 deletions(-) create mode 100644 rapids_logger/logger.cpp.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f1adf8d1..10a937b96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,9 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) +# option(SUPPORTS_LOGGING "Enable logging support" ON) +set(LOGGING_COMPATIBILITY OFF) + # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- @@ -74,23 +77,42 @@ rapids_find_package( rapids_cpm_init() add_subdirectory(rapids_logger) -rapids_make_logger( - LOGGER_TARGET - rmm_logger - LOGGER_HEADER_DIR - include/rmm - LOGGER_NAMESPACE - rmm - LOGGER_MACRO_PREFIX - RMM - BUILD_EXPORT_SET - rmm-exports - INSTALL_EXPORT_SET - rmm-exports - CMAKE_NAMESPACE - rmm:: - SUPPORTS_LOGGING - RMM_BACKWARDS_COMPATIBILITY) +if(LOGGING_COMPATIBILITY) + rapids_make_logger( + LOGGER_TARGET + rmm_logger + LOGGER_HEADER_DIR + include/rmm + LOGGER_NAMESPACE + rmm + LOGGER_MACRO_PREFIX + RMM + BUILD_EXPORT_SET + rmm-exports + INSTALL_EXPORT_SET + rmm-exports + CMAKE_NAMESPACE + rmm:: + SUPPORTS_LOGGING + RMM_BACKWARDS_COMPATIBILITY) +else() + rapids_make_logger( + LOGGER_TARGET + rmm_logger + LOGGER_HEADER_DIR + include/rmm + LOGGER_NAMESPACE + rmm + LOGGER_MACRO_PREFIX + RMM + BUILD_EXPORT_SET + rmm-exports + INSTALL_EXPORT_SET + rmm-exports + CMAKE_NAMESPACE + rmm:: + SUPPORTS_LOGGING) +endif() include(cmake/thirdparty/get_cccl.cmake) include(cmake/thirdparty/get_nvtx.cmake) diff --git a/include/rmm/mr/device/arena_memory_resource.hpp b/include/rmm/mr/device/arena_memory_resource.hpp index 3428e9c8f..eb5b87f8e 100644 --- a/include/rmm/mr/device/arena_memory_resource.hpp +++ b/include/rmm/mr/device/arena_memory_resource.hpp @@ -26,7 +26,9 @@ #include +#ifdef RMM_BACKWARDS_COMPATIBILITY #include +#endif #include #include @@ -97,12 +99,18 @@ class arena_memory_resource final : public device_memory_resource { : global_arena_{upstream_mr, arena_size}, dump_log_on_failure_{dump_log_on_failure} { if (dump_log_on_failure_) { +#ifdef RMM_BACKWARDS_COMPATIBILITY logger_ = std::make_shared("arena_memory_dump", std::make_shared( "rmm_arena_memory_dump.log", true /*truncate file*/)); // Set the level to `debug` for more detailed output. logger_->set_level(spdlog::level::info); +#else + logger_ = std::make_shared("arena_memory_dump", "rmm_arena_memory_dump.log"); + // Set the level to `debug` for more detailed output. + logger_->set_level(level_enum::info); +#endif } } @@ -356,7 +364,11 @@ class arena_memory_resource final : public device_memory_resource { /// If true, dump memory information to log on allocation failure. bool dump_log_on_failure_{}; /// The logger for memory dump. +#ifdef RMM_BACKWARDS_COMPATIBILITY std::shared_ptr logger_{}; +#else + std::shared_ptr logger_{}; +#endif /// Mutex for read and write locks on arena maps. mutable std::shared_mutex map_mtx_; /// Mutex for shared and unique locks on the mr. diff --git a/include/rmm/mr/device/detail/arena.hpp b/include/rmm/mr/device/detail/arena.hpp index da64ca85b..2d3dd9d7b 100644 --- a/include/rmm/mr/device/detail/arena.hpp +++ b/include/rmm/mr/device/detail/arena.hpp @@ -647,7 +647,11 @@ class global_arena final { * * @param logger the spdlog logger to use */ +#ifdef RMM_BACKWARDS_COMPATIBILITY RMM_HIDDEN void dump_memory_log(std::shared_ptr const& logger) const +#else + void dump_memory_log(std::shared_ptr const& logger) const +#endif { std::lock_guard lock(mtx_); diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 042fe24ef..64cc1cf50 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -72,10 +72,32 @@ function(rapids_make_logger) INTERFACE "$" "$") if(_RAPIDS_RMM_BACKWARDS_COMPATIBILITY) + if(NOT _RAPIDS_SUPPORTS_LOGGING) + message(STATUS "RMM_BACKWARDS_COMPATIBILITY requires SUPPORTS_LOGGING, turning it on") + set(_RAPIDS_SUPPORTS_LOGGING ON) + endif() target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE RMM_BACKWARDS_COMPATIBILITY) endif() if(_RAPIDS_SUPPORTS_LOGGING) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE SUPPORTS_LOGGING) + + if(NOT _RAPIDS_RMM_BACKWARDS_COMPATIBILITY) + # Create an interface target that will trigger compilation of the logger implementation in any + # target that is linked to it. + set(LOGGER_IMPL_SRC_OUTPUT_FILE ${BUILD_DIR}/logger_impl/logger.cpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.cpp.in + ${LOGGER_IMPL_SRC_OUTPUT_FILE}) + install(FILES ${LOGGER_IMPL_SRC_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) + + # Note that we cannot specify the source files directly in add_library, see the CMake + # documentation explaining that these do not populate INTERFACE_SOURCES. + # https://cmake.org/cmake/help/latest/command/add_library.html#interface-with-sources + add_library(${_RAPIDS_LOGGER_TARGET}_impl INTERFACE) + target_sources( + ${_RAPIDS_LOGGER_TARGET}_impl + INTERFACE $ + $) + endif() endif() if(_RAPIDS_LOGGER_CMAKE_NAMESPACE) diff --git a/rapids_logger/logger.cpp.in b/rapids_logger/logger.cpp.in new file mode 100644 index 000000000..36bb2ce02 --- /dev/null +++ b/rapids_logger/logger.cpp.in @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "logger_impl.hpp" diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index ee643c36e..bcaeb26e8 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -22,9 +22,32 @@ #include #endif +// We only define functions as inline when in backwards compatibility mode +// because in that mode those functions are included in the header, just +// defined out of band by the include of logger_impl.hpp into this file. In the +// new mode the functions are defined in their own TU. +#ifdef RMM_BACKWARDS_COMPATIBILITY +#define BACKWARDS_COMPAT_INLINE inline +#else +#define BACKWARDS_COMPAT_INLINE +#endif + #include +#include #include +#ifdef SUPPORTS_LOGGING +#include + +namespace spdlog { +namespace sinks { +class sink; +} // namespace sinks +using sink_ptr = std::shared_ptr; +} // namespace spdlog + +#endif + namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { @@ -69,6 +92,8 @@ struct bytes { } }; +// TODO: Check if we really need the fake_impl or if we can just not store +// anything at all in the parent class. /** * @class fake_logger_impl * @brief The fake implementation of the logger that performs no-ops. @@ -121,7 +146,7 @@ class logger { * Initializes the logger based on whether logging is supported. */ #ifdef SUPPORTS_LOGGING - logger(std::string name, std::string filename); + BACKWARDS_COMPAT_INLINE logger(std::string name, std::string filename); #else logger(std::string name, std::string filename) {} #endif @@ -133,7 +158,7 @@ class logger { * @brief Destructor for logger. */ #ifdef SUPPORTS_LOGGING - inline ~logger(); + BACKWARDS_COMPAT_INLINE ~logger(); #else ~logger() = default; #endif @@ -145,9 +170,9 @@ class logger { // delete copy assignment operator logger& operator=(logger const&) = delete; // default move constructor - inline logger(logger&&); + BACKWARDS_COMPAT_INLINE logger(logger&&); // default move assignment operator - inline logger& operator=(logger&&); + BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); template void log(level_enum lvl, std::string const& format, Args&&... args) @@ -159,7 +184,7 @@ class logger { log(lvl, {buf.get(), buf.get() + size - 1}); } - inline void log(level_enum lvl, std::string const& message); + BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); template void trace(std::string const& format, Args&&... args) @@ -197,6 +222,28 @@ class logger { log(level_enum::critical, format, std::forward(args)...); } +#ifdef SUPPORTS_LOGGING + BACKWARDS_COMPAT_INLINE void add_sink(spdlog::sink_ptr sink); + BACKWARDS_COMPAT_INLINE void remove_sink(spdlog::sink_ptr sink); +#else + // When logging is not supported we won't have a spdlog sink_ptr type defined + // when this function is, so a template is used to capture the user's type. + template + void add_sink(Sink sink) {} + template + void remove_sink(Sink sink) {} +#endif + +#ifdef SUPPORTS_LOGGING + BACKWARDS_COMPAT_INLINE level_enum level() const; + BACKWARDS_COMPAT_INLINE void set_level(level_enum log_level); + BACKWARDS_COMPAT_INLINE void flush(); +#else + BACKWARDS_COMPAT_INLINE level_enum level() const { return level_enum::off; } + void set_level(level::level_enum log_level) {} + void flush() {} +#endif + /** * @brief Check at compile-time whether logging is supported. * @return `true` if logging is supported, `false` otherwise. diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index e9a16925e..d40ba3daa 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -61,22 +61,52 @@ struct impl { { underlying.log(static_cast(static_cast(lvl)), message); } + + void set_level(level_enum log_level) + { + underlying.set_level(static_cast(static_cast(log_level))); + } + + void flush() + { + underlying.flush(); + } + + void add_sink(spdlog::sink_ptr sink) { + underlying.sinks().push_back(sink); + } + + void remove_sink(spdlog::sink_ptr sink) { + auto& sinks = underlying.sinks(); + sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); + } + + level_enum level() const + { + return static_cast(static_cast(underlying.level())); + } }; } // namespace detail -// TODO: Many of the inline and class keywords are likely unnecessary in the -// non-backwards compatibility version. -inline logger::logger(std::string name, std::string filename) +// TODO: Many of the class keywords are likely unnecessary in the non-backwards +// compatibility version. +BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) : pImpl{std::make_unique(name, filename)} { } -inline logger::~logger() = default; -inline logger::logger(logger&&) = default; -inline class logger& logger::operator=(logger&&) = default; +BACKWARDS_COMPAT_INLINE logger::~logger() = default; +BACKWARDS_COMPAT_INLINE logger::logger(logger&&) = default; +BACKWARDS_COMPAT_INLINE class logger& logger::operator=(logger&&) = default; + +BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } -inline void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } +BACKWARDS_COMPAT_INLINE void logger::set_level(level_enum log_level) { pImpl->set_level(log_level); } +BACKWARDS_COMPAT_INLINE void logger::flush() { pImpl->flush(); } +BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { pImpl->add_sink(sink); } +BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { pImpl->remove_sink(sink); } +BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return pImpl->level(); } #ifdef RMM_BACKWARDS_COMPATIBILITY namespace detail { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0258c59c5..aeecec456 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,6 +44,13 @@ function(ConfigureTestInternal TEST_NAME) target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror -Wno-error=deprecated-declarations>) + # When not building in compatibility mode, each test has to recompile the headers. TODO: For the + # tests, consider building an object library that can be reused. This is separate from what the + # main library does (providing an interface lib). + if(NOT LOGGING_COMPATIBILITY) + target_link_libraries(${TEST_NAME} rmm_logger_impl) + endif() + if(DISABLE_DEPRECATION_WARNING) target_compile_options( ${TEST_NAME} PUBLIC $<$:-Xcompiler=-Wno-deprecated-declarations>) diff --git a/tests/mr/device/tracking_mr_tests.cpp b/tests/mr/device/tracking_mr_tests.cpp index 3fce55fb8..f1da19463 100644 --- a/tests/mr/device/tracking_mr_tests.cpp +++ b/tests/mr/device/tracking_mr_tests.cpp @@ -204,8 +204,13 @@ TEST(TrackingTest, LogOutstandingAllocations) { std::ostringstream oss; auto oss_sink = std::make_shared(oss); +#ifdef RMM_BACKWARDS_COMPATIBILITY rmm::detail::logger().sinks().push_back(oss_sink); auto old_level = rmm::detail::logger().level(); +#else + auto old_level = rmm::default_logger().level(); + rmm::default_logger().add_sink(oss_sink); +#endif tracking_adaptor mr{rmm::mr::get_current_device_resource_ref()}; std::vector allocations; @@ -213,7 +218,11 @@ TEST(TrackingTest, LogOutstandingAllocations) allocations.push_back(mr.allocate(ten_MiB)); } +#ifdef RMM_BACKWARDS_COMPATIBILITY rmm::detail::logger().set_level(spdlog::level::debug); +#else + rmm::default_logger().set_level(rmm::level_enum::debug); +#endif EXPECT_NO_THROW(mr.log_outstanding_allocations()); #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG @@ -224,8 +233,13 @@ TEST(TrackingTest, LogOutstandingAllocations) mr.deallocate(allocation, ten_MiB); } +#ifdef RMM_BACKWARDS_COMPATIBILITY rmm::detail::logger().set_level(old_level); rmm::detail::logger().sinks().pop_back(); +#else + rmm::default_logger().set_level(old_level); + rmm::default_logger().remove_sink(oss_sink); +#endif } } // namespace From 54abd706ab4de17e1cf774c740d637be7d8b236c Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 1 Nov 2024 23:35:57 +0000 Subject: [PATCH 015/120] Get arena test passing --- include/rmm/mr/device/detail/arena.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rmm/mr/device/detail/arena.hpp b/include/rmm/mr/device/detail/arena.hpp index 2d3dd9d7b..d0cfe705e 100644 --- a/include/rmm/mr/device/detail/arena.hpp +++ b/include/rmm/mr/device/detail/arena.hpp @@ -656,7 +656,7 @@ class global_arena final { std::lock_guard lock(mtx_); logger->info(" Arena size: {}", rmm::detail::bytes{upstream_block_.size()}); - logger->info(" # superblocks: {}", superblocks_.size()); + logger->info(" # superblocks: %d", superblocks_.size()); if (!superblocks_.empty()) { logger->debug(" Total size of superblocks: {}", rmm::detail::bytes{total_memory_size(superblocks_)}); @@ -665,14 +665,14 @@ class global_arena final { auto const fragmentation = (1 - max_free / static_cast(total_free)) * 100; logger->info(" Total free memory: {}", rmm::detail::bytes{total_free}); logger->info(" Largest block of free memory: {}", rmm::detail::bytes{max_free}); - logger->info(" Fragmentation: {:.2f}%", fragmentation); + logger->info(" Fragmentation: %0.2f%%", fragmentation); auto index = 0; char* prev_end{}; for (auto const& sblk : superblocks_) { if (prev_end == nullptr) { prev_end = sblk.pointer(); } logger->debug( - " Superblock {}: start={}, end={}, size={}, empty={}, # free blocks={}, max free={}, " + " Superblock %d: start=%p, end=%p, size={}, empty=%d, # free blocks=%d, max free={}, " "gap={}", index, fmt::ptr(sblk.pointer()), From 627d369c5da2fb18a4b4cc112a34045aa155ae0a Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 00:34:15 +0000 Subject: [PATCH 016/120] Support a different approach for custom class formatting --- .../rmm/mr/device/arena_memory_resource.hpp | 2 +- include/rmm/mr/device/detail/arena.hpp | 12 +-- rapids_logger/logger.hpp.in | 80 ++++++++++++++++--- 3 files changed, 78 insertions(+), 16 deletions(-) diff --git a/include/rmm/mr/device/arena_memory_resource.hpp b/include/rmm/mr/device/arena_memory_resource.hpp index eb5b87f8e..6f9b7ac36 100644 --- a/include/rmm/mr/device/arena_memory_resource.hpp +++ b/include/rmm/mr/device/arena_memory_resource.hpp @@ -335,7 +335,7 @@ class arena_memory_resource final : public device_memory_resource { void dump_memory_log(size_t bytes) { logger_->info("**************************************************"); - logger_->info("Ran out of memory trying to allocate {}.", rmm::detail::bytes{bytes}); + logger_->info("Ran out of memory trying to allocate %s.", rmm::detail::bytes{bytes}); logger_->info("**************************************************"); logger_->info("Global arena:"); global_arena_.dump_memory_log(logger_); diff --git a/include/rmm/mr/device/detail/arena.hpp b/include/rmm/mr/device/detail/arena.hpp index d0cfe705e..a7fcd02f7 100644 --- a/include/rmm/mr/device/detail/arena.hpp +++ b/include/rmm/mr/device/detail/arena.hpp @@ -655,16 +655,16 @@ class global_arena final { { std::lock_guard lock(mtx_); - logger->info(" Arena size: {}", rmm::detail::bytes{upstream_block_.size()}); + logger->info(" Arena size: %s", rmm::detail::bytes{upstream_block_.size()}); logger->info(" # superblocks: %d", superblocks_.size()); if (!superblocks_.empty()) { - logger->debug(" Total size of superblocks: {}", + logger->debug(" Total size of superblocks: %s", rmm::detail::bytes{total_memory_size(superblocks_)}); auto const total_free = total_free_size(superblocks_); auto const max_free = max_free_size(superblocks_); auto const fragmentation = (1 - max_free / static_cast(total_free)) * 100; - logger->info(" Total free memory: {}", rmm::detail::bytes{total_free}); - logger->info(" Largest block of free memory: {}", rmm::detail::bytes{max_free}); + logger->info(" Total free memory: %s", rmm::detail::bytes{total_free}); + logger->info(" Largest block of free memory: %s", rmm::detail::bytes{max_free}); logger->info(" Fragmentation: %0.2f%%", fragmentation); auto index = 0; @@ -672,8 +672,8 @@ class global_arena final { for (auto const& sblk : superblocks_) { if (prev_end == nullptr) { prev_end = sblk.pointer(); } logger->debug( - " Superblock %d: start=%p, end=%p, size={}, empty=%d, # free blocks=%d, max free={}, " - "gap={}", + " Superblock %d: start=%p, end=%p, size=%s, empty=%d, # free blocks=%d, max free=%s, " + "gap=%s", index, fmt::ptr(sblk.pointer()), fmt::ptr(sblk.end()), diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index bcaeb26e8..d6e047938 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -72,6 +72,7 @@ inline std::string default_log_filename() struct bytes { std::size_t value; ///< The size in bytes +#ifdef RMM_BACKWARDS_COMPATIBILITY /** * @brief Construct a new bytes object * @@ -90,6 +91,21 @@ struct bytes { } return os << size << ' ' << units.at(index); } +#else + std::string to_string() const + { + static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; + + int index = 0; + auto size = static_cast(value); + while (size > 1024) { + size /= 1024; + index++; + } + return std::to_string(size) + ' ' + units.at(index); + } + +#endif }; // TODO: Check if we really need the fake_impl or if we can just not store @@ -112,6 +128,14 @@ class fake_impl { // Forward declaration of the real implementation struct impl; +// Trait to check if T has a to_string() method that returns std::string +template > +struct has_to_string : std::false_type {}; + +template +struct has_to_string().to_string())>> + : std::is_same().to_string()), std::string> {}; + } // namespace detail // These defines must be kept in sync with spdlog or bad things will happen! @@ -174,15 +198,21 @@ class logger { // default move assignment operator BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); - template - void log(level_enum lvl, std::string const& format, Args&&... args) - { - auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), args...) + 1); - if (size <= 0) { throw std::runtime_error("Error during formatting."); } - std::unique_ptr buf(new char[size]); - std::snprintf(buf.get(), size, format.c_str(), args...); - log(lvl, {buf.get(), buf.get() + size - 1}); - } + // This public log API allows users to pass format arguments to this function + // a la printf. + template + void log(level_enum lvl, std::string const& format, Args&&... args) { + auto convert_to_string = [](auto&& arg) -> decltype(auto) { + using ArgType = std::decay_t; + if constexpr (detail::has_to_string::value) { + return arg.to_string(); + } else { + return std::forward(arg); + } + }; + + this->_log(lvl, format, convert_to_string(std::forward(args))...); + }; BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); @@ -266,6 +296,38 @@ class logger { #else std::unique_ptr pImpl{}; #endif + +#ifdef RMM_BACKWARDS_COMPATIBILITY + private: +#endif + // TODO: When we migrate to C++20 we can use std::format and format strings + // instead of the printf-style printing used here. + template + void formatted_log(level_enum lvl, std::string const& format, Args&&... args) { + auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), args...) + 1); + if (size <= 0) { throw std::runtime_error("Error during formatting."); } + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), args...); + log(lvl, {buf.get(), buf.get() + size - 1}); + } + + // This second level of indirection preserves the lifetime of string + // temporaries created in the log() call so that the c_str pointers are valid + // in the subsequent formatted_log call. + template + void _log(level_enum lvl, std::string const& format, Args&&... args) { + auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { + using ArgType = std::decay_t; + if constexpr (std::is_same_v) { + return arg.c_str(); + } else { + return std::forward(arg); + } + }; + + this->formatted_log(lvl, format, convert_to_c_string(std::forward(args))...); + }; + }; namespace detail { From 39fe1b2211a8bf617c273ac302e7a371a6dc80eb Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 00:40:43 +0000 Subject: [PATCH 017/120] Get rid of redundant fake_impl --- rapids_logger/logger.hpp.in | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index d6e047938..2694d466d 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -108,23 +108,6 @@ struct bytes { #endif }; -// TODO: Check if we really need the fake_impl or if we can just not store -// anything at all in the parent class. -/** - * @class fake_logger_impl - * @brief The fake implementation of the logger that performs no-ops. - * This is the default behavior if real logging is not enabled. - */ -class fake_impl { - public: - fake_impl() = default; - - template - void log(Args&&... args) - { - } -}; - // Forward declaration of the real implementation struct impl; @@ -214,7 +197,11 @@ class logger { this->_log(lvl, format, convert_to_string(std::forward(args))...); }; +#ifdef SUPPORTS_LOGGING BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); +#else + void log(level_enum lvl, std::string const& message) {} +#endif template void trace(std::string const& format, Args&&... args) @@ -293,8 +280,6 @@ class logger { // TODO: Support args to the impl constructor #ifdef SUPPORTS_LOGGING std::unique_ptr pImpl{}; -#else - std::unique_ptr pImpl{}; #endif #ifdef RMM_BACKWARDS_COMPATIBILITY From 4a6cc9d02bb4e8c3ac0be93fa8cc2fb3b8065786 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 00:53:32 +0000 Subject: [PATCH 018/120] Some cleanup and consolidation of ifdef blocks --- rapids_logger/logger.hpp.in | 80 ++++++++++---------------------- rapids_logger/logger_impl.hpp.in | 8 ++-- 2 files changed, 28 insertions(+), 60 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 2694d466d..4e7a71f98 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -37,7 +37,6 @@ #include #ifdef SUPPORTS_LOGGING -#include namespace spdlog { namespace sinks { @@ -148,28 +147,17 @@ enum class level_enum : int32_t { */ class logger { public: - /** - * @brief Constructor for logger. - * Initializes the logger based on whether logging is supported. - */ #ifdef SUPPORTS_LOGGING BACKWARDS_COMPAT_INLINE logger(std::string name, std::string filename); + BACKWARDS_COMPAT_INLINE ~logger(); #else logger(std::string name, std::string filename) {} + ~logger() = default; #endif // Not default constructible. logger() = delete; - /** - * @brief Destructor for logger. - */ -#ifdef SUPPORTS_LOGGING - BACKWARDS_COMPAT_INLINE ~logger(); -#else - ~logger() = default; -#endif - /** * @brief Copy constructor for logger. */ @@ -181,6 +169,29 @@ class logger { // default move assignment operator BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); +#ifdef SUPPORTS_LOGGING + BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); + BACKWARDS_COMPAT_INLINE void add_sink(spdlog::sink_ptr sink); + BACKWARDS_COMPAT_INLINE void remove_sink(spdlog::sink_ptr sink); + BACKWARDS_COMPAT_INLINE level_enum level() const; + BACKWARDS_COMPAT_INLINE void set_level(level_enum log_level); + BACKWARDS_COMPAT_INLINE void flush(); + static constexpr bool supports_logging() { return true; } +#else + void log(level_enum lvl, std::string const& message) {} + // When logging is not supported we won't have a spdlog sink_ptr type defined + // when this function is, so a template is used to capture the user's type. + template + void add_sink(Sink sink) {} + template + void remove_sink(Sink sink); + level_enum level() const { return level_enum::off; } + void set_level(level::level_enum log_level) {} + void flush() {} + void remove_sink(Sink sink) {} + static constexpr bool supports_logging() { return false; } +#endif + // This public log API allows users to pass format arguments to this function // a la printf. template @@ -197,12 +208,6 @@ class logger { this->_log(lvl, format, convert_to_string(std::forward(args))...); }; -#ifdef SUPPORTS_LOGGING - BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); -#else - void log(level_enum lvl, std::string const& message) {} -#endif - template void trace(std::string const& format, Args&&... args) { @@ -239,41 +244,6 @@ class logger { log(level_enum::critical, format, std::forward(args)...); } -#ifdef SUPPORTS_LOGGING - BACKWARDS_COMPAT_INLINE void add_sink(spdlog::sink_ptr sink); - BACKWARDS_COMPAT_INLINE void remove_sink(spdlog::sink_ptr sink); -#else - // When logging is not supported we won't have a spdlog sink_ptr type defined - // when this function is, so a template is used to capture the user's type. - template - void add_sink(Sink sink) {} - template - void remove_sink(Sink sink) {} -#endif - -#ifdef SUPPORTS_LOGGING - BACKWARDS_COMPAT_INLINE level_enum level() const; - BACKWARDS_COMPAT_INLINE void set_level(level_enum log_level); - BACKWARDS_COMPAT_INLINE void flush(); -#else - BACKWARDS_COMPAT_INLINE level_enum level() const { return level_enum::off; } - void set_level(level::level_enum log_level) {} - void flush() {} -#endif - - /** - * @brief Check at compile-time whether logging is supported. - * @return `true` if logging is supported, `false` otherwise. - */ - static constexpr bool supports_logging() - { -#ifdef SUPPORTS_LOGGING - return true; -#else - return false; -#endif - } - #ifndef RMM_BACKWARDS_COMPATIBILITY private: #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index d40ba3daa..46b9e9a7a 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -21,12 +21,10 @@ #include "../logger.hpp" #endif -// In the long run this shouldn't be necessary because the file will only be -// compiled if SUPPORTS_LOGGING is enabled. -#ifdef SUPPORTS_LOGGING - +#ifdef RMM_BACKWARDS_COMPATIBILITY #include #include +#endif #include #include @@ -136,9 +134,9 @@ inline class spdlog::logger& logger() { return default_logger().pImpl->underlyin } // namespace @_RAPIDS_LOGGER_NAMESPACE@ +#ifdef RMM_BACKWARDS_COMPATIBILITY // Doxygen doesn't like this because we're overloading something from fmt //! @cond Doxygen_Suppress template <> struct fmt::formatter<@_RAPIDS_LOGGER_NAMESPACE@::detail::bytes> : fmt::ostream_formatter {}; - #endif From 91fab68172053f7e7d2ebf5d1027e37c85dd593d Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 01:04:32 +0000 Subject: [PATCH 019/120] Compile an object library for the tests to avoid recompilation. --- rapids_logger/CMakeLists.txt | 1 + tests/CMakeLists.txt | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 64cc1cf50..b86c54405 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -97,6 +97,7 @@ function(rapids_make_logger) ${_RAPIDS_LOGGER_TARGET}_impl INTERFACE $ $) + target_link_libraries(${_RAPIDS_LOGGER_TARGET}_impl INTERFACE ${_RAPIDS_LOGGER_TARGET}) endif() endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aeecec456..726764818 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,11 +44,11 @@ function(ConfigureTestInternal TEST_NAME) target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror -Wno-error=deprecated-declarations>) - # When not building in compatibility mode, each test has to recompile the headers. TODO: For the - # tests, consider building an object library that can be reused. This is separate from what the - # main library does (providing an interface lib). + # When not building in compatibility mode, each test has to recompile the headers. TODO: This + # assumes that rmm does not currently expose a build where compatibility mode is off but + # SUPPORTS_LOGGING is also false (in which case the impl target won't be created). if(NOT LOGGING_COMPATIBILITY) - target_link_libraries(${TEST_NAME} rmm_logger_impl) + target_link_libraries(${TEST_NAME} rmm_test_logger) endif() if(DISABLE_DEPRECATION_WARNING) @@ -125,6 +125,10 @@ function(ConfigureTest TEST_NAME) endfunction() +# Create an object library for the logger so that we don't have to recompile it. +add_library(rmm_test_logger OBJECT) +target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) + # test sources # device mr_ref tests From 2f58cc594f941a983af3030562a0d1cefe34e2c5 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 01:20:22 +0000 Subject: [PATCH 020/120] Properly enable building without logging support --- CMakeLists.txt | 16 +++++++++++++--- rapids_logger/logger.hpp.in | 9 ++++----- tests/CMakeLists.txt | 15 ++++++++------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 10a937b96..e17da24c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,8 +58,14 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -# option(SUPPORTS_LOGGING "Enable logging support" ON) -set(LOGGING_COMPATIBILITY OFF) +option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" OFF) +option(SUPPORTS_LOGGING "Enable logging support" OFF) +if(LOGGING_COMPATIBILITY) + if(NOT SUPPORTS_LOGGING) + message(STATUS "LOGGING_COMPATIBILITY requires SUPPORTS_LOGGING to be enabled") + set(SUPPORTS_LOGGING ON) + endif() +endif() # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- @@ -96,6 +102,10 @@ if(LOGGING_COMPATIBILITY) SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) else() + set(_logging_support_flag) + if(SUPPORTS_LOGGING) + set(_logging_support_flag "SUPPORTS_LOGGING") + endif() rapids_make_logger( LOGGER_TARGET rmm_logger @@ -111,7 +121,7 @@ else() rmm-exports CMAKE_NAMESPACE rmm:: - SUPPORTS_LOGGING) + ${_logging_support_flag}) endif() include(cmake/thirdparty/get_cccl.cmake) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 4e7a71f98..a7069a728 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -181,14 +181,13 @@ class logger { void log(level_enum lvl, std::string const& message) {} // When logging is not supported we won't have a spdlog sink_ptr type defined // when this function is, so a template is used to capture the user's type. - template + template void add_sink(Sink sink) {} - template - void remove_sink(Sink sink); + template + void remove_sink(Sink sink) {} level_enum level() const { return level_enum::off; } - void set_level(level::level_enum log_level) {} + void set_level(level_enum log_level) {} void flush() {} - void remove_sink(Sink sink) {} static constexpr bool supports_logging() { return false; } #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 726764818..c0009c013 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,10 +44,8 @@ function(ConfigureTestInternal TEST_NAME) target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror -Wno-error=deprecated-declarations>) - # When not building in compatibility mode, each test has to recompile the headers. TODO: This - # assumes that rmm does not currently expose a build where compatibility mode is off but - # SUPPORTS_LOGGING is also false (in which case the impl target won't be created). - if(NOT LOGGING_COMPATIBILITY) + # When not building in compatibility mode, each test has to recompile the headers. + if(TARGET rmm_test_logger) target_link_libraries(${TEST_NAME} rmm_test_logger) endif() @@ -125,9 +123,12 @@ function(ConfigureTest TEST_NAME) endfunction() -# Create an object library for the logger so that we don't have to recompile it. -add_library(rmm_test_logger OBJECT) -target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) +# Create an object library for the logger so that we don't have to recompile it. This is not +# necessary if logging is unsupported since then the header-only implementation is sufficient. +if(SUPPORTS_LOGGING AND NOT LOGGING_COMPATIBILITY) + add_library(rmm_test_logger OBJECT) + target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) +endif() # test sources From 2c021ec849a94170100f710c1597a042869e9cde Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 01:27:00 +0000 Subject: [PATCH 021/120] Clean up some todos --- rapids_logger/logger.hpp.in | 4 ++-- rapids_logger/logger_impl.hpp.in | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index a7069a728..b415f13e4 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -246,7 +246,6 @@ class logger { #ifndef RMM_BACKWARDS_COMPATIBILITY private: #endif -// TODO: Support args to the impl constructor #ifdef SUPPORTS_LOGGING std::unique_ptr pImpl{}; #endif @@ -324,7 +323,8 @@ inline logger& default_logger() #endif // Macros for easier logging, similar to spdlog. -// TODO: Assumes that we want to respect spdlog's own logging macro level settings. +// TODO: The macros below assume that we want to respect spdlog's level macros +// rather than the ones defined by this file. #define RMM_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 46b9e9a7a..f102c503d 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -87,8 +87,6 @@ struct impl { } // namespace detail -// TODO: Many of the class keywords are likely unnecessary in the non-backwards -// compatibility version. BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) : pImpl{std::make_unique(name, filename)} { @@ -96,7 +94,11 @@ BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) BACKWARDS_COMPAT_INLINE logger::~logger() = default; BACKWARDS_COMPAT_INLINE logger::logger(logger&&) = default; +#ifdef RMM_BACKWARDS_COMPATIBILITY BACKWARDS_COMPAT_INLINE class logger& logger::operator=(logger&&) = default; +#else +BACKWARDS_COMPAT_INLINE logger& logger::operator=(logger&&) = default; +#endif BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } From eb93bf2f078a7ae22ab607f5289f3b172ed86c16 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 01:46:35 +0000 Subject: [PATCH 022/120] Add documentation --- rapids_logger/logger.hpp.in | 190 +++++++++++++++++++++++++++---- rapids_logger/logger_impl.hpp.in | 31 ++++- 2 files changed, 198 insertions(+), 23 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index b415f13e4..498908f44 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -38,6 +38,7 @@ #ifdef SUPPORTS_LOGGING +// Forward declare spdlog types that are part of our public API. namespace spdlog { namespace sinks { class sink; @@ -91,6 +92,11 @@ struct bytes { return os << size << ' ' << units.at(index); } #else + /** + * @brief Convert the size to a string representation. + * + * @return std::string The size as a string. + */ std::string to_string() const { static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; @@ -110,7 +116,11 @@ struct bytes { // Forward declaration of the real implementation struct impl; -// Trait to check if T has a to_string() method that returns std::string +/** + * @brief Trait to check if a type has a `to_string()` method that returns a `std::string`. + * + * @tparam T The type to check. + */ template > struct has_to_string : std::false_type {}; @@ -120,7 +130,7 @@ struct has_to_string().to_string())>> } // namespace detail -// These defines must be kept in sync with spdlog or bad things will happen! +// These values must be kept in sync with spdlog! #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE 0 #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG 1 #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_INFO 2 @@ -129,6 +139,11 @@ struct has_to_string().to_string())>> #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_CRITICAL 5 #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_OFF 6 +/** + * @brief The log levels supported by the logger. + * + * These levels correspond to the levels defined by spdlog. + */ enum class level_enum : int32_t { trace = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE, debug = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG, @@ -148,34 +163,79 @@ enum class level_enum : int32_t { class logger { public: #ifdef SUPPORTS_LOGGING + /** + * @brief Construct a new logger object + * + * @param name The name of the logger + * @param filename The name of the log file + */ BACKWARDS_COMPAT_INLINE logger(std::string name, std::string filename); + + /** + * @brief Destroy the logger object + */ BACKWARDS_COMPAT_INLINE ~logger(); #else logger(std::string name, std::string filename) {} ~logger() = default; #endif - // Not default constructible. - logger() = delete; + logger() = delete; ///< Not default constructible + logger(logger const&) = delete; ///< Not copy constructible + logger& operator=(logger const&) = delete; ///< Not copy assignable - /** - * @brief Copy constructor for logger. - */ - logger(logger const&) = delete; - // delete copy assignment operator - logger& operator=(logger const&) = delete; - // default move constructor - BACKWARDS_COMPAT_INLINE logger(logger&&); - // default move assignment operator - BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); + BACKWARDS_COMPAT_INLINE logger(logger&&); ///< @default_move_constructor + BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); ///< @default_move_assignment{logger} #ifdef SUPPORTS_LOGGING + /** + * @brief Log a message at the specified level. + * + * This is the core logging routine that dispatches to spdlog. + * + * @param lvl The log level + * @param message The message to log + */ BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); + + /** + * @brief Add a sink to the logger. + * + * @param sink The sink to add + */ BACKWARDS_COMPAT_INLINE void add_sink(spdlog::sink_ptr sink); + + /** + * @brief Remove a sink from the logger. + * + * @param sink The sink to remove + */ BACKWARDS_COMPAT_INLINE void remove_sink(spdlog::sink_ptr sink); + + /** + * @brief Get the current log level. + * + * @return The current log level + */ BACKWARDS_COMPAT_INLINE level_enum level() const; + + /** + * @brief Set the log level. + * + * @param log_level The new log level + */ BACKWARDS_COMPAT_INLINE void set_level(level_enum log_level); + + /** + * @brief Flush the logger. + */ BACKWARDS_COMPAT_INLINE void flush(); + + /** + * @brief Check if the logger supports logging. + * + * @return true if the logger supports logging, false otherwise + */ static constexpr bool supports_logging() { return true; } #else void log(level_enum lvl, std::string const& message) {} @@ -191,8 +251,18 @@ class logger { static constexpr bool supports_logging() { return false; } #endif - // This public log API allows users to pass format arguments to this function - // a la printf. + /** + * @brief Log a message at the specified level. + * + * This public log API allows users to pass format arguments to this function + * a la printf. Any custom objects may be logged as long as the type + * implements a `to_string` method. The corresponding format specifier in the + * format string should simply be `%s` like for a normal string. + * + * @param lvl The log level + * @param format The format string + * @param args The format arguments + */ template void log(level_enum lvl, std::string const& format, Args&&... args) { auto convert_to_string = [](auto&& arg) -> decltype(auto) { @@ -207,36 +277,72 @@ class logger { this->_log(lvl, format, convert_to_string(std::forward(args))...); }; + /** + * @brief Log a message at the TRACE level. + * + * @param format The format string + * @param args The format arguments + */ template void trace(std::string const& format, Args&&... args) { log(level_enum::trace, format, std::forward(args)...); } + /** + * @brief Log a message at the DEBUG level. + * + * @param format The format string + * @param args The format arguments + */ template void debug(std::string const& format, Args&&... args) { log(level_enum::debug, format, std::forward(args)...); } + /** + * @brief Log a message at the INFO level. + * + * @param format The format string + * @param args The format arguments + */ template void info(std::string const& format, Args&&... args) { log(level_enum::info, format, std::forward(args)...); } + /** + * @brief Log a message at the WARN level. + * + * @param format The format string + * @param args The format arguments + */ template void warn(std::string const& format, Args&&... args) { log(level_enum::warn, format, std::forward(args)...); } + /** + * @brief Log a message at the ERROR level. + * + * @param format The format string + * @param args The format arguments + */ template void error(std::string const& format, Args&&... args) { log(level_enum::error, format, std::forward(args)...); } + /** + * @brief Log a message at the CRITICAL level. + * + * @param format The format string + * @param args The format arguments + */ template void critical(std::string const& format, Args&&... args) { @@ -247,7 +353,7 @@ class logger { private: #endif #ifdef SUPPORTS_LOGGING - std::unique_ptr pImpl{}; + std::unique_ptr pImpl{}; ///< pimpl idiom #endif #ifdef RMM_BACKWARDS_COMPATIBILITY @@ -255,6 +361,17 @@ class logger { #endif // TODO: When we migrate to C++20 we can use std::format and format strings // instead of the printf-style printing used here. + /** + * @brief Format and log a message. + * + * This function performs printf-style formatting to avoid the need for fmt + * or spdlog's own templated APIs (which would require exposing spdlog + * symbols publicly) and then logs the formatted message. + * + * @param lvl The log level + * @param format The format string + * @param args The format arguments + */ template void formatted_log(level_enum lvl, std::string const& format, Args&&... args) { auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), args...) + 1); @@ -264,9 +381,18 @@ class logger { log(lvl, {buf.get(), buf.get() + size - 1}); } - // This second level of indirection preserves the lifetime of string - // temporaries created in the log() call so that the c_str pointers are valid - // in the subsequent formatted_log call. + /** + * @brief Log a message at the specified level. + * + * This function only exists to provide a level of indirection underneath the + * public templated log API to preserve the lifetime of string temporaries + * created in the log() call so that the c_str pointers are valid in the + * subsequent formatted_log call. + * + * @param lvl The log level + * @param format The format string + * @param args The format arguments + */ template void _log(level_enum lvl, std::string const& format, Args&&... args) { auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { @@ -283,14 +409,29 @@ class logger { }; +#ifdef RMM_BACKWARDS_COMPATIBILITY namespace detail { -#ifdef RMM_BACKWARDS_COMPATIBILITY +/** + * @brief Get the default logger. + * + * @deprecated Will be removed in 25.02. + * + * @return logger& The default logger + */ inline logger& default_logger(); + +/** + * @brief Get the default logger. + * + * @deprecated Will be removed in 25.02. + * + * @return spdlog::logger& The default logger's underlying spdlog logger + */ inline spdlog::logger& logger(); -#endif } // namespace detail +#endif #ifdef RMM_BACKWARDS_COMPATIBILITY inline logger& default_logger() { return detail::default_logger(); } @@ -303,6 +444,11 @@ logger() return detail::logger(); } #else +/** + * @brief Get the default logger. + * + * @return logger& The default logger + */ inline logger& default_logger() { static logger logger_ = [] { diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index f102c503d..1af13f4c5 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -35,7 +35,6 @@ namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { /** - * @struct impl * @brief The real implementation of the logger using spdlog with a basic file sink. */ struct impl { @@ -43,6 +42,7 @@ struct impl { /** * @brief Constructor for the real implementation of the logger. + * * Initializes the logger with a basic file sink. */ impl(std::string name, std::string filename) @@ -55,30 +55,59 @@ struct impl { underlying.flush_on(spdlog::level::warn); } + /** + * @brief Log a message at the specified level. + * + * @param lvl The level at which to log the message. + * @param message The message to log. + */ void log(level_enum lvl, const std::string& message) { underlying.log(static_cast(static_cast(lvl)), message); } + /** + * @brief Set the logging level. + * + * @param log_level The new logging level. + */ void set_level(level_enum log_level) { underlying.set_level(static_cast(static_cast(log_level))); } + /** + * @brief Flush the logger. + */ void flush() { underlying.flush(); } + /** + * @brief Add a sink to the logger. + * + * @param sink The sink to add. + */ void add_sink(spdlog::sink_ptr sink) { underlying.sinks().push_back(sink); } + /** + * @brief Remove a sink from the logger. + * + * @param sink The sink to remove. + */ void remove_sink(spdlog::sink_ptr sink) { auto& sinks = underlying.sinks(); sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); } + /** + * @brief Get the current logging level. + * + * @return The current logging level. + */ level_enum level() const { return static_cast(static_cast(underlying.level())); From 7b449bc05525100b470c8916531460fd3c2b5442 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 19:26:30 +0000 Subject: [PATCH 023/120] Simplify options handling and remove unnecessary exporting rules --- CMakeLists.txt | 37 +++---------------------------- rapids_logger/CMakeLists.txt | 42 +++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e17da24c9..b8f719034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,7 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" OFF) -option(SUPPORTS_LOGGING "Enable logging support" OFF) +option(SUPPORTS_LOGGING "Enable logging support") if(LOGGING_COMPATIBILITY) if(NOT SUPPORTS_LOGGING) message(STATUS "LOGGING_COMPATIBILITY requires SUPPORTS_LOGGING to be enabled") @@ -84,44 +84,13 @@ rapids_cpm_init() add_subdirectory(rapids_logger) if(LOGGING_COMPATIBILITY) - rapids_make_logger( - LOGGER_TARGET - rmm_logger - LOGGER_HEADER_DIR - include/rmm - LOGGER_NAMESPACE - rmm - LOGGER_MACRO_PREFIX - RMM - BUILD_EXPORT_SET - rmm-exports - INSTALL_EXPORT_SET - rmm-exports - CMAKE_NAMESPACE - rmm:: - SUPPORTS_LOGGING - RMM_BACKWARDS_COMPATIBILITY) + rapids_make_logger(rmm SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) else() set(_logging_support_flag) if(SUPPORTS_LOGGING) set(_logging_support_flag "SUPPORTS_LOGGING") endif() - rapids_make_logger( - LOGGER_TARGET - rmm_logger - LOGGER_HEADER_DIR - include/rmm - LOGGER_NAMESPACE - rmm - LOGGER_MACRO_PREFIX - RMM - BUILD_EXPORT_SET - rmm-exports - INSTALL_EXPORT_SET - rmm-exports - CMAKE_NAMESPACE - rmm:: - ${_logging_support_flag}) + rapids_make_logger(rmm ${_logging_support_flag}) endif() include(cmake/thirdparty/get_cccl.cmake) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index b86c54405..103d2ad19 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -12,6 +12,10 @@ # the License. # ============================================================================= +# cmake-lint: disable=R0915 + +include_guard(GLOBAL) + cmake_minimum_required(VERSION 3.26.4 FATAL_ERROR) include(../rapids_config.cmake) @@ -34,17 +38,30 @@ include(../cmake/thirdparty/get_fmt.cmake) include(../cmake/thirdparty/get_spdlog.cmake) # Generate and install the logger files -function(rapids_make_logger) +function(rapids_make_logger logger_namespace) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") set(_rapids_options RMM_BACKWARDS_COMPATIBILITY SUPPORTS_LOGGING) - # TODO: Check for required options - set(_rapids_one_value BUILD_EXPORT_SET INSTALL_EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR - LOGGER_NAMESPACE LOGGER_MACRO_PREFIX CMAKE_NAMESPACE) + set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX) set(_rapids_multi_value) cmake_parse_arguments(_RAPIDS "${_rapids_options}" "${_rapids_one_value}" "${_rapids_multi_value}" ${ARGN}) + # Most arguments are optional and can be inferred from the namespace by default. + set(_RAPIDS_LOGGER_NAMESPACE ${logger_namespace}) + if(NOT _RAPIDS_EXPORT_SET) + set(_RAPIDS_EXPORT_SET "${logger_namespace}-exports") + endif() + if(NOT _RAPIDS_LOGGER_TARGET) + set(_RAPIDS_LOGGER_TARGET "${logger_namespace}_logger") + endif() + if(NOT _RAPIDS_LOGGER_HEADER_DIR) + set(_RAPIDS_LOGGER_HEADER_DIR "include/${logger_namespace}") + endif() + if(NOT _RAPIDS_LOGGER_MACRO_PREFIX) + string(TOUPPER ${logger_namespace} _RAPIDS_LOGGER_MACRO_PREFIX) + endif() + # All paths are computed relative to the current source/binary dir of the file from which the # function is invoked. As a result we cannot use relative paths here because CMake will root these # paths incorrectly for configure_file/install. @@ -101,16 +118,11 @@ function(rapids_make_logger) endif() endif() - if(_RAPIDS_LOGGER_CMAKE_NAMESPACE) - set(CMAKE_NAMESPACE "NAMESPACE ${_RAPIDS_LOGGER_CMAKE_NAMESPACE}") - endif() - if(_RAPIDS_INSTALL_EXPORT_SET) - install( - TARGETS ${_RAPIDS_LOGGER_TARGET} - EXPORT ${_RAPIDS_INSTALL_EXPORT_SET} - ${CMAKE_NAMESPACE}) - endif() - if(_RAPIDS_BUILD_EXPORT_SET) - export(EXPORT ${_RAPIDS_BUILD_EXPORT_SET} ${CMAKE_NAMESPACE}) + set(_install_export) + if(_RAPIDS_EXPORT_SET) + set(_install_export EXPORT ${_RAPIDS_EXPORT_SET}) endif() + + install(TARGETS ${_RAPIDS_LOGGER_TARGET} ${_install_export}) + endfunction() From 9f85459988b23c5c6e9d303d4950fbd204a04948 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 19:27:28 +0000 Subject: [PATCH 024/120] Set default options expected for rmm --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8f719034..fa827f55a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,8 +58,8 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" OFF) -option(SUPPORTS_LOGGING "Enable logging support") +option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) +option(SUPPORTS_LOGGING "Enable logging support" ON) if(LOGGING_COMPATIBILITY) if(NOT SUPPORTS_LOGGING) message(STATUS "LOGGING_COMPATIBILITY requires SUPPORTS_LOGGING to be enabled") From 946573a8fb9b4f863c12725d465389340180b546 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 19:44:39 +0000 Subject: [PATCH 025/120] Add documentation and stop defaulting export set --- CMakeLists.txt | 4 +- rapids_logger/CMakeLists.txt | 79 ++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa827f55a..ca8f78863 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,13 +84,13 @@ rapids_cpm_init() add_subdirectory(rapids_logger) if(LOGGING_COMPATIBILITY) - rapids_make_logger(rmm SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) + rapids_make_logger(rmm EXPORT_SET rmm-exports SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) else() set(_logging_support_flag) if(SUPPORTS_LOGGING) set(_logging_support_flag "SUPPORTS_LOGGING") endif() - rapids_make_logger(rmm ${_logging_support_flag}) + rapids_make_logger(rmm EXPORT_SET rmm-exports ${_logging_support_flag}) endif() include(cmake/thirdparty/get_cccl.cmake) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 103d2ad19..ae6398965 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -37,7 +37,81 @@ rapids_cpm_init() include(../cmake/thirdparty/get_fmt.cmake) include(../cmake/thirdparty/get_spdlog.cmake) -# Generate and install the logger files +#[=======================================================================[.rst: +rapids_make_logger +------------------ + +Generate a logger implementation customized for the specified namespace. + +.. code-block:: cmake + + rapids_make_logger( + [EXPORT_SET ] + [LOGGER_TARGET ] + [LOGGER_HEADER_DIR ] + [LOGGER_MACRO_PREFIX ] + [SUPPORTS_LOGGING] + [RMM_BACKWARDS_COMPATIBILITY] + ) + +This function produces an interface target named that, when linked to by other targets, provides them a header file that defines a logger interface for the specified namespace. The logger is generated from the provided template files and is configured to use the specified namespace and macro prefix. The generated logger is placed in the specified header directory. + +When `RMM_BACKWARDS_COMPATIBILITY` is specified, the logger target is configured to support backwards compatibility with RMM. In this mode, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. In this mode, `SUPPORTS_LOGGING` is always true. + +When not using backwards compatibility mode, the logger implementation (which lives in a separate header file) is not included in the declaration header. If `SUPPORTS_LOGGING` is off, the logger target is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. If `SUPPORTS_LOGGING` is on, the logger implementation is compiled into a separate target that must be linked to by any target that uses the logger. + + +``logger_namespace`` + The namespace for which to generate the logger implementation. + +``EXPORT_SET`` + The name of the export set to which the logger target should be added. If not specified, the logger target is not added to any export set. + +``LOGGER_TARGET`` + The name of the logger (and logger impl) target to create. If not specified, defaults to _logger. + +``LOGGER_HEADER_DIR`` + The directory in which to place the generated logger header file. If not specified, the logger header file is placed in include/. + +``LOGGER_MACRO_PREFIX`` + The prefix to use for the logger macros. If not specified, the macro prefix is the uppercase version of the logger namespace. + +``SUPPORTS_LOGGING`` + If specified, the logger target is configured to support logging. If not specified, the resulting logger is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. This setting is required for the logger implementation to be generated. It will be automatically turned on if `RMM_BACKWARDS_COMPATIBILITY` is specified. + +``RMM_BACKWARDS_COMPATIBILITY`` + If specified, the logger target is configured to support backwards compatibility with RMM. In backwards-compatibility mode, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. In this mode, `SUPPORTS_LOGGING` is always true. + + +Result Targets +^^^^^^^^^^^^^^^^ + is an interface target that provides the logger interface for the specified namespace. If `RMM_BACKWARDS_COMPATIBILITY` is on, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. This target only provides headers. + + _impl is an interface target that provides the logger implementation for the specified namespace. This target must be linked to by any target that uses the logger. It is only defined if `RMM_BACKWARDS_COMPATIBILITY` is off and `SUPPORTS_LOGGING` is on. Targets linking to this target will have the logger implementation compiled into them. + +Examples +^^^^^^^^ + +Example on how to use :cmake:command:`rapids_make_logger`. + + +.. code-block:: cmake + + # Generate a logger for the namespace "rapids" and associate it with the + # export set "rapids-exports". + rapids_make_logger(rapids + SUPPORTS_LOGGING + EXPORT_SET rapids-exports + ) + + # Generate a logger for the namespace "rmm" in backwards compatibility mode. + rapids_make_logger(rapids + SUPPORTS_LOGGING + RMM_BACKWARDS_COMPATIBILITY + ) + + +#]=======================================================================] function(rapids_make_logger logger_namespace) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") @@ -49,9 +123,6 @@ function(rapids_make_logger logger_namespace) # Most arguments are optional and can be inferred from the namespace by default. set(_RAPIDS_LOGGER_NAMESPACE ${logger_namespace}) - if(NOT _RAPIDS_EXPORT_SET) - set(_RAPIDS_EXPORT_SET "${logger_namespace}-exports") - endif() if(NOT _RAPIDS_LOGGER_TARGET) set(_RAPIDS_LOGGER_TARGET "${logger_namespace}_logger") endif() From 19556a63ba91dfd8f3b05d8952180aca54f69195 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 2 Nov 2024 21:25:46 +0000 Subject: [PATCH 026/120] Add functions required by the Python API --- CMakeLists.txt | 2 +- rapids_logger/logger.hpp.in | 21 +++++++++++++++++++++ rapids_logger/logger_impl.hpp.in | 29 ++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca8f78863..d3c7f19f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) +option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" OFF) option(SUPPORTS_LOGGING "Enable logging support" ON) if(LOGGING_COMPATIBILITY) if(NOT SUPPORTS_LOGGING) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 498908f44..e98f0acc2 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -231,6 +231,24 @@ class logger { */ BACKWARDS_COMPAT_INLINE void flush(); + /** + * @brief Flush all writes on the specified level or above. + */ + BACKWARDS_COMPAT_INLINE void flush_on(level_enum log_level); + + /** + * @brief Get the current flush level. + */ + BACKWARDS_COMPAT_INLINE level_enum flush_level() const; + + /** + * @brief Check if the logger should log a message at the specified level. + * + * @param msg_level The level of the message + * @return true if the message should be logged, false otherwise + */ + BACKWARDS_COMPAT_INLINE bool should_log(level_enum msg_level) const; + /** * @brief Check if the logger supports logging. * @@ -248,6 +266,9 @@ class logger { level_enum level() const { return level_enum::off; } void set_level(level_enum log_level) {} void flush() {} + void flush_on(level_enum log_level) {} + level_enum flush_level() { return level_enum::off; } + bool should_log(level_enum msg_level) const { return false; } static constexpr bool supports_logging() { return false; } #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 1af13f4c5..d7ac90ec7 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -52,7 +52,7 @@ struct impl { )} { underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); - underlying.flush_on(spdlog::level::warn); + flush_on(level_enum::warn); } /** @@ -84,6 +84,30 @@ struct impl { underlying.flush(); } + /** + * @brief Flush all writes on the specified level or higher. + */ + void flush_on(level_enum log_level) + { + underlying.flush_on(static_cast(static_cast(log_level))); + } + + /** + * @brief Get the flush level. + * + * @return The flush level. + */ + level_enum flush_level() const + { + return static_cast(static_cast(underlying.flush_level())); + } + + // TODO: Add conversion functions for spdlog::level::level_enum + bool should_log(level_enum lvl) const + { + return underlying.should_log(static_cast(static_cast(lvl))); + } + /** * @brief Add a sink to the logger. * @@ -133,6 +157,9 @@ BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& mess BACKWARDS_COMPAT_INLINE void logger::set_level(level_enum log_level) { pImpl->set_level(log_level); } BACKWARDS_COMPAT_INLINE void logger::flush() { pImpl->flush(); } +BACKWARDS_COMPAT_INLINE void logger::flush_on(level_enum log_level) { pImpl->flush_on(log_level); } +BACKWARDS_COMPAT_INLINE level_enum logger::flush_level() const { return pImpl->level(); } +BACKWARDS_COMPAT_INLINE bool logger::should_log(level_enum lvl) const { return pImpl->should_log(lvl); } BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { pImpl->add_sink(sink); } BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { pImpl->remove_sink(sink); } BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return pImpl->level(); } From 4a0dd6b66c0bc46dc588708f78ded9937ccb1e40 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 3 Nov 2024 17:10:41 +0000 Subject: [PATCH 027/120] Get the Python package building with the new logger --- python/rmm/rmm/librmm/CMakeLists.txt | 4 + python/rmm/rmm/librmm/_logger.pxd | 111 ++++++++++++++++--------- python/rmm/rmm/librmm/_logger.pyx | 2 - python/rmm/rmm/pylibrmm/CMakeLists.txt | 4 + python/rmm/rmm/pylibrmm/logger.pyx | 25 ++++-- rapids_logger/CMakeLists.txt | 10 ++- 6 files changed, 104 insertions(+), 52 deletions(-) diff --git a/python/rmm/rmm/librmm/CMakeLists.txt b/python/rmm/rmm/librmm/CMakeLists.txt index 5da2a1a01..82d0bc6ac 100644 --- a/python/rmm/rmm/librmm/CMakeLists.txt +++ b/python/rmm/rmm/librmm/CMakeLists.txt @@ -33,3 +33,7 @@ target_link_libraries(_torch_allocator PRIVATE rmm::rmm) cmake_path(RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR BASE_DIRECTORY "${PROJECT_SOURCE_DIR}" OUTPUT_VARIABLE _torch_allocator_location) install(TARGETS _torch_allocator DESTINATION "${_torch_allocator_location}") + +if(TARGET rmm::rmm_logger_impl) + target_link_libraries(_logger PRIVATE rmm::rmm_logger_impl) +endif() diff --git a/python/rmm/rmm/librmm/_logger.pxd b/python/rmm/rmm/librmm/_logger.pxd index fb2126b2f..5359e8d9a 100644 --- a/python/rmm/rmm/librmm/_logger.pxd +++ b/python/rmm/rmm/librmm/_logger.pxd @@ -13,54 +13,83 @@ # limitations under the License. from libcpp cimport bool +from libcpp.string cimport string +# Note: This must match the LOGGING_COMPATIBILITY setting in CMakeLists.txt for +# the C++ build or the build will fail since the expected symbols will not exist. +DEF LOGGING_COMPATIBILITY = False -cdef extern from "spdlog/common.h" namespace "spdlog::level" nogil: - cpdef enum logging_level "spdlog::level::level_enum": - """ - The debug logging level for RMM. +# Conditional compilation in Cython is deprecated, but we will remove the need +# for it here before that becomes an issue; this conditional just exists to +# smooth the transition. +# https://docs.cython.org/en/latest/src/userguide/language_basics.html#conditional-compilation +IF LOGGING_COMPATIBILITY: + cdef extern from "spdlog/common.h" namespace "spdlog::level" nogil: + cpdef enum logging_level "spdlog::level::level_enum": + """ + The debug logging level for RMM. - Debug logging prints messages to a log file. See - `Debug Logging `_ - for more information. + Debug logging prints messages to a log file. See + `Debug Logging `_ + for more information. - Valid levels, in decreasing order of verbosity, are TRACE, DEBUG, - INFO, WARN, ERR, CRITICAL, and OFF. Default is INFO. + Valid levels, in decreasing order of verbosity, are TRACE, DEBUG, + INFO, WARN, ERR, CRITICAL, and OFF. Default is INFO. - Examples - -------- - >>> import rmm - >>> rmm.logging_level.DEBUG - - >>> rmm.logging_level.DEBUG.value - 1 - >>> rmm.logging_level.DEBUG.name - 'DEBUG' + Examples + -------- + >>> import rmm + >>> rmm.logging_level.DEBUG + + >>> rmm.logging_level.DEBUG.value + 1 + >>> rmm.logging_level.DEBUG.name + 'DEBUG' - See Also - -------- - set_logging_level : Set the debug logging level - get_logging_level : Get the current debug logging level - """ - TRACE "spdlog::level::trace" - DEBUG "spdlog::level::debug" - INFO "spdlog::level::info" - WARN "spdlog::level::warn" - ERR "spdlog::level::err" - CRITICAL "spdlog::level::critical" - OFF "spdlog::level::off" + See Also + -------- + set_logging_level : Set the debug logging level + get_logging_level : Get the current debug logging level + """ + TRACE "spdlog::level::trace" + DEBUG "spdlog::level::debug" + INFO "spdlog::level::info" + WARN "spdlog::level::warn" + ERR "spdlog::level::err" + CRITICAL "spdlog::level::critical" + OFF "spdlog::level::off" + cdef extern from "spdlog/spdlog.h" namespace "spdlog" nogil: + cdef cppclass spdlog_logger "spdlog::logger": + spdlog_logger() except + + void set_level(logging_level level) + logging_level level() + void flush() except + + void flush_on(logging_level level) + logging_level flush_level() + bool should_log(logging_level msg_level) -cdef extern from "spdlog/spdlog.h" namespace "spdlog" nogil: - cdef cppclass spdlog_logger "spdlog::logger": - spdlog_logger() except + - void set_level(logging_level level) - logging_level level() - void flush() except + - void flush_on(logging_level level) - logging_level flush_level() - bool should_log(logging_level msg_level) + cdef extern from "rmm/logger.hpp" namespace "rmm::detail" nogil: + cdef spdlog_logger& logger() except + +ELSE: + cdef extern from "rmm/logger.hpp" namespace "rmm" nogil: + cpdef enum class level_enum: + trace + debug + info + warn + error + critical + off + n_levels + cdef cppclass logger: + logger(string name, string filename) except + + void set_level(level_enum log_level) except + + level_enum level() except + + void flush() except + + void flush_on(level_enum level) except + + level_enum flush_level() except + + bool should_log(level_enum msg_level) except + -cdef extern from "rmm/logger.hpp" namespace "rmm::detail" nogil: - cdef spdlog_logger& logger() except + + cdef logger& default_logger() except + diff --git a/python/rmm/rmm/librmm/_logger.pyx b/python/rmm/rmm/librmm/_logger.pyx index 4392cb106..57bbf5c62 100644 --- a/python/rmm/rmm/librmm/_logger.pyx +++ b/python/rmm/rmm/librmm/_logger.pyx @@ -11,5 +11,3 @@ # 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. - -from rmm.librmm._logger cimport logging_level # no-cython-lint diff --git a/python/rmm/rmm/pylibrmm/CMakeLists.txt b/python/rmm/rmm/pylibrmm/CMakeLists.txt index 0e88f01bb..cdfe3d67c 100644 --- a/python/rmm/rmm/pylibrmm/CMakeLists.txt +++ b/python/rmm/rmm/pylibrmm/CMakeLists.txt @@ -25,3 +25,7 @@ foreach(_cython_target IN LISTS RAPIDS_CYTHON_CREATED_TARGETS) set_target_properties(${_cython_target} PROPERTIES C_VISIBILITY_PRESET hidden CXX_VISIBILITY_PRESET hidden) endforeach() + +if(TARGET rmm::rmm_logger_impl) + target_link_libraries(logger PRIVATE rmm::rmm_logger_impl) +endif() diff --git a/python/rmm/rmm/pylibrmm/logger.pyx b/python/rmm/rmm/pylibrmm/logger.pyx index 119e1c92f..006568af9 100644 --- a/python/rmm/rmm/pylibrmm/logger.pyx +++ b/python/rmm/rmm/pylibrmm/logger.pyx @@ -14,14 +14,27 @@ import warnings -from rmm.librmm._logger cimport logger +# Note: This must match the LOGGING_COMPATIBILITY setting in CMakeLists.txt for +# the C++ build or the build will fail since the expected symbols will not exist. +DEF LOGGING_COMPATIBILITY = False -from rmm.librmm._logger import logging_level +IF LOGGING_COMPATIBILITY: + from rmm.librmm._logger cimport logger + + from rmm.librmm._logger import logging_level +ELSE: + from rmm.librmm._logger cimport default_logger as logger + + from rmm.librmm._logger import level_enum def _validate_level_type(level): - if not isinstance(level, logging_level): - raise TypeError("level must be an instance of the logging_level enum") + IF LOGGING_COMPATIBILITY: + if not isinstance(level, logging_level): + raise TypeError("level must be an instance of the logging_level enum") + ELSE: + if not isinstance(level, level_enum): + raise TypeError("level must be an instance of the level_enum enum") def should_log(level): @@ -118,7 +131,7 @@ def get_logging_level(): >>> rmm.get_logging_level() # get current logging level """ - return logging_level(logger().level()) + return logger().level() def flush_logger(): @@ -208,4 +221,4 @@ def get_flush_level(): >>> rmm.flush_level() # get current flush level """ - return logging_level(logger().flush_level()) + return logger().flush_level() diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index ae6398965..b1bd808b8 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -180,12 +180,13 @@ function(rapids_make_logger logger_namespace) # Note that we cannot specify the source files directly in add_library, see the CMake # documentation explaining that these do not populate INTERFACE_SOURCES. # https://cmake.org/cmake/help/latest/command/add_library.html#interface-with-sources - add_library(${_RAPIDS_LOGGER_TARGET}_impl INTERFACE) + set(impl_target ${_RAPIDS_LOGGER_TARGET}_impl) + add_library(${impl_target} INTERFACE) target_sources( - ${_RAPIDS_LOGGER_TARGET}_impl + ${impl_target} INTERFACE $ $) - target_link_libraries(${_RAPIDS_LOGGER_TARGET}_impl INTERFACE ${_RAPIDS_LOGGER_TARGET}) + target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET}) endif() endif() @@ -195,5 +196,8 @@ function(rapids_make_logger logger_namespace) endif() install(TARGETS ${_RAPIDS_LOGGER_TARGET} ${_install_export}) + if(TARGET ${impl_target}) + install(TARGETS ${impl_target} ${_install_export}) + endif() endfunction() From bec1a9fb9a170e114f581fd092c7281cfcbe894d Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 4 Nov 2024 17:42:01 +0000 Subject: [PATCH 028/120] Get Python package importable --- python/rmm/CMakeLists.txt | 8 ++++++++ python/rmm/rmm/__init__.py | 13 +++++++++++-- python/rmm/rmm/_cuda/CMakeLists.txt | 2 +- python/rmm/rmm/librmm/CMakeLists.txt | 6 +----- python/rmm/rmm/pylibrmm/CMakeLists.txt | 6 +----- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/python/rmm/CMakeLists.txt b/python/rmm/CMakeLists.txt index ac8495e14..c90ba011c 100644 --- a/python/rmm/CMakeLists.txt +++ b/python/rmm/CMakeLists.txt @@ -29,6 +29,14 @@ rapids_cython_init() # pass through logging level to spdlog add_compile_definitions("SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") +# Create an object library for the logger so that we don't have to recompile it. This assumes that +# we always have logging enabled when we built the C++ library since the targets that are created +# when we find_package(rmm) already have that setting baked in. TODO: Figure out how to use +# define_property in the C++ build to make SUPPORTS_LOGGING a queryable property that can be checked +# here. +add_library(cpp_logger OBJECT) +target_link_libraries(cpp_logger PRIVATE rmm::rmm_logger_impl) + add_subdirectory(rmm/_cuda) add_subdirectory(rmm/librmm) add_subdirectory(rmm/pylibrmm) diff --git a/python/rmm/rmm/__init__.py b/python/rmm/rmm/__init__.py index 832fec095..1c559723f 100644 --- a/python/rmm/rmm/__init__.py +++ b/python/rmm/rmm/__init__.py @@ -22,11 +22,20 @@ flush_logger, get_flush_level, get_logging_level, - logging_level, set_flush_level, set_logging_level, should_log, ) + +try: + from rmm.pylibrmm.logger import logging_level + + logging_level_var = "logging_level" +except ImportError: + from rmm.pylibrmm.logger import level_enum + + logging_level_var = "level_enum" + from rmm.rmm import ( RMMError, is_initialized, @@ -45,7 +54,7 @@ "get_log_filenames", "get_logging_level", "is_initialized", - "logging_level", + logging_level_var, "mr", "register_reinitialize_hook", "reinitialize", diff --git a/python/rmm/rmm/_cuda/CMakeLists.txt b/python/rmm/rmm/_cuda/CMakeLists.txt index 7fd27d110..7759432d3 100644 --- a/python/rmm/rmm/_cuda/CMakeLists.txt +++ b/python/rmm/rmm/_cuda/CMakeLists.txt @@ -13,7 +13,7 @@ # ============================================================================= set(cython_sources stream.pyx) -set(linked_libraries rmm::rmm) +set(linked_libraries rmm::rmm cpp_logger) rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" CXX) diff --git a/python/rmm/rmm/librmm/CMakeLists.txt b/python/rmm/rmm/librmm/CMakeLists.txt index 82d0bc6ac..dc807fdba 100644 --- a/python/rmm/rmm/librmm/CMakeLists.txt +++ b/python/rmm/rmm/librmm/CMakeLists.txt @@ -13,7 +13,7 @@ # ============================================================================= set(cython_sources _logger.pyx) -set(linked_libraries rmm::rmm) +set(linked_libraries rmm::rmm cpp_logger) # Build all of the Cython targets rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" @@ -33,7 +33,3 @@ target_link_libraries(_torch_allocator PRIVATE rmm::rmm) cmake_path(RELATIVE_PATH CMAKE_CURRENT_SOURCE_DIR BASE_DIRECTORY "${PROJECT_SOURCE_DIR}" OUTPUT_VARIABLE _torch_allocator_location) install(TARGETS _torch_allocator DESTINATION "${_torch_allocator_location}") - -if(TARGET rmm::rmm_logger_impl) - target_link_libraries(_logger PRIVATE rmm::rmm_logger_impl) -endif() diff --git a/python/rmm/rmm/pylibrmm/CMakeLists.txt b/python/rmm/rmm/pylibrmm/CMakeLists.txt index cdfe3d67c..0012cb93d 100644 --- a/python/rmm/rmm/pylibrmm/CMakeLists.txt +++ b/python/rmm/rmm/pylibrmm/CMakeLists.txt @@ -13,7 +13,7 @@ # ============================================================================= set(cython_sources device_buffer.pyx logger.pyx memory_resource.pyx cuda_stream.pyx helper.pyx) -set(linked_libraries rmm::rmm) +set(linked_libraries rmm::rmm cpp_logger) # Build all of the Cython targets rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" @@ -25,7 +25,3 @@ foreach(_cython_target IN LISTS RAPIDS_CYTHON_CREATED_TARGETS) set_target_properties(${_cython_target} PROPERTIES C_VISIBILITY_PRESET hidden CXX_VISIBILITY_PRESET hidden) endforeach() - -if(TARGET rmm::rmm_logger_impl) - target_link_libraries(logger PRIVATE rmm::rmm_logger_impl) -endif() From 0be4979ddb628eb70ca6d8726b5da16c3062fc7a Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 4 Nov 2024 18:52:40 +0000 Subject: [PATCH 029/120] Get all tests passing --- python/rmm/rmm/__init__.py | 1 + python/rmm/rmm/tests/test_rmm.py | 17 ++++++++++++++--- rapids_logger/logger_impl.hpp.in | 2 +- tests/mr/device/arena_mr_tests.cpp | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/python/rmm/rmm/__init__.py b/python/rmm/rmm/__init__.py index 1c559723f..5d431eba3 100644 --- a/python/rmm/rmm/__init__.py +++ b/python/rmm/rmm/__init__.py @@ -27,6 +27,7 @@ should_log, ) +# TODO: Clean up after we remove legacy logging. try: from rmm.pylibrmm.logger import logging_level diff --git a/python/rmm/rmm/tests/test_rmm.py b/python/rmm/rmm/tests/test_rmm.py index b52ea0179..085185b97 100644 --- a/python/rmm/rmm/tests/test_rmm.py +++ b/python/rmm/rmm/tests/test_rmm.py @@ -30,6 +30,13 @@ from rmm.allocators.cupy import rmm_cupy_allocator from rmm.allocators.numba import RMMNumbaManager +# TODO: Clean up after we remove legacy logging. +try: + from rmm.pylibrmm.logger import logging_level +except ImportError: + from rmm.pylibrmm.logger import level_enum as logging_level + + cuda.set_memory_manager(RMMNumbaManager) _driver_version = rmm._cuda.gpu.driverGetVersion() @@ -1055,8 +1062,12 @@ def test_rmm_device_buffer_copy(cuda_ary, make_copy): np.testing.assert_equal(expected, result) -@pytest.mark.parametrize("level", rmm.logging_level) +@pytest.mark.parametrize("level", logging_level) def test_valid_logging_level(level): + # TODO: Clean up after we remove legacy logging. + default_level = getattr( + logging_level, "INFO", getattr(logging_level, "info") + ) with warnings.catch_warnings(): warnings.filterwarnings( "ignore", message="RMM will not log logging_level.TRACE." @@ -1066,11 +1077,11 @@ def test_valid_logging_level(level): ) rmm.set_logging_level(level) assert rmm.get_logging_level() == level - rmm.set_logging_level(rmm.logging_level.INFO) # reset to default + rmm.set_logging_level(default_level) # reset to default rmm.set_flush_level(level) assert rmm.get_flush_level() == level - rmm.set_flush_level(rmm.logging_level.INFO) # reset to default + rmm.set_flush_level(default_level) # reset to default rmm.should_log(level) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index d7ac90ec7..fa6050f37 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -158,7 +158,7 @@ BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& mess BACKWARDS_COMPAT_INLINE void logger::set_level(level_enum log_level) { pImpl->set_level(log_level); } BACKWARDS_COMPAT_INLINE void logger::flush() { pImpl->flush(); } BACKWARDS_COMPAT_INLINE void logger::flush_on(level_enum log_level) { pImpl->flush_on(log_level); } -BACKWARDS_COMPAT_INLINE level_enum logger::flush_level() const { return pImpl->level(); } +BACKWARDS_COMPAT_INLINE level_enum logger::flush_level() const { return pImpl->flush_level(); } BACKWARDS_COMPAT_INLINE bool logger::should_log(level_enum lvl) const { return pImpl->should_log(lvl); } BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { pImpl->add_sink(sink); } BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { pImpl->remove_sink(sink); } diff --git a/tests/mr/device/arena_mr_tests.cpp b/tests/mr/device/arena_mr_tests.cpp index 95cc9c9c1..a8e424931 100644 --- a/tests/mr/device/arena_mr_tests.cpp +++ b/tests/mr/device/arena_mr_tests.cpp @@ -588,9 +588,11 @@ TEST_F(ArenaTest, DumpLogOnFailure) // NOLINT // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto) EXPECT_THROW(mr.allocate(8_MiB), rmm::out_of_memory); +#ifdef SUPPORTS_LOGGING struct stat file_status {}; EXPECT_EQ(stat("rmm_arena_memory_dump.log", &file_status), 0); EXPECT_GE(file_status.st_size, 0); +#endif } } // namespace From 0d6b118f50124da4cd06bbaa77093ca263b4ef59 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 4 Nov 2024 18:55:16 +0000 Subject: [PATCH 030/120] Consolidate enum conversion --- rapids_logger/logger_impl.hpp.in | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index fa6050f37..9093b1bf6 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -63,7 +63,7 @@ struct impl { */ void log(level_enum lvl, const std::string& message) { - underlying.log(static_cast(static_cast(lvl)), message); + underlying.log(to_spdlog_level(lvl), message); } /** @@ -73,7 +73,7 @@ struct impl { */ void set_level(level_enum log_level) { - underlying.set_level(static_cast(static_cast(log_level))); + underlying.set_level(to_spdlog_level(log_level)); } /** @@ -89,7 +89,7 @@ struct impl { */ void flush_on(level_enum log_level) { - underlying.flush_on(static_cast(static_cast(log_level))); + underlying.flush_on(to_spdlog_level(log_level)); } /** @@ -99,13 +99,12 @@ struct impl { */ level_enum flush_level() const { - return static_cast(static_cast(underlying.flush_level())); + return from_spdlog_level(underlying.flush_level()); } - // TODO: Add conversion functions for spdlog::level::level_enum bool should_log(level_enum lvl) const { - return underlying.should_log(static_cast(static_cast(lvl))); + return underlying.should_log(to_spdlog_level(lvl)); } /** @@ -134,7 +133,17 @@ struct impl { */ level_enum level() const { - return static_cast(static_cast(underlying.level())); + return from_spdlog_level(underlying.level()); + } + + spdlog::level::level_enum to_spdlog_level(level_enum lvl) const + { + return static_cast(static_cast(lvl)); + } + + level_enum from_spdlog_level(spdlog::level::level_enum lvl) const + { + return static_cast(static_cast(lvl)); } }; From adae837a4dfe1b65bfea6035ddd732509663ffd6 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 6 Nov 2024 00:42:02 +0000 Subject: [PATCH 031/120] Make logger work with cudf --- CMakeLists.txt | 7 +++++-- rapids_logger/CMakeLists.txt | 18 +++++++++++++--- rapids_logger/logger.hpp.in | 24 +++++++++++----------- rapids_logger/logger_impl.hpp.in | 35 +++++++++++++++++++++++++++----- 4 files changed, 62 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3c7f19f5..2ca1986b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,13 +84,16 @@ rapids_cpm_init() add_subdirectory(rapids_logger) if(LOGGING_COMPATIBILITY) - rapids_make_logger(rmm EXPORT_SET rmm-exports SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) + rapids_make_logger( + rmm EXPORT_SET rmm-exports VISIBILITY_MACRO "__attribute__((visibility(\"default\")))" + SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) else() set(_logging_support_flag) if(SUPPORTS_LOGGING) set(_logging_support_flag "SUPPORTS_LOGGING") endif() - rapids_make_logger(rmm EXPORT_SET rmm-exports ${_logging_support_flag}) + rapids_make_logger(rmm EXPORT_SET rmm-exports VISIBILITY_MACRO + "__attribute__((visibility(\"default\")))" ${_logging_support_flag}) endif() include(cmake/thirdparty/get_cccl.cmake) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index b1bd808b8..e436b03e7 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -50,8 +50,10 @@ Generate a logger implementation customized for the specified namespace. [LOGGER_TARGET ] [LOGGER_HEADER_DIR ] [LOGGER_MACRO_PREFIX ] + [VISIBILITY_MACRO ] [SUPPORTS_LOGGING] [RMM_BACKWARDS_COMPATIBILITY] + [CUDF_BACKWARDS_COMPATIBILITY] ) This function produces an interface target named that, when linked to by other targets, provides them a header file that defines a logger interface for the specified namespace. The logger is generated from the provided template files and is configured to use the specified namespace and macro prefix. The generated logger is placed in the specified header directory. @@ -76,11 +78,17 @@ When not using backwards compatibility mode, the logger implementation (which li ``LOGGER_MACRO_PREFIX`` The prefix to use for the logger macros. If not specified, the macro prefix is the uppercase version of the logger namespace. +``VISIBILITY_MACRO`` + The macro to use for visibility annotations. If not specified, no visibility annotations are added to the logger interface. + ``SUPPORTS_LOGGING`` If specified, the logger target is configured to support logging. If not specified, the resulting logger is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. This setting is required for the logger implementation to be generated. It will be automatically turned on if `RMM_BACKWARDS_COMPATIBILITY` is specified. ``RMM_BACKWARDS_COMPATIBILITY`` - If specified, the logger target is configured to support backwards compatibility with RMM. In backwards-compatibility mode, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. In this mode, `SUPPORTS_LOGGING` is always true. + If specified, the logger target is configured to support backwards compatibility with RMM. In backwards-compatibility mode, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. In this mode, `SUPPORTS_LOGGING` is always true. In addition, the underlying spdlog logger is exposed in public APIs when this flag is enabled (with suitable deprecation warnings). + +``CUDF_BACKWARDS_COMPATIBILITY`` + If specified, the underlying spdlog logger is exposed in public APIs when this flag is enabled (with suitable deprecation warnings). Result Targets @@ -115,8 +123,9 @@ Example on how to use :cmake:command:`rapids_make_logger`. function(rapids_make_logger logger_namespace) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") - set(_rapids_options RMM_BACKWARDS_COMPATIBILITY SUPPORTS_LOGGING) - set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX) + set(_rapids_options RMM_BACKWARDS_COMPATIBILITY CUDF_BACKWARDS_COMPATIBILITY SUPPORTS_LOGGING) + set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX + VISIBILITY_MACRO) set(_rapids_multi_value) cmake_parse_arguments(_RAPIDS "${_rapids_options}" "${_rapids_one_value}" "${_rapids_multi_value}" ${ARGN}) @@ -166,6 +175,9 @@ function(rapids_make_logger logger_namespace) endif() target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE RMM_BACKWARDS_COMPATIBILITY) endif() + if(_RAPIDS_CUDF_BACKWARDS_COMPATIBILITY) + target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE CUDF_BACKWARDS_COMPATIBILITY) + endif() if(_RAPIDS_SUPPORTS_LOGGING) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE SUPPORTS_LOGGING) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index e98f0acc2..018d86384 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -14,11 +14,9 @@ * limitations under the License. */ -// TODO: Add RMM_EXPORT tags or equivalent - #pragma once -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY #include #endif @@ -48,7 +46,7 @@ using sink_ptr = std::shared_ptr; #endif -namespace @_RAPIDS_LOGGER_NAMESPACE@ { +namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { @@ -63,6 +61,8 @@ namespace detail { inline std::string default_log_filename() { auto* filename = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEBUG_LOG_FILE"); + // TODO: Do we prefer rmm's default (a file rmm_log.txt) or cudf's default (a + // stderr sink)? I think the latter is better. return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; } @@ -370,14 +370,14 @@ class logger { log(level_enum::critical, format, std::forward(args)...); } -#ifndef RMM_BACKWARDS_COMPATIBILITY +#ifndef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY private: #endif #ifdef SUPPORTS_LOGGING std::unique_ptr pImpl{}; ///< pimpl idiom #endif -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY private: #endif // TODO: When we migrate to C++20 we can use std::format and format strings @@ -430,7 +430,7 @@ class logger { }; -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { /** @@ -440,7 +440,7 @@ namespace detail { * * @return logger& The default logger */ -inline logger& default_logger(); +logger& default_logger(); /** * @brief Get the default logger. @@ -449,12 +449,12 @@ inline logger& default_logger(); * * @return spdlog::logger& The default logger's underlying spdlog logger */ -inline spdlog::logger& logger(); +spdlog::logger& logger(); } // namespace detail #endif -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY inline logger& default_logger() { return detail::default_logger(); } [[deprecated( @@ -492,7 +492,7 @@ inline logger& default_logger() // Macros for easier logging, similar to spdlog. // TODO: The macros below assume that we want to respect spdlog's level macros // rather than the ones defined by this file. -#define RMM_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_TRACE(...) \ @@ -536,6 +536,6 @@ inline logger& default_logger() } // namespace @_RAPIDS_LOGGER_NAMESPACE@ -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY +#ifdef RMM_BACKWARDS_COMPATIBILITY #include "logger_impl/logger_impl.hpp" #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 9093b1bf6..bd77c14aa 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -29,11 +29,29 @@ #include #include +#include + namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { +level_enum string_to_level(std::string_view const env_lvl_str) +{ + if (env_lvl_str == "TRACE") return level_enum::trace; + if (env_lvl_str == "DEBUG") return level_enum::debug; + if (env_lvl_str == "INFO") return level_enum::info; + if (env_lvl_str == "WARN") return level_enum::warn; + if (env_lvl_str == "ERROR") return level_enum::error; + if (env_lvl_str == "CRITICAL") return level_enum::critical; + if (env_lvl_str == "OFF") return level_enum::off; + std::ostringstream os{}; + os << "Invalid logging level: " << env_lvl_str; + throw std::invalid_argument(os.str()); +} + + + /** * @brief The real implementation of the logger using spdlog with a basic file sink. */ @@ -52,7 +70,14 @@ struct impl { )} { underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); - flush_on(level_enum::warn); + auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); + if (env_logging_level != nullptr) { + set_level(string_to_level(env_logging_level)); + } + auto const env_flush_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_FLUSH_LEVEL"); + if (env_flush_level != nullptr) { + flush_on(string_to_level(env_flush_level)); + } } /** @@ -156,7 +181,7 @@ BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) BACKWARDS_COMPAT_INLINE logger::~logger() = default; BACKWARDS_COMPAT_INLINE logger::logger(logger&&) = default; -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY BACKWARDS_COMPAT_INLINE class logger& logger::operator=(logger&&) = default; #else BACKWARDS_COMPAT_INLINE logger& logger::operator=(logger&&) = default; @@ -173,10 +198,10 @@ BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { pImpl->ad BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { pImpl->remove_sink(sink); } BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return pImpl->level(); } -#ifdef RMM_BACKWARDS_COMPATIBILITY +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { -inline class logger& default_logger() +class logger& default_logger() { static class logger logger_ = [] { class logger logger_ { @@ -194,7 +219,7 @@ inline class logger& default_logger() return logger_; } -inline class spdlog::logger& logger() { return default_logger().pImpl->underlying; } +class spdlog::logger& logger() { return default_logger().pImpl->underlying; } } // namespace detail #endif From b422af62c7e2acf1987e3e88f5fdd346f2b75fb1 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 6 Nov 2024 22:46:51 +0000 Subject: [PATCH 032/120] Go back to compatibility mode for now --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ca1986b3..7f7d342aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" OFF) +option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) option(SUPPORTS_LOGGING "Enable logging support" ON) if(LOGGING_COMPATIBILITY) if(NOT SUPPORTS_LOGGING) From f7ae2be545d91f0925453f21146f686243f9ff03 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 00:45:31 +0000 Subject: [PATCH 033/120] Fix benchmarks --- benchmarks/replay/replay.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benchmarks/replay/replay.cpp b/benchmarks/replay/replay.cpp index 5afed036a..76632175f 100644 --- a/benchmarks/replay/replay.cpp +++ b/benchmarks/replay/replay.cpp @@ -172,7 +172,7 @@ struct replay_benchmark { void SetUp(const ::benchmark::State& state) { if (state.thread_index() == 0) { - rmm::logger().log(spdlog::level::info, "------ Start of Benchmark -----"); + rmm::detail::logger().log(spdlog::level::info, "------ Start of Benchmark -----"); mr_ = factory_(simulated_size_); } } @@ -181,7 +181,7 @@ struct replay_benchmark { void TearDown(const ::benchmark::State& state) { if (state.thread_index() == 0) { - rmm::logger().log(spdlog::level::info, "------ End of Benchmark -----"); + rmm::detail::logger().log(spdlog::level::info, "------ End of Benchmark -----"); // clean up any leaked allocations std::size_t total_leaked{0}; std::size_t num_leaked{0}; @@ -402,7 +402,7 @@ int main(int argc, char** argv) auto const num_threads = per_thread_events.size(); // Uncomment to enable / change default log level - // rmm::logger().set_level(spdlog::level::trace); + // rmm::detail::logger().set_level(spdlog::level::trace); if (args.count("resource") > 0) { std::string mr_name = args["resource"].as(); From 6a3028c540eeada2540ab25160567d70a936109f Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 00:49:43 +0000 Subject: [PATCH 034/120] Comment out bits in the Python build that we don't need yet --- python/rmm/CMakeLists.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/rmm/CMakeLists.txt b/python/rmm/CMakeLists.txt index c90ba011c..b3a4b81f3 100644 --- a/python/rmm/CMakeLists.txt +++ b/python/rmm/CMakeLists.txt @@ -33,9 +33,8 @@ add_compile_definitions("SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") # we always have logging enabled when we built the C++ library since the targets that are created # when we find_package(rmm) already have that setting baked in. TODO: Figure out how to use # define_property in the C++ build to make SUPPORTS_LOGGING a queryable property that can be checked -# here. -add_library(cpp_logger OBJECT) -target_link_libraries(cpp_logger PRIVATE rmm::rmm_logger_impl) +# here. add_library(cpp_logger OBJECT) target_link_libraries(cpp_logger PRIVATE +# "$") add_subdirectory(rmm/_cuda) add_subdirectory(rmm/librmm) From afc4dcf725fb12754e966d9607197e0a53bbb862 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 01:12:02 +0000 Subject: [PATCH 035/120] Fix the flag in Python --- python/rmm/rmm/librmm/_logger.pxd | 2 +- python/rmm/rmm/pylibrmm/logger.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/rmm/rmm/librmm/_logger.pxd b/python/rmm/rmm/librmm/_logger.pxd index 5359e8d9a..24a4adc55 100644 --- a/python/rmm/rmm/librmm/_logger.pxd +++ b/python/rmm/rmm/librmm/_logger.pxd @@ -17,7 +17,7 @@ from libcpp.string cimport string # Note: This must match the LOGGING_COMPATIBILITY setting in CMakeLists.txt for # the C++ build or the build will fail since the expected symbols will not exist. -DEF LOGGING_COMPATIBILITY = False +DEF LOGGING_COMPATIBILITY = True # Conditional compilation in Cython is deprecated, but we will remove the need # for it here before that becomes an issue; this conditional just exists to diff --git a/python/rmm/rmm/pylibrmm/logger.pyx b/python/rmm/rmm/pylibrmm/logger.pyx index 006568af9..7c4bd1257 100644 --- a/python/rmm/rmm/pylibrmm/logger.pyx +++ b/python/rmm/rmm/pylibrmm/logger.pyx @@ -16,7 +16,7 @@ import warnings # Note: This must match the LOGGING_COMPATIBILITY setting in CMakeLists.txt for # the C++ build or the build will fail since the expected symbols will not exist. -DEF LOGGING_COMPATIBILITY = False +DEF LOGGING_COMPATIBILITY = True IF LOGGING_COMPATIBILITY: from rmm.librmm._logger cimport logger From 47143225a8a5703b40653844e23506f1179fa95e Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 17:01:25 +0000 Subject: [PATCH 036/120] Temporarily reinstate inline keyword to get rmm working. --- rapids_logger/logger.hpp.in | 6 ++++-- rapids_logger/logger_impl.hpp.in | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 018d86384..0f8aa93e4 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -432,6 +432,8 @@ class logger { #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { +// TODO: These functions need to be inline for rmm but they cannot be for cudf. +// This is only relevant in backwards compatibility mode, though. /** * @brief Get the default logger. @@ -440,7 +442,7 @@ namespace detail { * * @return logger& The default logger */ -logger& default_logger(); +inline logger& default_logger(); /** * @brief Get the default logger. @@ -449,7 +451,7 @@ logger& default_logger(); * * @return spdlog::logger& The default logger's underlying spdlog logger */ -spdlog::logger& logger(); +inline spdlog::logger& logger(); } // namespace detail #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index bd77c14aa..93101a5f7 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -36,7 +36,7 @@ namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { -level_enum string_to_level(std::string_view const env_lvl_str) +inline level_enum string_to_level(std::string_view const env_lvl_str) { if (env_lvl_str == "TRACE") return level_enum::trace; if (env_lvl_str == "DEBUG") return level_enum::debug; From 08cb91bace3eb548ba2e1aba037bf86d424f271b Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 17:12:24 +0000 Subject: [PATCH 037/120] Make Python target selection safe in all modes --- python/rmm/rmm/_cuda/CMakeLists.txt | 6 +++++- python/rmm/rmm/librmm/CMakeLists.txt | 6 +++++- python/rmm/rmm/pylibrmm/CMakeLists.txt | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/python/rmm/rmm/_cuda/CMakeLists.txt b/python/rmm/rmm/_cuda/CMakeLists.txt index 7759432d3..1b9687768 100644 --- a/python/rmm/rmm/_cuda/CMakeLists.txt +++ b/python/rmm/rmm/_cuda/CMakeLists.txt @@ -13,7 +13,11 @@ # ============================================================================= set(cython_sources stream.pyx) -set(linked_libraries rmm::rmm cpp_logger) +if(TARGET cpp_logger) + set(linked_libraries rmm::rmm cpp_logger) +else() + set(linked_libraries rmm::rmm) +endif() rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" CXX) diff --git a/python/rmm/rmm/librmm/CMakeLists.txt b/python/rmm/rmm/librmm/CMakeLists.txt index dc807fdba..895a3f1ed 100644 --- a/python/rmm/rmm/librmm/CMakeLists.txt +++ b/python/rmm/rmm/librmm/CMakeLists.txt @@ -13,7 +13,11 @@ # ============================================================================= set(cython_sources _logger.pyx) -set(linked_libraries rmm::rmm cpp_logger) +if(TARGET cpp_logger) + set(linked_libraries rmm::rmm cpp_logger) +else() + set(linked_libraries rmm::rmm) +endif() # Build all of the Cython targets rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" diff --git a/python/rmm/rmm/pylibrmm/CMakeLists.txt b/python/rmm/rmm/pylibrmm/CMakeLists.txt index 0012cb93d..962efcbe2 100644 --- a/python/rmm/rmm/pylibrmm/CMakeLists.txt +++ b/python/rmm/rmm/pylibrmm/CMakeLists.txt @@ -13,7 +13,11 @@ # ============================================================================= set(cython_sources device_buffer.pyx logger.pyx memory_resource.pyx cuda_stream.pyx helper.pyx) -set(linked_libraries rmm::rmm cpp_logger) +if(TARGET cpp_logger) + set(linked_libraries rmm::rmm cpp_logger) +else() + set(linked_libraries rmm::rmm) +endif() # Build all of the Cython targets rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" From aaf4b7c64da9166d2c63cb00a07f86a200dd27bc Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 18:04:31 +0000 Subject: [PATCH 038/120] Address first round of feedback --- CMakeLists.txt | 1 - rapids_logger/CMakeLists.txt | 6 +++++- tests/CMakeLists.txt | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f7d342aa..5db556585 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,7 +119,6 @@ endif() target_link_libraries(rmm INTERFACE rmm_logger) target_link_libraries(rmm INTERFACE CCCL::CCCL) target_link_libraries(rmm INTERFACE fmt::fmt-header-only) -target_link_libraries(rmm INTERFACE spdlog::spdlog_header_only) target_link_libraries(rmm INTERFACE dl) target_link_libraries(rmm INTERFACE nvtx3::nvtx3-cpp) target_compile_features(rmm INTERFACE cxx_std_17 $) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index e436b03e7..781e7e874 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -168,6 +168,7 @@ function(rapids_make_logger logger_namespace) ${_RAPIDS_LOGGER_TARGET} INTERFACE "$" "$") + target_compile_features(${_RAPIDS_LOGGER_TARGET} INTERFACE cxx_std_17) if(_RAPIDS_RMM_BACKWARDS_COMPATIBILITY) if(NOT _RAPIDS_SUPPORTS_LOGGING) message(STATUS "RMM_BACKWARDS_COMPATIBILITY requires SUPPORTS_LOGGING, turning it on") @@ -198,7 +199,10 @@ function(rapids_make_logger logger_namespace) ${impl_target} INTERFACE $ $) - target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET}) + target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} + spdlog::spdlog_header_only) + else() + target_link_libraries(${_RAPIDS_LOGGER_TARGET} INTERFACE spdlog::spdlog_header_only) endif() endif() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c0009c013..90d912be6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,7 +46,7 @@ function(ConfigureTestInternal TEST_NAME) # When not building in compatibility mode, each test has to recompile the headers. if(TARGET rmm_test_logger) - target_link_libraries(${TEST_NAME} rmm_test_logger) + target_link_libraries(${TEST_NAME} PRIVATE rmm_test_logger) endif() if(DISABLE_DEPRECATION_WARNING) From 7c9134c81286ac56d7b7637b7cba5e71e426f034 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 18:16:15 +0000 Subject: [PATCH 039/120] Prefix new CMake variables with RMM_ and ensure that SUPPORTS_LOGGING flags are specific to each project embedding a logger --- CMakeLists.txt | 16 ++++++++-------- rapids_logger/CMakeLists.txt | 3 ++- rapids_logger/logger.hpp.in | 8 ++++---- tests/CMakeLists.txt | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5db556585..19b3dc965 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,12 +58,12 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -option(LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) -option(SUPPORTS_LOGGING "Enable logging support" ON) -if(LOGGING_COMPATIBILITY) - if(NOT SUPPORTS_LOGGING) - message(STATUS "LOGGING_COMPATIBILITY requires SUPPORTS_LOGGING to be enabled") - set(SUPPORTS_LOGGING ON) +option(RMM_LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) +option(RMM_SUPPORTS_LOGGING "Enable logging support" ON) +if(RMM_LOGGING_COMPATIBILITY) + if(NOT RMM_SUPPORTS_LOGGING) + message(STATUS "RMM_LOGGING_COMPATIBILITY requires RMM_SUPPORTS_LOGGING to be enabled") + set(RMM_SUPPORTS_LOGGING ON) endif() endif() @@ -83,13 +83,13 @@ rapids_find_package( rapids_cpm_init() add_subdirectory(rapids_logger) -if(LOGGING_COMPATIBILITY) +if(RMM_LOGGING_COMPATIBILITY) rapids_make_logger( rmm EXPORT_SET rmm-exports VISIBILITY_MACRO "__attribute__((visibility(\"default\")))" SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) else() set(_logging_support_flag) - if(SUPPORTS_LOGGING) + if(RMM_SUPPORTS_LOGGING) set(_logging_support_flag "SUPPORTS_LOGGING") endif() rapids_make_logger(rmm EXPORT_SET rmm-exports VISIBILITY_MACRO diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 781e7e874..56b15423e 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -180,7 +180,8 @@ function(rapids_make_logger logger_namespace) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE CUDF_BACKWARDS_COMPATIBILITY) endif() if(_RAPIDS_SUPPORTS_LOGGING) - target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE SUPPORTS_LOGGING) + target_compile_definitions(${_RAPIDS_LOGGER_TARGET} + INTERFACE "${_RAPIDS_LOGGER_MACRO_PREFIX}_SUPPORTS_LOGGING") if(NOT _RAPIDS_RMM_BACKWARDS_COMPATIBILITY) # Create an interface target that will trigger compilation of the logger implementation in any diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 0f8aa93e4..6763f6c8a 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -34,7 +34,7 @@ #include #include -#ifdef SUPPORTS_LOGGING +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING // Forward declare spdlog types that are part of our public API. namespace spdlog { @@ -162,7 +162,7 @@ enum class level_enum : int32_t { */ class logger { public: -#ifdef SUPPORTS_LOGGING +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING /** * @brief Construct a new logger object * @@ -187,7 +187,7 @@ class logger { BACKWARDS_COMPAT_INLINE logger(logger&&); ///< @default_move_constructor BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); ///< @default_move_assignment{logger} -#ifdef SUPPORTS_LOGGING +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING /** * @brief Log a message at the specified level. * @@ -373,7 +373,7 @@ class logger { #ifndef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY private: #endif -#ifdef SUPPORTS_LOGGING +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING std::unique_ptr pImpl{}; ///< pimpl idiom #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 90d912be6..7a1a744df 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -125,7 +125,7 @@ endfunction() # Create an object library for the logger so that we don't have to recompile it. This is not # necessary if logging is unsupported since then the header-only implementation is sufficient. -if(SUPPORTS_LOGGING AND NOT LOGGING_COMPATIBILITY) +if(SUPPORTS_LOGGING AND NOT RMM_LOGGING_COMPATIBILITY) add_library(rmm_test_logger OBJECT) target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) endif() From 8fd90360dc2c411ffcf32977c9eb6cd071015592 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 19:10:33 +0000 Subject: [PATCH 040/120] Get tests and benchmarks fully working when building without compatibility mode. --- benchmarks/CMakeLists.txt | 17 +++++++++++++++-- benchmarks/replay/replay.cpp | 12 ++++++++++++ include/rmm/mr/device/detail/arena.hpp | 2 ++ tests/CMakeLists.txt | 9 +++++---- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 9dfb2c538..54ceffbca 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,5 +1,5 @@ # ============================================================================= -# Copyright (c) 2018-2020, NVIDIA CORPORATION. +# Copyright (c) 2018-2024, 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 @@ -34,7 +34,7 @@ function(ConfigureBench BENCH_NAME) RUNTIME_OUTPUT_DIRECTORY "$" CUDA_ARCHITECTURES "${CMAKE_CUDA_ARCHITECTURES}" INSTALL_RPATH "\$ORIGIN/../../../lib") - target_link_libraries(${BENCH_NAME} benchmark::benchmark pthread rmm) + target_link_libraries(${BENCH_NAME} PRIVATE benchmark::benchmark pthread rmm) target_compile_definitions(${BENCH_NAME} PUBLIC "SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") @@ -45,6 +45,12 @@ function(ConfigureBench BENCH_NAME) target_compile_options( ${BENCH_NAME} PUBLIC $<$:-Wall -Werror -Wno-error=deprecated-declarations -Wno-unknown-pragmas>) + + # When not building in compatibility mode, each benchmark has to recompile the logger. + if(TARGET rmm_bench_logger) + target_link_libraries(${BENCH_NAME} PRIVATE rmm_bench_logger) + endif() + if(DISABLE_DEPRECATION_WARNING) target_compile_options( ${BENCH_NAME} PUBLIC $<$:-Xcompiler=-Wno-deprecated-declarations>) @@ -59,6 +65,13 @@ function(ConfigureBench BENCH_NAME) EXCLUDE_FROM_ALL) endfunction(ConfigureBench) +# Create an object library for the logger so that we don't have to recompile it. This is not +# necessary if logging is unsupported since then the header-only implementation is sufficient. +if(RMM_SUPPORTS_LOGGING AND NOT RMM_LOGGING_COMPATIBILITY) + add_library(rmm_bench_logger OBJECT) + target_link_libraries(rmm_bench_logger PRIVATE rmm_logger_impl) +endif() + # random allocations benchmark ConfigureBench(RANDOM_ALLOCATIONS_BENCH random_allocations/random_allocations.cpp) diff --git a/benchmarks/replay/replay.cpp b/benchmarks/replay/replay.cpp index 76632175f..6cbc37889 100644 --- a/benchmarks/replay/replay.cpp +++ b/benchmarks/replay/replay.cpp @@ -32,10 +32,14 @@ #include #include #include + +#ifdef RMM_BACKWARDS_COMPATIBILITY #include +#endif #include #include +#include #include #include #include @@ -172,7 +176,11 @@ struct replay_benchmark { void SetUp(const ::benchmark::State& state) { if (state.thread_index() == 0) { +#ifdef RMM_BACKWARDS_COMPATIBILITY rmm::detail::logger().log(spdlog::level::info, "------ Start of Benchmark -----"); +#else + rmm::default_logger().log(rmm::level_enum::info, "------ Start of Benchmark -----"); +#endif mr_ = factory_(simulated_size_); } } @@ -181,7 +189,11 @@ struct replay_benchmark { void TearDown(const ::benchmark::State& state) { if (state.thread_index() == 0) { +#ifdef RMM_BACKWARDS_COMPATIBILITY rmm::detail::logger().log(spdlog::level::info, "------ End of Benchmark -----"); +#else + rmm::default_logger().log(rmm::level_enum::info, "------ End of Benchmark -----"); +#endif // clean up any leaked allocations std::size_t total_leaked{0}; std::size_t num_leaked{0}; diff --git a/include/rmm/mr/device/detail/arena.hpp b/include/rmm/mr/device/detail/arena.hpp index a7fcd02f7..63ed1a77e 100644 --- a/include/rmm/mr/device/detail/arena.hpp +++ b/include/rmm/mr/device/detail/arena.hpp @@ -28,7 +28,9 @@ #include #include +#ifdef RMM_BACKWARDS_COMPATIBILITY #include +#endif #include #include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7a1a744df..8c64c3781 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,8 +27,9 @@ rapids_cmake_support_conda_env(conda_env) function(ConfigureTestInternal TEST_NAME) add_executable(${TEST_NAME} ${ARGN}) target_include_directories(${TEST_NAME} PRIVATE "$") - target_link_libraries(${TEST_NAME} GTest::gmock GTest::gtest GTest::gmock_main GTest::gtest_main - pthread rmm $) + target_link_libraries( + ${TEST_NAME} PRIVATE GTest::gmock GTest::gtest GTest::gmock_main GTest::gtest_main pthread rmm + $) set_target_properties( ${TEST_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON @@ -44,7 +45,7 @@ function(ConfigureTestInternal TEST_NAME) target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror -Wno-error=deprecated-declarations>) - # When not building in compatibility mode, each test has to recompile the headers. + # When not building in compatibility mode, each testhas to recompile the logger. if(TARGET rmm_test_logger) target_link_libraries(${TEST_NAME} PRIVATE rmm_test_logger) endif() @@ -125,7 +126,7 @@ endfunction() # Create an object library for the logger so that we don't have to recompile it. This is not # necessary if logging is unsupported since then the header-only implementation is sufficient. -if(SUPPORTS_LOGGING AND NOT RMM_LOGGING_COMPATIBILITY) +if(RMM_SUPPORTS_LOGGING AND NOT RMM_LOGGING_COMPATIBILITY) add_library(rmm_test_logger OBJECT) target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) endif() From e6ec9f41c9841ce0cb7a7672ddfb9c54dda5b852 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 19:16:50 +0000 Subject: [PATCH 041/120] Fix tests --- python/rmm/rmm/tests/test_rmm.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/rmm/rmm/tests/test_rmm.py b/python/rmm/rmm/tests/test_rmm.py index 085185b97..002507c3c 100644 --- a/python/rmm/rmm/tests/test_rmm.py +++ b/python/rmm/rmm/tests/test_rmm.py @@ -1065,8 +1065,10 @@ def test_rmm_device_buffer_copy(cuda_ary, make_copy): @pytest.mark.parametrize("level", logging_level) def test_valid_logging_level(level): # TODO: Clean up after we remove legacy logging. - default_level = getattr( - logging_level, "INFO", getattr(logging_level, "info") + # Note that we cannot specify the default value to getattr since that would + # always be run, but with `or` we can rely on short-circuiting. + default_level = getattr(logging_level, "INFO") or getattr( + logging_level, "info" ) with warnings.catch_warnings(): warnings.filterwarnings( From 62efe4407b992bfd9d2d961a02b92a271bf869a8 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 19:31:42 +0000 Subject: [PATCH 042/120] Fix handling of configurable inline --- rapids_logger/CMakeLists.txt | 2 ++ rapids_logger/logger.hpp.in | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 56b15423e..b0b8a915d 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -175,9 +175,11 @@ function(rapids_make_logger logger_namespace) set(_RAPIDS_SUPPORTS_LOGGING ON) endif() target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE RMM_BACKWARDS_COMPATIBILITY) + set(_RAPIDS_DETAIL_FUNCTION_INLINE inline) endif() if(_RAPIDS_CUDF_BACKWARDS_COMPATIBILITY) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE CUDF_BACKWARDS_COMPATIBILITY) + set(_RAPIDS_DETAIL_FUNCTION_INLINE) endif() if(_RAPIDS_SUPPORTS_LOGGING) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 6763f6c8a..7e15e8f09 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -432,8 +432,6 @@ class logger { #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { -// TODO: These functions need to be inline for rmm but they cannot be for cudf. -// This is only relevant in backwards compatibility mode, though. /** * @brief Get the default logger. @@ -442,7 +440,7 @@ namespace detail { * * @return logger& The default logger */ -inline logger& default_logger(); +@_RAPIDS_DETAIL_FUNCTION_INLINE@ logger& default_logger(); /** * @brief Get the default logger. @@ -451,7 +449,7 @@ inline logger& default_logger(); * * @return spdlog::logger& The default logger's underlying spdlog logger */ -inline spdlog::logger& logger(); +@_RAPIDS_DETAIL_FUNCTION_INLINE@ spdlog::logger& logger(); } // namespace detail #endif From 0c08a3faac649f135dfd9914441a7b7ffdf2b615 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Thu, 7 Nov 2024 19:35:40 +0000 Subject: [PATCH 043/120] Fix up Python builds and tests again for non-legacy case --- python/rmm/CMakeLists.txt | 5 +++-- python/rmm/rmm/tests/test_rmm.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python/rmm/CMakeLists.txt b/python/rmm/CMakeLists.txt index b3a4b81f3..9097b48e1 100644 --- a/python/rmm/CMakeLists.txt +++ b/python/rmm/CMakeLists.txt @@ -33,8 +33,9 @@ add_compile_definitions("SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") # we always have logging enabled when we built the C++ library since the targets that are created # when we find_package(rmm) already have that setting baked in. TODO: Figure out how to use # define_property in the C++ build to make SUPPORTS_LOGGING a queryable property that can be checked -# here. add_library(cpp_logger OBJECT) target_link_libraries(cpp_logger PRIVATE -# "$") +# here. Otherwise we just assume that the Python package is never built against a C++ rmm without +# logging support. add_library(cpp_logger OBJECT) target_link_libraries(cpp_logger PRIVATE +# rmm::rmm_logger_impl) add_subdirectory(rmm/_cuda) add_subdirectory(rmm/librmm) diff --git a/python/rmm/rmm/tests/test_rmm.py b/python/rmm/rmm/tests/test_rmm.py index 002507c3c..35b9081ff 100644 --- a/python/rmm/rmm/tests/test_rmm.py +++ b/python/rmm/rmm/tests/test_rmm.py @@ -1067,7 +1067,7 @@ def test_valid_logging_level(level): # TODO: Clean up after we remove legacy logging. # Note that we cannot specify the default value to getattr since that would # always be run, but with `or` we can rely on short-circuiting. - default_level = getattr(logging_level, "INFO") or getattr( + default_level = getattr(logging_level, "INFO", None) or getattr( logging_level, "info" ) with warnings.catch_warnings(): From ee33b2591d0b365193d2b114a3ab0a19a27e5354 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 8 Nov 2024 22:12:55 +0000 Subject: [PATCH 044/120] Make arena printing work in backwards compatibility mode --- include/rmm/mr/device/arena_memory_resource.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/rmm/mr/device/arena_memory_resource.hpp b/include/rmm/mr/device/arena_memory_resource.hpp index 6f9b7ac36..1b8e0937d 100644 --- a/include/rmm/mr/device/arena_memory_resource.hpp +++ b/include/rmm/mr/device/arena_memory_resource.hpp @@ -335,7 +335,11 @@ class arena_memory_resource final : public device_memory_resource { void dump_memory_log(size_t bytes) { logger_->info("**************************************************"); +#ifdef RMM_BACKWARDS_COMPATIBILITY + logger_->info("Ran out of memory trying to allocate {}.", rmm::detail::bytes{bytes}); +#else logger_->info("Ran out of memory trying to allocate %s.", rmm::detail::bytes{bytes}); +#endif logger_->info("**************************************************"); logger_->info("Global arena:"); global_arena_.dump_memory_log(logger_); From 28e7c21881070e744b74770944c331f152a2e489 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 9 Nov 2024 02:15:19 +0000 Subject: [PATCH 045/120] Add set_pattern to logger --- rapids_logger/logger.hpp.in | 8 ++++++++ rapids_logger/logger_impl.hpp.in | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 7e15e8f09..86e13b210 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -249,6 +249,13 @@ class logger { */ BACKWARDS_COMPAT_INLINE bool should_log(level_enum msg_level) const; + /** + * @brief Set the pattern for the logger. + * + * @param pattern The pattern to use + */ + BACKWARDS_COMPAT_INLINE void set_pattern(std::string pattern); + /** * @brief Check if the logger supports logging. * @@ -269,6 +276,7 @@ class logger { void flush_on(level_enum log_level) {} level_enum flush_level() { return level_enum::off; } bool should_log(level_enum msg_level) const { return false; } + void set_pattern(std::string pattern) {} static constexpr bool supports_logging() { return false; } #endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 93101a5f7..903fb3f35 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -30,6 +30,7 @@ #include #include +#include namespace @_RAPIDS_LOGGER_NAMESPACE@ { @@ -80,6 +81,15 @@ struct impl { } } + /** + * @brief Set the pattern for the logger. + * + * @param pattern The pattern to use for the logger. + */ + void set_pattern(std::string pattern) { + underlying.set_pattern(pattern); + } + /** * @brief Log a message at the specified level. * @@ -197,6 +207,7 @@ BACKWARDS_COMPAT_INLINE bool logger::should_log(level_enum lvl) const { return p BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { pImpl->add_sink(sink); } BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { pImpl->remove_sink(sink); } BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return pImpl->level(); } +BACKWARDS_COMPAT_INLINE void set_pattern(std::string pattern) { pImpl->set_pattern(pattern); } #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { From 55b3926633fc2c81d4a20f10d520c08504bb0ead Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 9 Nov 2024 23:27:46 +0000 Subject: [PATCH 046/120] Remove unnecessary level of indirection. --- rapids_logger/logger.hpp.in | 6 +- rapids_logger/logger_impl.hpp.in | 168 ++++++------------------------- 2 files changed, 33 insertions(+), 141 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 86e13b210..6f33eef8f 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -38,6 +38,7 @@ // Forward declare spdlog types that are part of our public API. namespace spdlog { +class logger; namespace sinks { class sink; } // namespace sinks @@ -113,9 +114,6 @@ struct bytes { #endif }; -// Forward declaration of the real implementation -struct impl; - /** * @brief Trait to check if a type has a `to_string()` method that returns a `std::string`. * @@ -382,7 +380,7 @@ class logger { private: #endif #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - std::unique_ptr pImpl{}; ///< pimpl idiom + std::unique_ptr impl{}; #endif #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 903fb3f35..49e5cedb3 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -51,144 +51,35 @@ inline level_enum string_to_level(std::string_view const env_lvl_str) throw std::invalid_argument(os.str()); } +spdlog::level::level_enum to_spdlog_level(level_enum lvl) +{ + return static_cast(static_cast(lvl)); +} +level_enum from_spdlog_level(spdlog::level::level_enum lvl) +{ + return static_cast(static_cast(lvl)); +} -/** - * @brief The real implementation of the logger using spdlog with a basic file sink. - */ -struct impl { - spdlog::logger underlying; ///< spdlog logger instance - - /** - * @brief Constructor for the real implementation of the logger. - * - * Initializes the logger with a basic file sink. - */ - impl(std::string name, std::string filename) - : underlying{ +} // namespace detail + +BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) + : impl{std::make_unique( name, std::make_shared(filename, true // truncate file - )} - { - underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); + ))} +{ + impl->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { - set_level(string_to_level(env_logging_level)); + set_level(detail::string_to_level(env_logging_level)); } auto const env_flush_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_FLUSH_LEVEL"); if (env_flush_level != nullptr) { - flush_on(string_to_level(env_flush_level)); + flush_on(detail::string_to_level(env_flush_level)); } } - /** - * @brief Set the pattern for the logger. - * - * @param pattern The pattern to use for the logger. - */ - void set_pattern(std::string pattern) { - underlying.set_pattern(pattern); - } - - /** - * @brief Log a message at the specified level. - * - * @param lvl The level at which to log the message. - * @param message The message to log. - */ - void log(level_enum lvl, const std::string& message) - { - underlying.log(to_spdlog_level(lvl), message); - } - - /** - * @brief Set the logging level. - * - * @param log_level The new logging level. - */ - void set_level(level_enum log_level) - { - underlying.set_level(to_spdlog_level(log_level)); - } - - /** - * @brief Flush the logger. - */ - void flush() - { - underlying.flush(); - } - - /** - * @brief Flush all writes on the specified level or higher. - */ - void flush_on(level_enum log_level) - { - underlying.flush_on(to_spdlog_level(log_level)); - } - - /** - * @brief Get the flush level. - * - * @return The flush level. - */ - level_enum flush_level() const - { - return from_spdlog_level(underlying.flush_level()); - } - - bool should_log(level_enum lvl) const - { - return underlying.should_log(to_spdlog_level(lvl)); - } - - /** - * @brief Add a sink to the logger. - * - * @param sink The sink to add. - */ - void add_sink(spdlog::sink_ptr sink) { - underlying.sinks().push_back(sink); - } - - /** - * @brief Remove a sink from the logger. - * - * @param sink The sink to remove. - */ - void remove_sink(spdlog::sink_ptr sink) { - auto& sinks = underlying.sinks(); - sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); - } - - /** - * @brief Get the current logging level. - * - * @return The current logging level. - */ - level_enum level() const - { - return from_spdlog_level(underlying.level()); - } - - spdlog::level::level_enum to_spdlog_level(level_enum lvl) const - { - return static_cast(static_cast(lvl)); - } - - level_enum from_spdlog_level(spdlog::level::level_enum lvl) const - { - return static_cast(static_cast(lvl)); - } -}; - -} // namespace detail - -BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) - : pImpl{std::make_unique(name, filename)} -{ -} - BACKWARDS_COMPAT_INLINE logger::~logger() = default; BACKWARDS_COMPAT_INLINE logger::logger(logger&&) = default; #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY @@ -197,17 +88,20 @@ BACKWARDS_COMPAT_INLINE class logger& logger::operator=(logger&&) = default; BACKWARDS_COMPAT_INLINE logger& logger::operator=(logger&&) = default; #endif -BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& message) { pImpl->log(lvl, message); } - -BACKWARDS_COMPAT_INLINE void logger::set_level(level_enum log_level) { pImpl->set_level(log_level); } -BACKWARDS_COMPAT_INLINE void logger::flush() { pImpl->flush(); } -BACKWARDS_COMPAT_INLINE void logger::flush_on(level_enum log_level) { pImpl->flush_on(log_level); } -BACKWARDS_COMPAT_INLINE level_enum logger::flush_level() const { return pImpl->flush_level(); } -BACKWARDS_COMPAT_INLINE bool logger::should_log(level_enum lvl) const { return pImpl->should_log(lvl); } -BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { pImpl->add_sink(sink); } -BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { pImpl->remove_sink(sink); } -BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return pImpl->level(); } -BACKWARDS_COMPAT_INLINE void set_pattern(std::string pattern) { pImpl->set_pattern(pattern); } +BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& message) { impl->log(detail::to_spdlog_level(lvl), message); } + +BACKWARDS_COMPAT_INLINE void logger::set_level(level_enum log_level) { impl->set_level(detail::to_spdlog_level(log_level)); } +BACKWARDS_COMPAT_INLINE void logger::flush() { impl->flush(); } +BACKWARDS_COMPAT_INLINE void logger::flush_on(level_enum log_level) { impl->flush_on(detail::to_spdlog_level(log_level)); } +BACKWARDS_COMPAT_INLINE level_enum logger::flush_level() const { return detail::from_spdlog_level(impl->flush_level()); } +BACKWARDS_COMPAT_INLINE bool logger::should_log(level_enum lvl) const { return impl->should_log(detail::to_spdlog_level(lvl)); } +BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { impl->sinks().push_back(sink); } +BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { + auto& sinks = impl->sinks(); + sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); +} +BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return detail::from_spdlog_level(impl->level()); } +BACKWARDS_COMPAT_INLINE void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { From 56ab8362b3ed1dad9bbda1fba617593a3a4dd6d4 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 9 Nov 2024 23:56:15 +0000 Subject: [PATCH 047/120] Simplify logging_resource_adaptor constructor stack --- .../mr/device/logging_resource_adaptor.hpp | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index 595ab2e4e..41531d9f3 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -77,9 +77,8 @@ class logging_resource_adaptor final : public device_memory_resource { logging_resource_adaptor(Upstream* upstream, std::string const& filename = get_default_filename(), bool auto_flush = false) - : logger_{make_logger(filename)}, upstream_{to_device_async_resource_ref_checked(upstream)} + : logging_resource_adaptor(to_device_async_resource_ref_checked(upstream), filename, auto_flush) { - init_logger(auto_flush); } /** @@ -97,9 +96,8 @@ class logging_resource_adaptor final : public device_memory_resource { * performance. */ logging_resource_adaptor(Upstream* upstream, std::ostream& stream, bool auto_flush = false) - : logger_{make_logger(stream)}, upstream_{to_device_async_resource_ref_checked(upstream)} + : logging_resource_adaptor(to_device_async_resource_ref_checked(upstream), stream, auto_flush) { - init_logger(auto_flush); } /** @@ -119,9 +117,8 @@ class logging_resource_adaptor final : public device_memory_resource { logging_resource_adaptor(Upstream* upstream, spdlog::sinks_init_list sinks, bool auto_flush = false) - : logger_{make_logger(sinks)}, upstream_{to_device_async_resource_ref_checked(upstream)} + : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} { - init_logger(auto_flush); } /** @@ -147,9 +144,8 @@ class logging_resource_adaptor final : public device_memory_resource { logging_resource_adaptor(device_async_resource_ref upstream, std::string const& filename = get_default_filename(), bool auto_flush = false) - : logger_{make_logger(filename)}, upstream_{upstream} + : logging_resource_adaptor{make_logger(filename), upstream, auto_flush} { - init_logger(auto_flush); } /** @@ -167,9 +163,8 @@ class logging_resource_adaptor final : public device_memory_resource { logging_resource_adaptor(device_async_resource_ref upstream, std::ostream& stream, bool auto_flush = false) - : logger_{make_logger(stream)}, upstream_{upstream} + : logging_resource_adaptor{make_logger(stream), upstream, auto_flush} { - init_logger(auto_flush); } /** @@ -187,9 +182,8 @@ class logging_resource_adaptor final : public device_memory_resource { logging_resource_adaptor(device_async_resource_ref upstream, spdlog::sinks_init_list sinks, bool auto_flush = false) - : logger_{make_logger(sinks)}, upstream_{upstream} + : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} { - init_logger(auto_flush); } logging_resource_adaptor() = delete; @@ -257,10 +251,10 @@ class logging_resource_adaptor final : public device_memory_resource { return std::make_shared("RMM", sinks); } - /** - * @brief Initialize the logger. - */ - void init_logger(bool auto_flush) + logging_resource_adaptor(std::shared_ptr logger, + device_async_resource_ref upstream, + bool auto_flush) + : logger_{logger}, upstream_{upstream} { if (auto_flush) { logger_->flush_on(spdlog::level::info); } logger_->set_pattern("%v"); From a690620b99a6a739248dea21e31eeabf70742e57 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 10 Nov 2024 02:00:35 +0000 Subject: [PATCH 048/120] Implement basic support for sinks to get logging_resource_adaptor working --- .../mr/device/logging_resource_adaptor.hpp | 65 +++++++++++++++++-- rapids_logger/logger.hpp.in | 45 +++++++++++++ rapids_logger/logger_impl.hpp.in | 29 +++++++++ tests/logger_tests.cpp | 1 + 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index 41531d9f3..f07346111 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -18,14 +18,17 @@ #include #include #include +#include #include #include #include +#ifdef RMM_BACKWARDS_COMPATIBILITY #include #include #include #include +#endif #include #include @@ -34,6 +37,7 @@ namespace RMM_NAMESPACE { namespace mr { + /** * @addtogroup device_resource_adaptors * @{ @@ -114,8 +118,9 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ + template logging_resource_adaptor(Upstream* upstream, - spdlog::sinks_init_list sinks, + std::initializer_list sinks, bool auto_flush = false) : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} { @@ -179,8 +184,9 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ + template logging_resource_adaptor(device_async_resource_ref upstream, - spdlog::sinks_init_list sinks, + std::initializer_list sinks, bool auto_flush = false) : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} { @@ -236,27 +242,62 @@ class logging_resource_adaptor final : public device_memory_resource { private: static auto make_logger(std::ostream& stream) { +#ifdef RMM_BACKWARDS_COMPATIBILITY return std::make_shared( "RMM", std::make_shared(stream)); +#else + return std::make_shared("RMM", stream); +#endif } static auto make_logger(std::string const& filename) { +#ifdef RMM_BACKWARDS_COMPATIBILITY return std::make_shared( "RMM", std::make_shared(filename, true /*truncate file*/)); +#else + return std::make_shared("RMM", filename); +#endif } - static auto make_logger(spdlog::sinks_init_list sinks) + // TODO: See if there is a way to make this function only valid for our sink + // or spdlog's without leaking spdlog symbols. When logging isn't enabled our + // sink type is constructible from anything, so that sort of analysis won't + // help (and fixing that would require the same ideas as fixing this). + template + static auto make_logger(std::initializer_list sinks) { +#ifdef RMM_BACKWARDS_COMPATIBILITY return std::make_shared("RMM", sinks); +#else + // Support passing either + if constexpr (std::is_same_v) { + return std::make_shared("RMM", sinks); + } else { + std::vector> rmm_sinks; + rmm_sinks.reserve(sinks.size()); + for (const auto& s : sinks) { + rmm_sinks.push_back(std::make_shared(s)); + } + return std::make_shared("RMM", std::move(rmm_sinks)); + } +#endif } +#ifdef RMM_BACKWARDS_COMPATIBILITY logging_resource_adaptor(std::shared_ptr logger, +#else + logging_resource_adaptor(std::shared_ptr logger, +#endif device_async_resource_ref upstream, bool auto_flush) : logger_{logger}, upstream_{upstream} { +#ifdef RMM_BACKWARDS_COMPATIBILITY if (auto_flush) { logger_->flush_on(spdlog::level::info); } +#else + if (auto_flush) { logger_->flush_on(level_enum::info); } +#endif logger_->set_pattern("%v"); logger_->info(header()); logger_->set_pattern("%t,%H:%M:%S.%f,%v"); @@ -291,10 +332,18 @@ class logging_resource_adaptor final : public device_memory_resource { { try { auto const ptr = get_upstream_resource().allocate_async(bytes, stream); - logger_->info("allocate,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); +#ifdef RMM_BACKWARDS_COMPATIBILITY + logger_->info("allocate failure,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); +#else + logger_->info("allocate failure,%p,%s,%p", ptr, bytes, fmt::ptr(stream.value())); +#endif return ptr; } catch (...) { +#ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("allocate failure,{},{},{}", nullptr, bytes, fmt::ptr(stream.value())); +#else + logger_->info("allocate failure,%p,%s,%p", nullptr, bytes, fmt::ptr(stream.value())); +#endif throw; } } @@ -315,7 +364,11 @@ class logging_resource_adaptor final : public device_memory_resource { */ void do_deallocate(void* ptr, std::size_t bytes, cuda_stream_view stream) override { +#ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("free,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); +#else + logger_->info("free,%p,%s,%p", ptr, bytes, fmt::ptr(stream.value())); +#endif get_upstream_resource().deallocate_async(ptr, bytes, stream); } @@ -334,7 +387,11 @@ class logging_resource_adaptor final : public device_memory_resource { return get_upstream_resource() == cast->get_upstream_resource(); } +#ifdef RMM_BACKWARDS_COMPATIBILITY std::shared_ptr logger_; ///< spdlog logger object +#else + std::shared_ptr logger_{}; +#endif device_async_resource_ref upstream_; ///< The upstream resource used for satisfying ///< allocation requests diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 6f33eef8f..f068ab39c 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING @@ -153,6 +154,22 @@ enum class level_enum : int32_t { n_levels }; + +class sink { +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING + public: + BACKWARDS_COMPAT_INLINE sink(spdlog::sink_ptr); + private: + spdlog::sink_ptr impl; +#else + public: + // Use a template to avoid needing a definition of spdlog's sink_ptr type. + template + BACKWARDS_COMPAT_INLINE sink(Sink) {} +#endif + friend class logger; +}; + /** * @class logger * @brief A logger class that either uses the real implementation (via spdlog) or performs no-ops if @@ -169,12 +186,35 @@ class logger { */ BACKWARDS_COMPAT_INLINE logger(std::string name, std::string filename); + /** + * @brief Construct a new logger object + * + * @param name The name of the logger + * @param stream The stream to log to + */ + BACKWARDS_COMPAT_INLINE logger(std::string name, std::ostream& stream); + + /** + * @brief Construct a new logger object + * + * @param name The name of the logger + * @param sinks The sinks to log to + * + * Note that we must use a vector because initializer_lists are not flexible + * enough to support programmatic construction in callers, and an + * iterator-based API would require templating and thus exposing spdlog + * types. + */ + BACKWARDS_COMPAT_INLINE logger(std::string name, std::vector> sinks); + /** * @brief Destroy the logger object */ BACKWARDS_COMPAT_INLINE ~logger(); #else logger(std::string name, std::string filename) {} + logger(std::string name, std::ostream& stream) {} + logger(std::string name, std::vector> sinks) {} ~logger() = default; #endif @@ -434,6 +474,11 @@ class logger { this->formatted_log(lvl, format, convert_to_c_string(std::forward(args))...); }; +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING + BACKWARDS_COMPAT_INLINE void init_logger(); +#else + void init_logger() {} +#endif }; #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 49e5cedb3..4ba2e55ae 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -26,6 +26,7 @@ #include #endif #include +#include #include #include @@ -63,12 +64,40 @@ level_enum from_spdlog_level(spdlog::level::level_enum lvl) } // namespace detail + +// Sink methods +BACKWARDS_COMPAT_INLINE sink::sink(spdlog::sink_ptr sink) : impl{sink} {} + +// Logger methods BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) : impl{std::make_unique( name, std::make_shared(filename, true // truncate file ))} { + init_logger(); +} + +BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::ostream& stream) + : impl{std::make_unique( + name, + std::make_shared(stream))} +{ + init_logger(); +} + +BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::vector> sinks) +{ + std::vector spdlog_sinks; + spdlog_sinks.reserve(sinks.size()); + for (auto const& s : sinks) { + spdlog_sinks.emplace_back(s->impl); + } + impl = std::make_unique(name, spdlog_sinks.begin(), spdlog_sinks.end()); + init_logger(); +} + +BACKWARDS_COMPAT_INLINE void logger::init_logger() { impl->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { diff --git a/tests/logger_tests.cpp b/tests/logger_tests.cpp index 643281d91..e6385d862 100644 --- a/tests/logger_tests.cpp +++ b/tests/logger_tests.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include From 19c82efe67a6315b7c3682a28ff33c45f78732aa Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 10 Nov 2024 04:12:14 +0000 Subject: [PATCH 049/120] Fix logger format strings --- include/rmm/mr/device/logging_resource_adaptor.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index f07346111..6598fb6c8 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -335,14 +335,14 @@ class logging_resource_adaptor final : public device_memory_resource { #ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("allocate failure,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); #else - logger_->info("allocate failure,%p,%s,%p", ptr, bytes, fmt::ptr(stream.value())); + logger_->info("allocate failure,%p,%zu,%p", ptr, bytes, fmt::ptr(stream.value())); #endif return ptr; } catch (...) { #ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("allocate failure,{},{},{}", nullptr, bytes, fmt::ptr(stream.value())); #else - logger_->info("allocate failure,%p,%s,%p", nullptr, bytes, fmt::ptr(stream.value())); + logger_->info("allocate failure,%p,%zu,%p", nullptr, bytes, fmt::ptr(stream.value())); #endif throw; } @@ -367,7 +367,7 @@ class logging_resource_adaptor final : public device_memory_resource { #ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("free,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); #else - logger_->info("free,%p,%s,%p", ptr, bytes, fmt::ptr(stream.value())); + logger_->info("free,%p,%zu,%p", ptr, bytes, fmt::ptr(stream.value())); #endif get_upstream_resource().deallocate_async(ptr, bytes, stream); } From 9faf1b3b2ae3b0cc75b999b7479a70a1d57a14ee Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 10 Nov 2024 05:17:40 +0000 Subject: [PATCH 050/120] Fix logger output to match old fmt prints --- include/rmm/mr/device/logging_resource_adaptor.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index 6598fb6c8..e3696a972 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -333,16 +333,16 @@ class logging_resource_adaptor final : public device_memory_resource { try { auto const ptr = get_upstream_resource().allocate_async(bytes, stream); #ifdef RMM_BACKWARDS_COMPATIBILITY - logger_->info("allocate failure,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); + logger_->info("allocate,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); #else - logger_->info("allocate failure,%p,%zu,%p", ptr, bytes, fmt::ptr(stream.value())); + logger_->info("allocate,%llx,%zu,%llx", ptr, bytes, stream.value()); #endif return ptr; } catch (...) { #ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("allocate failure,{},{},{}", nullptr, bytes, fmt::ptr(stream.value())); #else - logger_->info("allocate failure,%p,%zu,%p", nullptr, bytes, fmt::ptr(stream.value())); + logger_->info("allocate failure,%llx,%zu,%llx", nullptr, bytes, stream.value()); #endif throw; } @@ -367,7 +367,7 @@ class logging_resource_adaptor final : public device_memory_resource { #ifdef RMM_BACKWARDS_COMPATIBILITY logger_->info("free,{},{},{}", ptr, bytes, fmt::ptr(stream.value())); #else - logger_->info("free,%p,%zu,%p", ptr, bytes, fmt::ptr(stream.value())); + logger_->info("free,%llx,%zu,%llx", ptr, bytes, stream.value()); #endif get_upstream_resource().deallocate_async(ptr, bytes, stream); } From b9b14f529fdc49e6acda0ff151668285ff3b86cf Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 10 Nov 2024 05:21:21 +0000 Subject: [PATCH 051/120] Inline the extra log call, the extra lambda invocation shouldn't be that different from an extra log stack frame --- rapids_logger/logger.hpp.in | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index f068ab39c..68769357a 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -341,7 +341,7 @@ class logger { } }; - this->_log(lvl, format, convert_to_string(std::forward(args))...); + this->formatted_log(lvl, format, convert_to_string(std::forward(args))...); }; /** @@ -441,27 +441,6 @@ class logger { */ template void formatted_log(level_enum lvl, std::string const& format, Args&&... args) { - auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), args...) + 1); - if (size <= 0) { throw std::runtime_error("Error during formatting."); } - std::unique_ptr buf(new char[size]); - std::snprintf(buf.get(), size, format.c_str(), args...); - log(lvl, {buf.get(), buf.get() + size - 1}); - } - - /** - * @brief Log a message at the specified level. - * - * This function only exists to provide a level of indirection underneath the - * public templated log API to preserve the lifetime of string temporaries - * created in the log() call so that the c_str pointers are valid in the - * subsequent formatted_log call. - * - * @param lvl The log level - * @param format The format string - * @param args The format arguments - */ - template - void _log(level_enum lvl, std::string const& format, Args&&... args) { auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { using ArgType = std::decay_t; if constexpr (std::is_same_v) { @@ -471,8 +450,12 @@ class logger { } }; - this->formatted_log(lvl, format, convert_to_c_string(std::forward(args))...); - }; + auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...) + 1); + if (size <= 0) { throw std::runtime_error("Error during formatting."); } + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), convert_to_c_string(std::forward(args))...); + log(lvl, {buf.get(), buf.get() + size - 1}); + } #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING BACKWARDS_COMPAT_INLINE void init_logger(); From 39b3da88b95e116ea2c6dbe96de06de15676e5ea Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 10 Nov 2024 07:28:15 +0000 Subject: [PATCH 052/120] Update logger tests for when logging is not supported --- tests/logger_tests.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/logger_tests.cpp b/tests/logger_tests.cpp index e6385d862..74c32a669 100644 --- a/tests/logger_tests.cpp +++ b/tests/logger_tests.cpp @@ -101,6 +101,7 @@ class raii_temp_directory { void expect_log_events(std::string const& filename, std::vector const& expected_events) { +#ifdef SUPPORTS_LOGGING auto actual_events = rmm::detail::parse_csv(filename); std::equal(expected_events.begin(), @@ -118,6 +119,7 @@ void expect_log_events(std::string const& filename, EXPECT_EQ(expected.pointer, actual.pointer); return true; }); +#endif } TEST(Adaptor, FilenameConstructor) @@ -291,7 +293,9 @@ TEST(Adaptor, STDOUT) std::string output = testing::internal::GetCapturedStdout(); std::string header = output.substr(0, output.find('\n')); +#ifdef SUPPORTS_LOGGING ASSERT_EQ(header, log_mr.header()); +#endif } TEST(Adaptor, STDERR) @@ -309,7 +313,9 @@ TEST(Adaptor, STDERR) std::string output = testing::internal::GetCapturedStderr(); std::string header = output.substr(0, output.find('\n')); +#ifdef SUPPORTS_LOGGING ASSERT_EQ(header, log_mr.header()); +#endif } } // namespace From f299fd26c37372ef8879d1b16d54696fca3d5c6a Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 11 Nov 2024 00:07:06 +0000 Subject: [PATCH 053/120] Make compatible with backwards compatibility mode again --- .../rmm/mr/device/logging_resource_adaptor.hpp | 18 ++++++++++++++++++ rapids_logger/CMakeLists.txt | 7 +++++-- rapids_logger/logger_impl.hpp.in | 8 ++++---- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index e3696a972..fb0dd961b 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -118,6 +118,14 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ +#ifdef RMM_BACKWARDS_COMPATIBILITY + logging_resource_adaptor(Upstream* upstream, + spdlog::sinks_init_list sinks, + bool auto_flush = false) + : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} + { + } +#else template logging_resource_adaptor(Upstream* upstream, std::initializer_list sinks, @@ -125,6 +133,7 @@ class logging_resource_adaptor final : public device_memory_resource { : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} { } +#endif /** * @brief Construct a new logging resource adaptor using `upstream` to satisfy @@ -184,6 +193,14 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ +#ifdef RMM_BACKWARDS_COMPATIBILITY + logging_resource_adaptor(device_async_resource_ref upstream, + spdlog::sinks_init_list sinks, + bool auto_flush = false) + : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} + { + } +#else template logging_resource_adaptor(device_async_resource_ref upstream, std::initializer_list sinks, @@ -191,6 +208,7 @@ class logging_resource_adaptor final : public device_memory_resource { : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} { } +#endif logging_resource_adaptor() = delete; ~logging_resource_adaptor() override = default; diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index b0b8a915d..88ae32427 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -142,6 +142,11 @@ function(rapids_make_logger logger_namespace) string(TOUPPER ${logger_namespace} _RAPIDS_LOGGER_MACRO_PREFIX) endif() + set(_RAPIDS_DETAIL_FUNCTION_INLINE) + if(_RAPIDS_RMM_BACKWARDS_COMPATIBILITY) + set(_RAPIDS_DETAIL_FUNCTION_INLINE inline) + endif() + # All paths are computed relative to the current source/binary dir of the file from which the # function is invoked. As a result we cannot use relative paths here because CMake will root these # paths incorrectly for configure_file/install. @@ -175,11 +180,9 @@ function(rapids_make_logger logger_namespace) set(_RAPIDS_SUPPORTS_LOGGING ON) endif() target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE RMM_BACKWARDS_COMPATIBILITY) - set(_RAPIDS_DETAIL_FUNCTION_INLINE inline) endif() if(_RAPIDS_CUDF_BACKWARDS_COMPATIBILITY) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE CUDF_BACKWARDS_COMPATIBILITY) - set(_RAPIDS_DETAIL_FUNCTION_INLINE) endif() if(_RAPIDS_SUPPORTS_LOGGING) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 4ba2e55ae..d8c77655f 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -52,12 +52,12 @@ inline level_enum string_to_level(std::string_view const env_lvl_str) throw std::invalid_argument(os.str()); } -spdlog::level::level_enum to_spdlog_level(level_enum lvl) +BACKWARDS_COMPAT_INLINE spdlog::level::level_enum to_spdlog_level(level_enum lvl) { return static_cast(static_cast(lvl)); } -level_enum from_spdlog_level(spdlog::level::level_enum lvl) +BACKWARDS_COMPAT_INLINE level_enum from_spdlog_level(spdlog::level::level_enum lvl) { return static_cast(static_cast(lvl)); } @@ -135,7 +135,7 @@ BACKWARDS_COMPAT_INLINE void logger::set_pattern(std::string pattern) { impl->se #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY namespace detail { -class logger& default_logger() +@_RAPIDS_DETAIL_FUNCTION_INLINE@ class logger& default_logger() { static class logger logger_ = [] { class logger logger_ { @@ -153,7 +153,7 @@ class logger& default_logger() return logger_; } -class spdlog::logger& logger() { return default_logger().pImpl->underlying; } +@_RAPIDS_DETAIL_FUNCTION_INLINE@ class spdlog::logger& logger() { return *(default_logger().impl); } } // namespace detail #endif From 15cdb0cfa09c2a4231baad28eb389d07a176375d Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 11 Nov 2024 00:14:04 +0000 Subject: [PATCH 054/120] Make notes on what changes will be needed to use hide all spdlog symbols when we remove backwards compatibility mode. --- cmake/thirdparty/get_spdlog.cmake | 13 ++++++++++++- rapids_logger/CMakeLists.txt | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 7f80b3726..d381a9d2d 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -16,10 +16,21 @@ function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) + # TODO: When we disable backwards compatibility mode we will switch these flags on to build a + # static lib of spdlog and link to that. Forcing a download is one way to rebuild and ensure that + # we can build with the necessary symbol visibility flag. The other option is to pass + # Wl,--exclude-libs,libspdlog to the linker, which seems to capture a couple of symbols that this + # setting misses. However, in either case we may need to force building since spdlog's CMake + # reuses the same target for static and dynamic library builds. set(CPM_DOWNLOAD_spdlog ON) + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") rapids_cpm_spdlog( FMT_OPTION "EXTERNAL_FMT_HO" INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports) + BUILD_EXPORT_SET rmm-exports + # TODO: We can't support both modes right now unfortunately because we require a static spdlog + # for the new builds to hide the symbols properly. CPM_ARGS OPTIONS "SPDLOG_BUILD_SHARED OFF" + # "BUILD_SHARED_LIBS OFF" + ) endfunction() diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 88ae32427..ae1769d00 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -207,6 +207,9 @@ function(rapids_make_logger logger_namespace) $) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog_header_only) + # TODO: When we drop backwards compatibility mode, stop linking to the header-only spdlog and + # use the static library instead. spdlog::spdlog) See get_spdlog.cmake for details. + # target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") else() target_link_libraries(${_RAPIDS_LOGGER_TARGET} INTERFACE spdlog::spdlog_header_only) endif() From 3e8e286e7da9ddb689787231ae494e71b791c898 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 11 Nov 2024 00:35:33 +0000 Subject: [PATCH 055/120] Make notes on tests expected to fail when logging is disabled --- python/rmm/rmm/tests/test_rmm.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python/rmm/rmm/tests/test_rmm.py b/python/rmm/rmm/tests/test_rmm.py index 35b9081ff..dfcbbf7c8 100644 --- a/python/rmm/rmm/tests/test_rmm.py +++ b/python/rmm/rmm/tests/test_rmm.py @@ -136,6 +136,9 @@ def test_rmm_modes_system_memory(dtype, nelem, alloc, system, pool, headroom): array_tester(dtype, nelem, alloc) +# TODO: This won't work when logging is disabled in C++, but I think we should +# assume that the Python package is always built against a librmm with logging +# support. @pytest.mark.parametrize("dtype", _dtypes) @pytest.mark.parametrize("nelem", _nelems) @pytest.mark.parametrize("alloc", _allocs) @@ -577,6 +580,9 @@ def test_reinitialize_with_invalid_str_arg_pool_size(): assert "Could not parse" in str(e.value) +# TODO: This won't work when logging is disabled in C++, but I think we should +# assume that the Python package is always built against a librmm with logging +# support. @pytest.mark.parametrize("dtype", _dtypes) @pytest.mark.parametrize("nelem", _nelems) @pytest.mark.parametrize("alloc", _allocs) @@ -1062,6 +1068,9 @@ def test_rmm_device_buffer_copy(cuda_ary, make_copy): np.testing.assert_equal(expected, result) +# TODO: This won't work when logging is disabled in C++, but I think we should +# assume that the Python package is always built against a librmm with logging +# support. @pytest.mark.parametrize("level", logging_level) def test_valid_logging_level(level): # TODO: Clean up after we remove legacy logging. From 440d7c1cfdc5e6725f6b3c1f1a84a4b4a4246a31 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 12 Nov 2024 21:20:22 +0000 Subject: [PATCH 056/120] Always hide the visibility of the logger implementation bits. --- rapids_logger/logger_impl.hpp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index d8c77655f..cf6080901 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -34,7 +34,7 @@ #include -namespace @_RAPIDS_LOGGER_NAMESPACE@ { +namespace __attribute__((visibility("hidden"))) @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { From 704c8e2c150ebe3adcd7128f6eaedfb63723c9bc Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 12 Nov 2024 21:52:35 +0000 Subject: [PATCH 057/120] Add all notes on how we want to use spdlog to fully hide symbols in the future. --- CMakeLists.txt | 3 +++ cmake/thirdparty/get_spdlog.cmake | 37 ++++++++++++++++++++++--------- rapids_logger/CMakeLists.txt | 5 ++++- rapids_logger/logger_impl.hpp.in | 10 +++++++++ 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 19b3dc965..86ee394cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,9 @@ option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) option(RMM_LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) option(RMM_SUPPORTS_LOGGING "Enable logging support" ON) +# cmake-format: off +#option(RMM_SPDLOG_DYNAMIC "Use dynamic linking for spdlog" OFF) +# cmake-format: on if(RMM_LOGGING_COMPATIBILITY) if(NOT RMM_SUPPORTS_LOGGING) message(STATUS "RMM_LOGGING_COMPATIBILITY requires RMM_SUPPORTS_LOGGING to be enabled") diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index d381a9d2d..9f8f283f0 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -17,19 +17,36 @@ function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) # TODO: When we disable backwards compatibility mode we will switch these flags on to build a - # static lib of spdlog and link to that. Forcing a download is one way to rebuild and ensure that - # we can build with the necessary symbol visibility flag. The other option is to pass - # Wl,--exclude-libs,libspdlog to the linker, which seems to capture a couple of symbols that this - # setting misses. However, in either case we may need to force building since spdlog's CMake - # reuses the same target for static and dynamic library builds. set(CPM_DOWNLOAD_spdlog ON) - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") + # static lib of spdlog and link to that. The current approach of using a header-only spdlog works + # with both compatibility and new logger modes, but it does not support completely hiding spdlog + # symbols due to the inlining of functions that spdlog does when in header-only mode. When we + # switch, forcing a download is one way to rebuild and ensure that we can build with the necessary + # symbol visibility flag. The other option is to pass Wl,--exclude-libs,libspdlog to the linker, + # which seems to capture a couple of symbols that this setting misses. In either case we may need + # to force building since spdlog's CMake reuses the same target for static and dynamic library + # builds. + + set(_options) + # cmake-format: off + ## TODO: Figure out how to use this variable properly inside + ## rapids_cpm_spdlog. The way quotes are being interpolated is almost + ## certainly not what I expect. + #set(_options OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF") + #if(RMM_SPDLOG_DYNAMIC) + # set(_options OPTIONS "SPDLOG_BUILD_SHARED ON" "BUILD_SHARED_LIBS ON") + #else() + # set(CPM_DOWNLOAD_spdlog ON) + # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") + #endif() +# cmake-format: on rapids_cpm_spdlog( + # TODO: We can drop this when we stop using header-only spdlog. FMT_OPTION "EXTERNAL_FMT_HO" INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports - # TODO: We can't support both modes right now unfortunately because we require a static spdlog - # for the new builds to hide the symbols properly. CPM_ARGS OPTIONS "SPDLOG_BUILD_SHARED OFF" - # "BUILD_SHARED_LIBS OFF" + BUILD_EXPORT_SET rmm-exports # cmake-format: off + #OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" + #EXCLUDE_FROM_ALL +# cmake-format: on ) endfunction() diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index ae1769d00..8370f7061 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -207,9 +207,12 @@ function(rapids_make_logger logger_namespace) $) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog_header_only) + # cmake-format: off # TODO: When we drop backwards compatibility mode, stop linking to the header-only spdlog and - # use the static library instead. spdlog::spdlog) See get_spdlog.cmake for details. + # use the static library instead. See get_spdlog.cmake for details. + # spdlog::spdlog) # target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") +# cmake-format: on else() target_link_libraries(${_RAPIDS_LOGGER_TARGET} INTERFACE spdlog::spdlog_header_only) endif() diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index cf6080901..8043dc903 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -69,6 +69,16 @@ BACKWARDS_COMPAT_INLINE level_enum from_spdlog_level(spdlog::level::level_enum l BACKWARDS_COMPAT_INLINE sink::sink(spdlog::sink_ptr sink) : impl{sink} {} // Logger methods +// TODO: This constructor and the one below introduce some undesirable +// vtable/typeinfo public symbols for basic_file_sink and ostream_sink. I'm not +// sure how to avoid this since they come from std::shared_ptr having inline +// methods that require injection into the global symbol table for +// disambiguation across TUs. I'm also not sure that we entirely need to +// support this kind of constructor, so we might just want to remove it. At +// minimum we will always have to expose the +// std::shared_ptr add_sink/remove_sink functions, but +// those don't introduce any vtable or tbypeinfo entries (presumably because +// the class doesn't actually implement any virtual functions). BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) : impl{std::make_unique( name, From 5d11768a65489dd519f99e1207298c7c87914a58 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 13 Nov 2024 02:34:16 +0000 Subject: [PATCH 058/120] Make sure the unique_ptr is not default instantiated --- rapids_logger/logger.hpp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 68769357a..342b971d8 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -420,7 +420,7 @@ class logger { private: #endif #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - std::unique_ptr impl{}; + std::unique_ptr impl; #endif #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY From 1fdee9753289a3bc3d63a39833f2b8e32242d387 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:02:10 +0000 Subject: [PATCH 059/120] Remove all compatibility logic --- CMakeLists.txt | 23 +--- benchmarks/CMakeLists.txt | 3 +- benchmarks/replay/replay.cpp | 6 +- cmake/thirdparty/get_spdlog.cmake | 39 ++---- .../rmm/mr/device/arena_memory_resource.hpp | 17 --- include/rmm/mr/device/detail/arena.hpp | 10 +- .../mr/device/logging_resource_adaptor.hpp | 56 +-------- python/rmm/CMakeLists.txt | 5 +- python/rmm/rmm/__init__.py | 14 +-- python/rmm/rmm/_cuda/CMakeLists.txt | 6 +- python/rmm/rmm/librmm/CMakeLists.txt | 6 +- python/rmm/rmm/librmm/_logger.pxd | 98 ++++----------- python/rmm/rmm/pylibrmm/CMakeLists.txt | 6 +- python/rmm/rmm/pylibrmm/logger.pyx | 37 ++---- python/rmm/rmm/tests/test_rmm.py | 21 +--- rapids_logger/CMakeLists.txt | 89 ++++--------- rapids_logger/logger.hpp.in | 118 +++--------------- rapids_logger/logger_impl.hpp.in | 88 ++++--------- tests/CMakeLists.txt | 3 +- tests/mr/device/tracking_mr_tests.cpp | 16 +-- 20 files changed, 135 insertions(+), 526 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06bb4466d..fe7a467ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,17 +58,10 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -option(RMM_LOGGING_COMPATIBILITY "Enable backwards compatibility with older logging macros" ON) option(RMM_SUPPORTS_LOGGING "Enable logging support" ON) # cmake-format: off #option(RMM_SPDLOG_DYNAMIC "Use dynamic linking for spdlog" OFF) # cmake-format: on -if(RMM_LOGGING_COMPATIBILITY) - if(NOT RMM_SUPPORTS_LOGGING) - message(STATUS "RMM_LOGGING_COMPATIBILITY requires RMM_SUPPORTS_LOGGING to be enabled") - set(RMM_SUPPORTS_LOGGING ON) - endif() -endif() # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- @@ -86,18 +79,12 @@ rapids_find_package( rapids_cpm_init() add_subdirectory(rapids_logger) -if(RMM_LOGGING_COMPATIBILITY) - rapids_make_logger( - rmm EXPORT_SET rmm-exports VISIBILITY_MACRO "__attribute__((visibility(\"default\")))" - SUPPORTS_LOGGING RMM_BACKWARDS_COMPATIBILITY) -else() - set(_logging_support_flag) - if(RMM_SUPPORTS_LOGGING) - set(_logging_support_flag "SUPPORTS_LOGGING") - endif() - rapids_make_logger(rmm EXPORT_SET rmm-exports VISIBILITY_MACRO - "__attribute__((visibility(\"default\")))" ${_logging_support_flag}) +set(_logging_support_flag) +if(RMM_SUPPORTS_LOGGING) + set(_logging_support_flag "SUPPORTS_LOGGING") endif() +rapids_make_logger(rmm EXPORT_SET rmm-exports VISIBILITY_MACRO + "__attribute__((visibility(\"default\")))" ${_logging_support_flag}) include(cmake/thirdparty/get_cccl.cmake) include(cmake/thirdparty/get_nvtx.cmake) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 86857d503..715a06890 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -45,7 +45,6 @@ function(ConfigureBench BENCH_NAME) target_compile_options(${BENCH_NAME} PUBLIC $<$:-Wall -Werror -Wno-unknown-pragmas>) - # When not building in compatibility mode, each benchmark has to recompile the logger. if(TARGET rmm_bench_logger) target_link_libraries(${BENCH_NAME} PRIVATE rmm_bench_logger) endif() @@ -66,7 +65,7 @@ endfunction(ConfigureBench) # Create an object library for the logger so that we don't have to recompile it. This is not # necessary if logging is unsupported since then the header-only implementation is sufficient. -if(RMM_SUPPORTS_LOGGING AND NOT RMM_LOGGING_COMPATIBILITY) +if(RMM_SUPPORTS_LOGGING) add_library(rmm_bench_logger OBJECT) target_link_libraries(rmm_bench_logger PRIVATE rmm_logger_impl) endif() diff --git a/benchmarks/replay/replay.cpp b/benchmarks/replay/replay.cpp index e2b105927..8edbf11f9 100644 --- a/benchmarks/replay/replay.cpp +++ b/benchmarks/replay/replay.cpp @@ -34,10 +34,6 @@ #include #include -#ifdef RMM_BACKWARDS_COMPATIBILITY -#include -#endif - #include #include #include @@ -407,7 +403,7 @@ int main(int argc, char** argv) auto const num_threads = per_thread_events.size(); // Uncomment to enable / change default log level - // rmm::detail::logger().set_level(spdlog::level::trace); + // rmm::logger().set_level(rmm::level_enum::trace); if (args.count("resource") > 0) { std::string mr_name = args["resource"].as(); diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 1b54794ed..0dbf0306d 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -16,36 +16,21 @@ function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) - # TODO: When we disable backwards compatibility mode we will switch these flags on to build a - # static lib of spdlog and link to that. The current approach of using a header-only spdlog works - # with both compatibility and new logger modes, but it does not support completely hiding spdlog - # symbols due to the inlining of functions that spdlog does when in header-only mode. When we - # switch, forcing a download is one way to rebuild and ensure that we can build with the necessary - # symbol visibility flag. The other option is to pass Wl,--exclude-libs,libspdlog to the linker, - # which seems to capture a couple of symbols that this setting misses. In either case we may need - # to force building since spdlog's CMake reuses the same target for static and dynamic library - # builds. - set(_options) - # cmake-format: off - ## TODO: Figure out how to use this variable properly inside - ## rapids_cpm_spdlog. The way quotes are being interpolated is almost - ## certainly not what I expect. - #set(_options OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF") - #if(RMM_SPDLOG_DYNAMIC) - # set(_options OPTIONS "SPDLOG_BUILD_SHARED ON" "BUILD_SHARED_LIBS ON") - #else() - # set(CPM_DOWNLOAD_spdlog ON) - # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") - #endif() -# cmake-format: on + # TODO: Figure out how to use this variable properly inside rapids_cpm_spdlog. The way quotes are + # being interpolated is almost certainly not what I expect. set(_options OPTIONS + # "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF") + if(RMM_SPDLOG_DYNAMIC) + # Has no effect as of yet. + set(_options OPTIONS "SPDLOG_BUILD_SHARED ON" "BUILD_SHARED_LIBS ON") + else() + set(CPM_DOWNLOAD_spdlog ON) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") + endif() rapids_cpm_spdlog( INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports # cmake-format: off - #OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" - #EXCLUDE_FROM_ALL -# cmake-format: on - ) + BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" + EXCLUDE_FROM_ALL) endfunction() diff --git a/include/rmm/mr/device/arena_memory_resource.hpp b/include/rmm/mr/device/arena_memory_resource.hpp index b61e90da1..4aa4f1ff1 100644 --- a/include/rmm/mr/device/arena_memory_resource.hpp +++ b/include/rmm/mr/device/arena_memory_resource.hpp @@ -27,10 +27,6 @@ #include -#ifdef RMM_BACKWARDS_COMPATIBILITY -#include -#endif - #include #include #include @@ -100,18 +96,9 @@ class arena_memory_resource final : public device_memory_resource { : global_arena_{upstream_mr, arena_size}, dump_log_on_failure_{dump_log_on_failure} { if (dump_log_on_failure_) { -#ifdef RMM_BACKWARDS_COMPATIBILITY - logger_ = - std::make_shared("arena_memory_dump", - std::make_shared( - "rmm_arena_memory_dump.log", true /*truncate file*/)); - // Set the level to `debug` for more detailed output. - logger_->set_level(spdlog::level::info); -#else logger_ = std::make_shared("arena_memory_dump", "rmm_arena_memory_dump.log"); // Set the level to `debug` for more detailed output. logger_->set_level(level_enum::info); -#endif } } @@ -366,11 +353,7 @@ class arena_memory_resource final : public device_memory_resource { /// If true, dump memory information to log on allocation failure. bool dump_log_on_failure_{}; /// The logger for memory dump. -#ifdef RMM_BACKWARDS_COMPATIBILITY - std::shared_ptr logger_{}; -#else std::shared_ptr logger_{}; -#endif /// Mutex for read and write locks on arena maps. mutable std::shared_mutex map_mtx_; /// Mutex for shared and unique locks on the mr. diff --git a/include/rmm/mr/device/detail/arena.hpp b/include/rmm/mr/device/detail/arena.hpp index 767dd29af..57f48c4e4 100644 --- a/include/rmm/mr/device/detail/arena.hpp +++ b/include/rmm/mr/device/detail/arena.hpp @@ -28,10 +28,6 @@ #include -#ifdef RMM_BACKWARDS_COMPATIBILITY -#include -#endif - #include #include #include @@ -647,13 +643,9 @@ class global_arena final { /** * @brief Dump memory to log. * - * @param logger the spdlog logger to use + * @param logger the logger to use */ -#ifdef RMM_BACKWARDS_COMPATIBILITY - RMM_HIDDEN void dump_memory_log(std::shared_ptr const& logger) const -#else void dump_memory_log(std::shared_ptr const& logger) const -#endif { std::lock_guard lock(mtx_); diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index 4ca666052..fd30ec66a 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -23,13 +23,6 @@ #include #include -#ifdef RMM_BACKWARDS_COMPATIBILITY -#include -#include -#include -#include -#endif - #include #include #include @@ -119,14 +112,6 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ -#ifdef RMM_BACKWARDS_COMPATIBILITY - logging_resource_adaptor(Upstream* upstream, - spdlog::sinks_init_list sinks, - bool auto_flush = false) - : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} - { - } -#else template logging_resource_adaptor(Upstream* upstream, std::initializer_list sinks, @@ -134,7 +119,6 @@ class logging_resource_adaptor final : public device_memory_resource { : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} { } -#endif /** * @brief Construct a new logging resource adaptor using `upstream` to satisfy @@ -194,14 +178,6 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ -#ifdef RMM_BACKWARDS_COMPATIBILITY - logging_resource_adaptor(device_async_resource_ref upstream, - spdlog::sinks_init_list sinks, - bool auto_flush = false) - : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} - { - } -#else template logging_resource_adaptor(device_async_resource_ref upstream, std::initializer_list sinks, @@ -209,7 +185,6 @@ class logging_resource_adaptor final : public device_memory_resource { : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} { } -#endif logging_resource_adaptor() = delete; ~logging_resource_adaptor() override = default; @@ -259,24 +234,11 @@ class logging_resource_adaptor final : public device_memory_resource { } private: - static auto make_logger(std::ostream& stream) - { -#ifdef RMM_BACKWARDS_COMPATIBILITY - return std::make_shared( - "RMM", std::make_shared(stream)); -#else - return std::make_shared("RMM", stream); -#endif - } + static auto make_logger(std::ostream& stream) { return std::make_shared("RMM", stream); } static auto make_logger(std::string const& filename) { -#ifdef RMM_BACKWARDS_COMPATIBILITY - return std::make_shared( - "RMM", std::make_shared(filename, true /*truncate file*/)); -#else return std::make_shared("RMM", filename); -#endif } // TODO: See if there is a way to make this function only valid for our sink @@ -286,9 +248,6 @@ class logging_resource_adaptor final : public device_memory_resource { template static auto make_logger(std::initializer_list sinks) { -#ifdef RMM_BACKWARDS_COMPATIBILITY - return std::make_shared("RMM", sinks); -#else // Support passing either if constexpr (std::is_same_v) { return std::make_shared("RMM", sinks); @@ -300,23 +259,14 @@ class logging_resource_adaptor final : public device_memory_resource { } return std::make_shared("RMM", std::move(rmm_sinks)); } -#endif } -#ifdef RMM_BACKWARDS_COMPATIBILITY - logging_resource_adaptor(std::shared_ptr logger, -#else logging_resource_adaptor(std::shared_ptr logger, -#endif device_async_resource_ref upstream, bool auto_flush) : logger_{logger}, upstream_{upstream} { -#ifdef RMM_BACKWARDS_COMPATIBILITY - if (auto_flush) { logger_->flush_on(spdlog::level::info); } -#else if (auto_flush) { logger_->flush_on(level_enum::info); } -#endif logger_->set_pattern("%v"); logger_->info(header()); logger_->set_pattern("%t,%H:%M:%S.%f,%v"); @@ -397,11 +347,7 @@ class logging_resource_adaptor final : public device_memory_resource { return get_upstream_resource() == cast->get_upstream_resource(); } -#ifdef RMM_BACKWARDS_COMPATIBILITY - std::shared_ptr logger_; ///< spdlog logger object -#else std::shared_ptr logger_{}; -#endif device_async_resource_ref upstream_; ///< The upstream resource used for satisfying ///< allocation requests diff --git a/python/rmm/CMakeLists.txt b/python/rmm/CMakeLists.txt index 9097b48e1..cf1383573 100644 --- a/python/rmm/CMakeLists.txt +++ b/python/rmm/CMakeLists.txt @@ -34,8 +34,9 @@ add_compile_definitions("SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") # when we find_package(rmm) already have that setting baked in. TODO: Figure out how to use # define_property in the C++ build to make SUPPORTS_LOGGING a queryable property that can be checked # here. Otherwise we just assume that the Python package is never built against a C++ rmm without -# logging support. add_library(cpp_logger OBJECT) target_link_libraries(cpp_logger PRIVATE -# rmm::rmm_logger_impl) +# logging support. +add_library(cpp_logger OBJECT) +target_link_libraries(cpp_logger PRIVATE rmm::rmm_logger_impl) add_subdirectory(rmm/_cuda) add_subdirectory(rmm/librmm) diff --git a/python/rmm/rmm/__init__.py b/python/rmm/rmm/__init__.py index 5d431eba3..5c865eba8 100644 --- a/python/rmm/rmm/__init__.py +++ b/python/rmm/rmm/__init__.py @@ -22,21 +22,11 @@ flush_logger, get_flush_level, get_logging_level, + level_enum, set_flush_level, set_logging_level, should_log, ) - -# TODO: Clean up after we remove legacy logging. -try: - from rmm.pylibrmm.logger import logging_level - - logging_level_var = "logging_level" -except ImportError: - from rmm.pylibrmm.logger import level_enum - - logging_level_var = "level_enum" - from rmm.rmm import ( RMMError, is_initialized, @@ -55,7 +45,7 @@ "get_log_filenames", "get_logging_level", "is_initialized", - logging_level_var, + "level_enum", "mr", "register_reinitialize_hook", "reinitialize", diff --git a/python/rmm/rmm/_cuda/CMakeLists.txt b/python/rmm/rmm/_cuda/CMakeLists.txt index 1b9687768..7759432d3 100644 --- a/python/rmm/rmm/_cuda/CMakeLists.txt +++ b/python/rmm/rmm/_cuda/CMakeLists.txt @@ -13,11 +13,7 @@ # ============================================================================= set(cython_sources stream.pyx) -if(TARGET cpp_logger) - set(linked_libraries rmm::rmm cpp_logger) -else() - set(linked_libraries rmm::rmm) -endif() +set(linked_libraries rmm::rmm cpp_logger) rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" CXX) diff --git a/python/rmm/rmm/librmm/CMakeLists.txt b/python/rmm/rmm/librmm/CMakeLists.txt index 895a3f1ed..dc807fdba 100644 --- a/python/rmm/rmm/librmm/CMakeLists.txt +++ b/python/rmm/rmm/librmm/CMakeLists.txt @@ -13,11 +13,7 @@ # ============================================================================= set(cython_sources _logger.pyx) -if(TARGET cpp_logger) - set(linked_libraries rmm::rmm cpp_logger) -else() - set(linked_libraries rmm::rmm) -endif() +set(linked_libraries rmm::rmm cpp_logger) # Build all of the Cython targets rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" diff --git a/python/rmm/rmm/librmm/_logger.pxd b/python/rmm/rmm/librmm/_logger.pxd index 24a4adc55..bd0728bc1 100644 --- a/python/rmm/rmm/librmm/_logger.pxd +++ b/python/rmm/rmm/librmm/_logger.pxd @@ -15,81 +15,25 @@ from libcpp cimport bool from libcpp.string cimport string -# Note: This must match the LOGGING_COMPATIBILITY setting in CMakeLists.txt for -# the C++ build or the build will fail since the expected symbols will not exist. -DEF LOGGING_COMPATIBILITY = True -# Conditional compilation in Cython is deprecated, but we will remove the need -# for it here before that becomes an issue; this conditional just exists to -# smooth the transition. -# https://docs.cython.org/en/latest/src/userguide/language_basics.html#conditional-compilation -IF LOGGING_COMPATIBILITY: - cdef extern from "spdlog/common.h" namespace "spdlog::level" nogil: - cpdef enum logging_level "spdlog::level::level_enum": - """ - The debug logging level for RMM. - - Debug logging prints messages to a log file. See - `Debug Logging `_ - for more information. - - Valid levels, in decreasing order of verbosity, are TRACE, DEBUG, - INFO, WARN, ERR, CRITICAL, and OFF. Default is INFO. - - Examples - -------- - >>> import rmm - >>> rmm.logging_level.DEBUG - - >>> rmm.logging_level.DEBUG.value - 1 - >>> rmm.logging_level.DEBUG.name - 'DEBUG' - - See Also - -------- - set_logging_level : Set the debug logging level - get_logging_level : Get the current debug logging level - """ - TRACE "spdlog::level::trace" - DEBUG "spdlog::level::debug" - INFO "spdlog::level::info" - WARN "spdlog::level::warn" - ERR "spdlog::level::err" - CRITICAL "spdlog::level::critical" - OFF "spdlog::level::off" - - cdef extern from "spdlog/spdlog.h" namespace "spdlog" nogil: - cdef cppclass spdlog_logger "spdlog::logger": - spdlog_logger() except + - void set_level(logging_level level) - logging_level level() - void flush() except + - void flush_on(logging_level level) - logging_level flush_level() - bool should_log(logging_level msg_level) - - cdef extern from "rmm/logger.hpp" namespace "rmm::detail" nogil: - cdef spdlog_logger& logger() except + -ELSE: - cdef extern from "rmm/logger.hpp" namespace "rmm" nogil: - cpdef enum class level_enum: - trace - debug - info - warn - error - critical - off - n_levels - - cdef cppclass logger: - logger(string name, string filename) except + - void set_level(level_enum log_level) except + - level_enum level() except + - void flush() except + - void flush_on(level_enum level) except + - level_enum flush_level() except + - bool should_log(level_enum msg_level) except + - - cdef logger& default_logger() except + +cdef extern from "rmm/logger.hpp" namespace "rmm" nogil: + cpdef enum class level_enum: + trace + debug + info + warn + error + critical + off + n_levels + + cdef cppclass logger: + logger(string name, string filename) except + + void set_level(level_enum log_level) except + + level_enum level() except + + void flush() except + + void flush_on(level_enum level) except + + level_enum flush_level() except + + bool should_log(level_enum msg_level) except + + + cdef logger& default_logger() except + diff --git a/python/rmm/rmm/pylibrmm/CMakeLists.txt b/python/rmm/rmm/pylibrmm/CMakeLists.txt index 962efcbe2..0012cb93d 100644 --- a/python/rmm/rmm/pylibrmm/CMakeLists.txt +++ b/python/rmm/rmm/pylibrmm/CMakeLists.txt @@ -13,11 +13,7 @@ # ============================================================================= set(cython_sources device_buffer.pyx logger.pyx memory_resource.pyx cuda_stream.pyx helper.pyx) -if(TARGET cpp_logger) - set(linked_libraries rmm::rmm cpp_logger) -else() - set(linked_libraries rmm::rmm) -endif() +set(linked_libraries rmm::rmm cpp_logger) # Build all of the Cython targets rapids_cython_create_modules(SOURCE_FILES "${cython_sources}" LINKED_LIBRARIES "${linked_libraries}" diff --git a/python/rmm/rmm/pylibrmm/logger.pyx b/python/rmm/rmm/pylibrmm/logger.pyx index 7c4bd1257..9d5877fae 100644 --- a/python/rmm/rmm/pylibrmm/logger.pyx +++ b/python/rmm/rmm/pylibrmm/logger.pyx @@ -14,27 +14,14 @@ import warnings -# Note: This must match the LOGGING_COMPATIBILITY setting in CMakeLists.txt for -# the C++ build or the build will fail since the expected symbols will not exist. -DEF LOGGING_COMPATIBILITY = True +from rmm.librmm._logger cimport default_logger -IF LOGGING_COMPATIBILITY: - from rmm.librmm._logger cimport logger - - from rmm.librmm._logger import logging_level -ELSE: - from rmm.librmm._logger cimport default_logger as logger - - from rmm.librmm._logger import level_enum +from rmm.librmm._logger import level_enum def _validate_level_type(level): - IF LOGGING_COMPATIBILITY: - if not isinstance(level, logging_level): - raise TypeError("level must be an instance of the logging_level enum") - ELSE: - if not isinstance(level, level_enum): - raise TypeError("level must be an instance of the level_enum enum") + if not isinstance(level, level_enum): + raise TypeError("level must be an instance of the level_enum enum") def should_log(level): @@ -67,7 +54,7 @@ def should_log(level): If the logging level is not an instance of the ``logging_level`` enum. """ _validate_level_type(level) - return logger().should_log(level) + return default_logger().should_log(level) def set_logging_level(level): @@ -99,10 +86,10 @@ def set_logging_level(level): >>> rmm.set_logging_level(rmm.logging_level.WARN) # set logging level to warn """ _validate_level_type(level) - logger().set_level(level) + default_logger().set_level(level) if not should_log(level): - warnings.warn(f"RMM will not log logging_level.{level.name}. This " + warnings.warn(f"RMM will not log level_enum.{level.name}. This " "may be because the C++ library is compiled for a " "less-verbose logging level.") @@ -131,7 +118,7 @@ def get_logging_level(): >>> rmm.get_logging_level() # get current logging level """ - return logger().level() + return default_logger().level() def flush_logger(): @@ -153,7 +140,7 @@ def flush_logger(): >>> import rmm >>> rmm.flush_logger() # flush the logger """ - logger().flush() + default_logger().flush() def set_flush_level(level): @@ -187,10 +174,10 @@ def set_flush_level(level): >>> rmm.flush_on(rmm.logging_level.WARN) # set flush level to warn """ _validate_level_type(level) - logger().flush_on(level) + default_logger().flush_on(level) if not should_log(level): - warnings.warn(f"RMM will not log logging_level.{level.name}. This " + warnings.warn(f"RMM will not log level_enum.{level.name}. This " "may be because the C++ library is compiled for a " "less-verbose logging level.") @@ -221,4 +208,4 @@ def get_flush_level(): >>> rmm.flush_level() # get current flush level """ - return logger().flush_level() + return default_logger().flush_level() diff --git a/python/rmm/rmm/tests/test_rmm.py b/python/rmm/rmm/tests/test_rmm.py index dfcbbf7c8..bbe44aef0 100644 --- a/python/rmm/rmm/tests/test_rmm.py +++ b/python/rmm/rmm/tests/test_rmm.py @@ -29,13 +29,7 @@ import rmm._cuda.stream from rmm.allocators.cupy import rmm_cupy_allocator from rmm.allocators.numba import RMMNumbaManager - -# TODO: Clean up after we remove legacy logging. -try: - from rmm.pylibrmm.logger import logging_level -except ImportError: - from rmm.pylibrmm.logger import level_enum as logging_level - +from rmm.pylibrmm.logger import level_enum cuda.set_memory_manager(RMMNumbaManager) @@ -1071,20 +1065,15 @@ def test_rmm_device_buffer_copy(cuda_ary, make_copy): # TODO: This won't work when logging is disabled in C++, but I think we should # assume that the Python package is always built against a librmm with logging # support. -@pytest.mark.parametrize("level", logging_level) +@pytest.mark.parametrize("level", level_enum) def test_valid_logging_level(level): - # TODO: Clean up after we remove legacy logging. - # Note that we cannot specify the default value to getattr since that would - # always be run, but with `or` we can rely on short-circuiting. - default_level = getattr(logging_level, "INFO", None) or getattr( - logging_level, "info" - ) + default_level = level_enum.info with warnings.catch_warnings(): warnings.filterwarnings( - "ignore", message="RMM will not log logging_level.TRACE." + "ignore", message="RMM will not log level_enum.trace." ) warnings.filterwarnings( - "ignore", message="RMM will not log logging_level.DEBUG." + "ignore", message="RMM will not log level_enum.debug." ) rmm.set_logging_level(level) assert rmm.get_logging_level() == level diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index f8d84774b..715c66e15 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -51,15 +51,11 @@ Generate a logger implementation customized for the specified namespace. [LOGGER_MACRO_PREFIX ] [VISIBILITY_MACRO ] [SUPPORTS_LOGGING] - [RMM_BACKWARDS_COMPATIBILITY] - [CUDF_BACKWARDS_COMPATIBILITY] ) This function produces an interface target named that, when linked to by other targets, provides them a header file that defines a logger interface for the specified namespace. The logger is generated from the provided template files and is configured to use the specified namespace and macro prefix. The generated logger is placed in the specified header directory. -When `RMM_BACKWARDS_COMPATIBILITY` is specified, the logger target is configured to support backwards compatibility with RMM. In this mode, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. In this mode, `SUPPORTS_LOGGING` is always true. - -When not using backwards compatibility mode, the logger implementation (which lives in a separate header file) is not included in the declaration header. If `SUPPORTS_LOGGING` is off, the logger target is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. If `SUPPORTS_LOGGING` is on, the logger implementation is compiled into a separate target that must be linked to by any target that uses the logger. +The logger implementation lives in a separate header file that is not included in the declaration header. If `SUPPORTS_LOGGING` is off, the logger target is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. If `SUPPORTS_LOGGING` is on, the logger implementation is compiled into a separate target that must be linked to by any target that uses the logger. ``logger_namespace`` @@ -81,20 +77,13 @@ When not using backwards compatibility mode, the logger implementation (which li The macro to use for visibility annotations. If not specified, no visibility annotations are added to the logger interface. ``SUPPORTS_LOGGING`` - If specified, the logger target is configured to support logging. If not specified, the resulting logger is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. This setting is required for the logger implementation to be generated. It will be automatically turned on if `RMM_BACKWARDS_COMPATIBILITY` is specified. - -``RMM_BACKWARDS_COMPATIBILITY`` - If specified, the logger target is configured to support backwards compatibility with RMM. In backwards-compatibility mode, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. In this mode, `SUPPORTS_LOGGING` is always true. In addition, the underlying spdlog logger is exposed in public APIs when this flag is enabled (with suitable deprecation warnings). - -``CUDF_BACKWARDS_COMPATIBILITY`` - If specified, the underlying spdlog logger is exposed in public APIs when this flag is enabled (with suitable deprecation warnings). - + If specified, the logger target is configured to support logging. If not specified, the resulting logger is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. This setting is required for the logger implementation to be generated. Result Targets ^^^^^^^^^^^^^^^^ - is an interface target that provides the logger interface for the specified namespace. If `RMM_BACKWARDS_COMPATIBILITY` is on, the logger implementation is entirely header-only and including it is sufficient for downstream consumers to support logging. This target only provides headers. + is an interface target that provides the logger interface for the specified namespace. - _impl is an interface target that provides the logger implementation for the specified namespace. This target must be linked to by any target that uses the logger. It is only defined if `RMM_BACKWARDS_COMPATIBILITY` is off and `SUPPORTS_LOGGING` is on. Targets linking to this target will have the logger implementation compiled into them. + _impl is an interface target that provides the logger implementation for the specified namespace. This target must be linked to by any target that uses the logger. It is only defined `SUPPORTS_LOGGING` is on. Targets linking to this target will have the logger implementation compiled into them. Examples ^^^^^^^^ @@ -111,18 +100,15 @@ Example on how to use :cmake:command:`rapids_make_logger`. EXPORT_SET rapids-exports ) - # Generate a logger for the namespace "rmm" in backwards compatibility mode. - rapids_make_logger(rapids - SUPPORTS_LOGGING - RMM_BACKWARDS_COMPATIBILITY - ) + # Generate a logger for the namespace "rmm" that does not support logging. + rapids_make_logger(rapids) #]=======================================================================] function(rapids_make_logger logger_namespace) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") - set(_rapids_options RMM_BACKWARDS_COMPATIBILITY CUDF_BACKWARDS_COMPATIBILITY SUPPORTS_LOGGING) + set(_rapids_options SUPPORTS_LOGGING) set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX VISIBILITY_MACRO) set(_rapids_multi_value) @@ -141,11 +127,6 @@ function(rapids_make_logger logger_namespace) string(TOUPPER ${logger_namespace} _RAPIDS_LOGGER_MACRO_PREFIX) endif() - set(_RAPIDS_DETAIL_FUNCTION_INLINE) - if(_RAPIDS_RMM_BACKWARDS_COMPATIBILITY) - set(_RAPIDS_DETAIL_FUNCTION_INLINE inline) - endif() - # All paths are computed relative to the current source/binary dir of the file from which the # function is invoked. As a result we cannot use relative paths here because CMake will root these # paths incorrectly for configure_file/install. @@ -173,48 +154,28 @@ function(rapids_make_logger logger_namespace) INTERFACE "$" "$") target_compile_features(${_RAPIDS_LOGGER_TARGET} INTERFACE cxx_std_17) - if(_RAPIDS_RMM_BACKWARDS_COMPATIBILITY) - if(NOT _RAPIDS_SUPPORTS_LOGGING) - message(STATUS "RMM_BACKWARDS_COMPATIBILITY requires SUPPORTS_LOGGING, turning it on") - set(_RAPIDS_SUPPORTS_LOGGING ON) - endif() - target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE RMM_BACKWARDS_COMPATIBILITY) - endif() - if(_RAPIDS_CUDF_BACKWARDS_COMPATIBILITY) - target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE CUDF_BACKWARDS_COMPATIBILITY) - endif() if(_RAPIDS_SUPPORTS_LOGGING) target_compile_definitions(${_RAPIDS_LOGGER_TARGET} INTERFACE "${_RAPIDS_LOGGER_MACRO_PREFIX}_SUPPORTS_LOGGING") - if(NOT _RAPIDS_RMM_BACKWARDS_COMPATIBILITY) - # Create an interface target that will trigger compilation of the logger implementation in any - # target that is linked to it. - set(LOGGER_IMPL_SRC_OUTPUT_FILE ${BUILD_DIR}/logger_impl/logger.cpp) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.cpp.in - ${LOGGER_IMPL_SRC_OUTPUT_FILE}) - install(FILES ${LOGGER_IMPL_SRC_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) - - # Note that we cannot specify the source files directly in add_library, see the CMake - # documentation explaining that these do not populate INTERFACE_SOURCES. - # https://cmake.org/cmake/help/latest/command/add_library.html#interface-with-sources - set(impl_target ${_RAPIDS_LOGGER_TARGET}_impl) - add_library(${impl_target} INTERFACE) - target_sources( - ${impl_target} - INTERFACE $ - $) - target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} - spdlog::spdlog_header_only) - # cmake-format: off - # TODO: When we drop backwards compatibility mode, stop linking to the header-only spdlog and - # use the static library instead. See get_spdlog.cmake for details. - # spdlog::spdlog) - # target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") -# cmake-format: on - else() - target_link_libraries(${_RAPIDS_LOGGER_TARGET} INTERFACE spdlog::spdlog_header_only) - endif() + # Create an interface target that will trigger compilation of the logger implementation in any + # target that is linked to it. + set(LOGGER_IMPL_SRC_OUTPUT_FILE ${BUILD_DIR}/logger_impl/logger.cpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.cpp.in ${LOGGER_IMPL_SRC_OUTPUT_FILE}) + install(FILES ${LOGGER_IMPL_SRC_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) + + # Note that we cannot specify the source files directly in add_library, see the CMake + # documentation explaining that these do not populate INTERFACE_SOURCES. + # https://cmake.org/cmake/help/latest/command/add_library.html#interface-with-sources + set(impl_target ${_RAPIDS_LOGGER_TARGET}_impl) + add_library(${impl_target} INTERFACE) + target_sources( + ${impl_target} + INTERFACE $ + $) + target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) + # TODO: Figure out whether to use this or the visibility settings at compile-time. + target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") endif() set(_install_export) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 342b971d8..8194ddcfb 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -16,20 +16,6 @@ #pragma once -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY -#include -#endif - -// We only define functions as inline when in backwards compatibility mode -// because in that mode those functions are included in the header, just -// defined out of band by the include of logger_impl.hpp into this file. In the -// new mode the functions are defined in their own TU. -#ifdef RMM_BACKWARDS_COMPATIBILITY -#define BACKWARDS_COMPAT_INLINE inline -#else -#define BACKWARDS_COMPAT_INLINE -#endif - #include #include #include @@ -74,26 +60,6 @@ inline std::string default_log_filename() struct bytes { std::size_t value; ///< The size in bytes -#ifdef RMM_BACKWARDS_COMPATIBILITY - /** - * @brief Construct a new bytes object - * - * @param os The output stream - * @param value The size in bytes - */ - friend std::ostream& operator<<(std::ostream& os, bytes const& value) - { - static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; - - int index = 0; - auto size = static_cast(value.value); - while (size > 1024) { - size /= 1024; - index++; - } - return os << size << ' ' << units.at(index); - } -#else /** * @brief Convert the size to a string representation. * @@ -112,7 +78,6 @@ struct bytes { return std::to_string(size) + ' ' + units.at(index); } -#endif }; /** @@ -158,14 +123,14 @@ enum class level_enum : int32_t { class sink { #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING public: - BACKWARDS_COMPAT_INLINE sink(spdlog::sink_ptr); + sink(spdlog::sink_ptr); private: spdlog::sink_ptr impl; #else public: // Use a template to avoid needing a definition of spdlog's sink_ptr type. template - BACKWARDS_COMPAT_INLINE sink(Sink) {} + sink(Sink) {} #endif friend class logger; }; @@ -184,7 +149,7 @@ class logger { * @param name The name of the logger * @param filename The name of the log file */ - BACKWARDS_COMPAT_INLINE logger(std::string name, std::string filename); + logger(std::string name, std::string filename); /** * @brief Construct a new logger object @@ -192,7 +157,7 @@ class logger { * @param name The name of the logger * @param stream The stream to log to */ - BACKWARDS_COMPAT_INLINE logger(std::string name, std::ostream& stream); + logger(std::string name, std::ostream& stream); /** * @brief Construct a new logger object @@ -205,12 +170,12 @@ class logger { * iterator-based API would require templating and thus exposing spdlog * types. */ - BACKWARDS_COMPAT_INLINE logger(std::string name, std::vector> sinks); + logger(std::string name, std::vector> sinks); /** * @brief Destroy the logger object */ - BACKWARDS_COMPAT_INLINE ~logger(); + ~logger(); #else logger(std::string name, std::string filename) {} logger(std::string name, std::ostream& stream) {} @@ -222,8 +187,8 @@ class logger { logger(logger const&) = delete; ///< Not copy constructible logger& operator=(logger const&) = delete; ///< Not copy assignable - BACKWARDS_COMPAT_INLINE logger(logger&&); ///< @default_move_constructor - BACKWARDS_COMPAT_INLINE logger& operator=(logger&&); ///< @default_move_assignment{logger} + logger(logger&&); ///< @default_move_constructor + logger& operator=(logger&&); ///< @default_move_assignment{logger} #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING /** @@ -234,50 +199,50 @@ class logger { * @param lvl The log level * @param message The message to log */ - BACKWARDS_COMPAT_INLINE void log(level_enum lvl, std::string const& message); + void log(level_enum lvl, std::string const& message); /** * @brief Add a sink to the logger. * * @param sink The sink to add */ - BACKWARDS_COMPAT_INLINE void add_sink(spdlog::sink_ptr sink); + void add_sink(spdlog::sink_ptr sink); /** * @brief Remove a sink from the logger. * * @param sink The sink to remove */ - BACKWARDS_COMPAT_INLINE void remove_sink(spdlog::sink_ptr sink); + void remove_sink(spdlog::sink_ptr sink); /** * @brief Get the current log level. * * @return The current log level */ - BACKWARDS_COMPAT_INLINE level_enum level() const; + level_enum level() const; /** * @brief Set the log level. * * @param log_level The new log level */ - BACKWARDS_COMPAT_INLINE void set_level(level_enum log_level); + void set_level(level_enum log_level); /** * @brief Flush the logger. */ - BACKWARDS_COMPAT_INLINE void flush(); + void flush(); /** * @brief Flush all writes on the specified level or above. */ - BACKWARDS_COMPAT_INLINE void flush_on(level_enum log_level); + void flush_on(level_enum log_level); /** * @brief Get the current flush level. */ - BACKWARDS_COMPAT_INLINE level_enum flush_level() const; + level_enum flush_level() const; /** * @brief Check if the logger should log a message at the specified level. @@ -285,14 +250,14 @@ class logger { * @param msg_level The level of the message * @return true if the message should be logged, false otherwise */ - BACKWARDS_COMPAT_INLINE bool should_log(level_enum msg_level) const; + bool should_log(level_enum msg_level) const; /** * @brief Set the pattern for the logger. * * @param pattern The pattern to use */ - BACKWARDS_COMPAT_INLINE void set_pattern(std::string pattern); + void set_pattern(std::string pattern); /** * @brief Check if the logger supports logging. @@ -416,16 +381,11 @@ class logger { log(level_enum::critical, format, std::forward(args)...); } -#ifndef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY private: -#endif #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING std::unique_ptr impl; #endif -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY - private: -#endif // TODO: When we migrate to C++20 we can use std::format and format strings // instead of the printf-style printing used here. /** @@ -458,47 +418,12 @@ class logger { } #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - BACKWARDS_COMPAT_INLINE void init_logger(); + void init_logger(); #else void init_logger() {} #endif }; -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY -namespace detail { - -/** - * @brief Get the default logger. - * - * @deprecated Will be removed in 25.02. - * - * @return logger& The default logger - */ -@_RAPIDS_DETAIL_FUNCTION_INLINE@ logger& default_logger(); - -/** - * @brief Get the default logger. - * - * @deprecated Will be removed in 25.02. - * - * @return spdlog::logger& The default logger's underlying spdlog logger - */ -@_RAPIDS_DETAIL_FUNCTION_INLINE@ spdlog::logger& logger(); - -} // namespace detail -#endif - -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY -inline logger& default_logger() { return detail::default_logger(); } - -[[deprecated( - "Support for direct access to spdlog loggers in rmm is planned for " - "removal")]] inline spdlog::logger& -logger() -{ - return detail::logger(); -} -#else /** * @brief Get the default logger. * @@ -521,7 +446,6 @@ inline logger& default_logger() }(); return logger_; } -#endif // Macros for easier logging, similar to spdlog. // TODO: The macros below assume that we want to respect spdlog's level macros @@ -569,7 +493,3 @@ inline logger& default_logger() #endif } // namespace @_RAPIDS_LOGGER_NAMESPACE@ - -#ifdef RMM_BACKWARDS_COMPATIBILITY -#include "logger_impl/logger_impl.hpp" -#endif diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 8043dc903..4aca3b1b8 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -16,15 +16,8 @@ #pragma once -// We'll flip the include once this -#ifndef RMM_BACKWARDS_COMPATIBILITY #include "../logger.hpp" -#endif -#ifdef RMM_BACKWARDS_COMPATIBILITY -#include -#include -#endif #include #include #include @@ -52,12 +45,12 @@ inline level_enum string_to_level(std::string_view const env_lvl_str) throw std::invalid_argument(os.str()); } -BACKWARDS_COMPAT_INLINE spdlog::level::level_enum to_spdlog_level(level_enum lvl) +spdlog::level::level_enum to_spdlog_level(level_enum lvl) { return static_cast(static_cast(lvl)); } -BACKWARDS_COMPAT_INLINE level_enum from_spdlog_level(spdlog::level::level_enum lvl) +level_enum from_spdlog_level(spdlog::level::level_enum lvl) { return static_cast(static_cast(lvl)); } @@ -66,7 +59,7 @@ BACKWARDS_COMPAT_INLINE level_enum from_spdlog_level(spdlog::level::level_enum l // Sink methods -BACKWARDS_COMPAT_INLINE sink::sink(spdlog::sink_ptr sink) : impl{sink} {} +sink::sink(spdlog::sink_ptr sink) : impl{sink} {} // Logger methods // TODO: This constructor and the one below introduce some undesirable @@ -79,7 +72,7 @@ BACKWARDS_COMPAT_INLINE sink::sink(spdlog::sink_ptr sink) : impl{sink} {} // std::shared_ptr add_sink/remove_sink functions, but // those don't introduce any vtable or tbypeinfo entries (presumably because // the class doesn't actually implement any virtual functions). -BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) +logger::logger(std::string name, std::string filename) : impl{std::make_unique( name, std::make_shared(filename, true // truncate file @@ -88,7 +81,7 @@ BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::string filename) init_logger(); } -BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::ostream& stream) +logger::logger(std::string name, std::ostream& stream) : impl{std::make_unique( name, std::make_shared(stream))} @@ -96,7 +89,7 @@ BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::ostream& stream) init_logger(); } -BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::vector> sinks) +logger::logger(std::string name, std::vector> sinks) { std::vector spdlog_sinks; spdlog_sinks.reserve(sinks.size()); @@ -107,7 +100,7 @@ BACKWARDS_COMPAT_INLINE logger::logger(std::string name, std::vectorset_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { @@ -119,60 +112,23 @@ BACKWARDS_COMPAT_INLINE void logger::init_logger() { } } -BACKWARDS_COMPAT_INLINE logger::~logger() = default; -BACKWARDS_COMPAT_INLINE logger::logger(logger&&) = default; -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY -BACKWARDS_COMPAT_INLINE class logger& logger::operator=(logger&&) = default; -#else -BACKWARDS_COMPAT_INLINE logger& logger::operator=(logger&&) = default; -#endif - -BACKWARDS_COMPAT_INLINE void logger::log(level_enum lvl, std::string const& message) { impl->log(detail::to_spdlog_level(lvl), message); } - -BACKWARDS_COMPAT_INLINE void logger::set_level(level_enum log_level) { impl->set_level(detail::to_spdlog_level(log_level)); } -BACKWARDS_COMPAT_INLINE void logger::flush() { impl->flush(); } -BACKWARDS_COMPAT_INLINE void logger::flush_on(level_enum log_level) { impl->flush_on(detail::to_spdlog_level(log_level)); } -BACKWARDS_COMPAT_INLINE level_enum logger::flush_level() const { return detail::from_spdlog_level(impl->flush_level()); } -BACKWARDS_COMPAT_INLINE bool logger::should_log(level_enum lvl) const { return impl->should_log(detail::to_spdlog_level(lvl)); } -BACKWARDS_COMPAT_INLINE void logger::add_sink(spdlog::sink_ptr sink) { impl->sinks().push_back(sink); } -BACKWARDS_COMPAT_INLINE void logger::remove_sink(spdlog::sink_ptr sink) { - auto& sinks = impl->sinks(); - sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); -} -BACKWARDS_COMPAT_INLINE level_enum logger::level() const { return detail::from_spdlog_level(impl->level()); } -BACKWARDS_COMPAT_INLINE void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } +logger::~logger() = default; +logger::logger(logger&&) = default; +logger& logger::operator=(logger&&) = default; -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_BACKWARDS_COMPATIBILITY -namespace detail { +void logger::log(level_enum lvl, std::string const& message) { impl->log(detail::to_spdlog_level(lvl), message); } -@_RAPIDS_DETAIL_FUNCTION_INLINE@ class logger& default_logger() -{ - static class logger logger_ = [] { - class logger logger_ { - "RAPIDS", detail::default_log_filename() - }; -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO -#ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM - logger_.info("----- RAPIDS LOG BEGIN [PTDS ENABLED] -----"); -#else - logger_.info("----- RAPIDS LOG BEGIN [PTDS DISABLED] -----"); -#endif -#endif - return logger_; - }(); - return logger_; +void logger::set_level(level_enum log_level) { impl->set_level(detail::to_spdlog_level(log_level)); } +void logger::flush() { impl->flush(); } +void logger::flush_on(level_enum log_level) { impl->flush_on(detail::to_spdlog_level(log_level)); } +level_enum logger::flush_level() const { return detail::from_spdlog_level(impl->flush_level()); } +bool logger::should_log(level_enum lvl) const { return impl->should_log(detail::to_spdlog_level(lvl)); } +void logger::add_sink(spdlog::sink_ptr sink) { impl->sinks().push_back(sink); } +void logger::remove_sink(spdlog::sink_ptr sink) { + auto& sinks = impl->sinks(); + sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); } - -@_RAPIDS_DETAIL_FUNCTION_INLINE@ class spdlog::logger& logger() { return *(default_logger().impl); } - -} // namespace detail -#endif +level_enum logger::level() const { return detail::from_spdlog_level(impl->level()); } +void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } } // namespace @_RAPIDS_LOGGER_NAMESPACE@ - -#ifdef RMM_BACKWARDS_COMPATIBILITY -// Doxygen doesn't like this because we're overloading something from fmt -//! @cond Doxygen_Suppress -template <> -struct fmt::formatter<@_RAPIDS_LOGGER_NAMESPACE@::detail::bytes> : fmt::ostream_formatter {}; -#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d32bea9c1..ceba933f9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,7 +44,6 @@ function(ConfigureTestInternal TEST_NAME) PUBLIC "SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror>) - # When not building in compatibility mode, each testhas to recompile the logger. if(TARGET rmm_test_logger) target_link_libraries(${TEST_NAME} PRIVATE rmm_test_logger) endif() @@ -125,7 +124,7 @@ endfunction() # Create an object library for the logger so that we don't have to recompile it. This is not # necessary if logging is unsupported since then the header-only implementation is sufficient. -if(RMM_SUPPORTS_LOGGING AND NOT RMM_LOGGING_COMPATIBILITY) +if(RMM_SUPPORTS_LOGGING) add_library(rmm_test_logger OBJECT) target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) endif() diff --git a/tests/mr/device/tracking_mr_tests.cpp b/tests/mr/device/tracking_mr_tests.cpp index f1da19463..14c9cc9a7 100644 --- a/tests/mr/device/tracking_mr_tests.cpp +++ b/tests/mr/device/tracking_mr_tests.cpp @@ -203,14 +203,9 @@ TEST(TrackingTest, DeallocWrongBytes) TEST(TrackingTest, LogOutstandingAllocations) { std::ostringstream oss; - auto oss_sink = std::make_shared(oss); -#ifdef RMM_BACKWARDS_COMPATIBILITY - rmm::detail::logger().sinks().push_back(oss_sink); - auto old_level = rmm::detail::logger().level(); -#else + auto oss_sink = std::make_shared(oss); auto old_level = rmm::default_logger().level(); rmm::default_logger().add_sink(oss_sink); -#endif tracking_adaptor mr{rmm::mr::get_current_device_resource_ref()}; std::vector allocations; @@ -218,11 +213,7 @@ TEST(TrackingTest, LogOutstandingAllocations) allocations.push_back(mr.allocate(ten_MiB)); } -#ifdef RMM_BACKWARDS_COMPATIBILITY - rmm::detail::logger().set_level(spdlog::level::debug); -#else rmm::default_logger().set_level(rmm::level_enum::debug); -#endif EXPECT_NO_THROW(mr.log_outstanding_allocations()); #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG @@ -233,13 +224,8 @@ TEST(TrackingTest, LogOutstandingAllocations) mr.deallocate(allocation, ten_MiB); } -#ifdef RMM_BACKWARDS_COMPATIBILITY - rmm::detail::logger().set_level(old_level); - rmm::detail::logger().sinks().pop_back(); -#else rmm::default_logger().set_level(old_level); rmm::default_logger().remove_sink(oss_sink); -#endif } } // namespace From b372c695f841599f13a445247401da1a47d1ca07 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:26:06 +0000 Subject: [PATCH 060/120] Resort the file to reduce complexity for the reader --- rapids_logger/logger.hpp.in | 275 ++++++++++++++++++------------------ 1 file changed, 136 insertions(+), 139 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 8194ddcfb..c86f8f9f8 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -119,7 +119,6 @@ enum class level_enum : int32_t { n_levels }; - class sink { #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING public: @@ -142,47 +141,6 @@ class sink { */ class logger { public: -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - /** - * @brief Construct a new logger object - * - * @param name The name of the logger - * @param filename The name of the log file - */ - logger(std::string name, std::string filename); - - /** - * @brief Construct a new logger object - * - * @param name The name of the logger - * @param stream The stream to log to - */ - logger(std::string name, std::ostream& stream); - - /** - * @brief Construct a new logger object - * - * @param name The name of the logger - * @param sinks The sinks to log to - * - * Note that we must use a vector because initializer_lists are not flexible - * enough to support programmatic construction in callers, and an - * iterator-based API would require templating and thus exposing spdlog - * types. - */ - logger(std::string name, std::vector> sinks); - - /** - * @brief Destroy the logger object - */ - ~logger(); -#else - logger(std::string name, std::string filename) {} - logger(std::string name, std::ostream& stream) {} - logger(std::string name, std::vector> sinks) {} - ~logger() = default; -#endif - logger() = delete; ///< Not default constructible logger(logger const&) = delete; ///< Not copy constructible logger& operator=(logger const&) = delete; ///< Not copy assignable @@ -190,99 +148,6 @@ class logger { logger(logger&&); ///< @default_move_constructor logger& operator=(logger&&); ///< @default_move_assignment{logger} -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - /** - * @brief Log a message at the specified level. - * - * This is the core logging routine that dispatches to spdlog. - * - * @param lvl The log level - * @param message The message to log - */ - void log(level_enum lvl, std::string const& message); - - /** - * @brief Add a sink to the logger. - * - * @param sink The sink to add - */ - void add_sink(spdlog::sink_ptr sink); - - /** - * @brief Remove a sink from the logger. - * - * @param sink The sink to remove - */ - void remove_sink(spdlog::sink_ptr sink); - - /** - * @brief Get the current log level. - * - * @return The current log level - */ - level_enum level() const; - - /** - * @brief Set the log level. - * - * @param log_level The new log level - */ - void set_level(level_enum log_level); - - /** - * @brief Flush the logger. - */ - void flush(); - - /** - * @brief Flush all writes on the specified level or above. - */ - void flush_on(level_enum log_level); - - /** - * @brief Get the current flush level. - */ - level_enum flush_level() const; - - /** - * @brief Check if the logger should log a message at the specified level. - * - * @param msg_level The level of the message - * @return true if the message should be logged, false otherwise - */ - bool should_log(level_enum msg_level) const; - - /** - * @brief Set the pattern for the logger. - * - * @param pattern The pattern to use - */ - void set_pattern(std::string pattern); - - /** - * @brief Check if the logger supports logging. - * - * @return true if the logger supports logging, false otherwise - */ - static constexpr bool supports_logging() { return true; } -#else - void log(level_enum lvl, std::string const& message) {} - // When logging is not supported we won't have a spdlog sink_ptr type defined - // when this function is, so a template is used to capture the user's type. - template - void add_sink(Sink sink) {} - template - void remove_sink(Sink sink) {} - level_enum level() const { return level_enum::off; } - void set_level(level_enum log_level) {} - void flush() {} - void flush_on(level_enum log_level) {} - level_enum flush_level() { return level_enum::off; } - bool should_log(level_enum msg_level) const { return false; } - void set_pattern(std::string pattern) {} - static constexpr bool supports_logging() { return false; } -#endif - /** * @brief Log a message at the specified level. * @@ -382,10 +247,6 @@ class logger { } private: -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - std::unique_ptr impl; -#endif - // TODO: When we migrate to C++20 we can use std::format and format strings // instead of the printf-style printing used here. /** @@ -417,13 +278,149 @@ class logger { log(lvl, {buf.get(), buf.get() + size - 1}); } + // Everything below here is conditionally compiled based on whether logging is supported. + public: +#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING + /** + * @brief Construct a new logger object + * + * @param name The name of the logger + * @param filename The name of the log file + */ + logger(std::string name, std::string filename); + + /** + * @brief Construct a new logger object + * + * @param name The name of the logger + * @param stream The stream to log to + */ + logger(std::string name, std::ostream& stream); + + /** + * @brief Construct a new logger object + * + * @param name The name of the logger + * @param sinks The sinks to log to + * + * Note that we must use a vector because initializer_lists are not flexible + * enough to support programmatic construction in callers, and an + * iterator-based API would require templating and thus exposing spdlog + * types. + */ + logger(std::string name, std::vector> sinks); + + /** + * @brief Destroy the logger object + */ + ~logger(); + + /** + * @brief Log a message at the specified level. + * + * This is the core logging routine that dispatches to spdlog. + * + * @param lvl The log level + * @param message The message to log + */ + void log(level_enum lvl, std::string const& message); + + /** + * @brief Add a sink to the logger. + * + * @param sink The sink to add + */ + void add_sink(spdlog::sink_ptr sink); + + /** + * @brief Remove a sink from the logger. + * + * @param sink The sink to remove + */ + void remove_sink(spdlog::sink_ptr sink); + + /** + * @brief Get the current log level. + * + * @return The current log level + */ + level_enum level() const; + + /** + * @brief Set the log level. + * + * @param log_level The new log level + */ + void set_level(level_enum log_level); + + /** + * @brief Flush the logger. + */ + void flush(); + + /** + * @brief Flush all writes on the specified level or above. + */ + void flush_on(level_enum log_level); + + /** + * @brief Get the current flush level. + */ + level_enum flush_level() const; + + /** + * @brief Check if the logger should log a message at the specified level. + * + * @param msg_level The level of the message + * @return true if the message should be logged, false otherwise + */ + bool should_log(level_enum msg_level) const; + + /** + * @brief Set the pattern for the logger. + * + * @param pattern The pattern to use + */ + void set_pattern(std::string pattern); + + /** + * @brief Check if the logger supports logging. + * + * @return true if the logger supports logging, false otherwise + */ + static constexpr bool supports_logging() { return true; } +#else + logger(std::string name, std::string filename) {} + logger(std::string name, std::ostream& stream) {} + logger(std::string name, std::vector> sinks) {} + ~logger() = default; + void log(level_enum lvl, std::string const& message) {} + // When logging is not supported we won't have a spdlog sink_ptr type defined + // when this function is, so a template is used to capture the user's type. + template + void add_sink(Sink sink) {} + template + void remove_sink(Sink sink) {} + level_enum level() const { return level_enum::off; } + void set_level(level_enum log_level) {} + void flush() {} + void flush_on(level_enum log_level) {} + level_enum flush_level() { return level_enum::off; } + bool should_log(level_enum msg_level) const { return false; } + void set_pattern(std::string pattern) {} + static constexpr bool supports_logging() { return false; } +#endif + + private: #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING + std::unique_ptr impl; ///< The spdlog logger void init_logger(); #else void init_logger() {} #endif }; + /** * @brief Get the default logger. * From 6f6603accec65ba01904d067f948b42add2fad35 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:32:49 +0000 Subject: [PATCH 061/120] Remove now redundant bytes formatting struct --- rapids_logger/logger.hpp.in | 53 ++----------------------------------- 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index c86f8f9f8..d7461debc 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -54,44 +54,6 @@ inline std::string default_log_filename() return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; } -/** - * @brief Represent a size in number of bytes. - */ -struct bytes { - std::size_t value; ///< The size in bytes - - /** - * @brief Convert the size to a string representation. - * - * @return std::string The size as a string. - */ - std::string to_string() const - { - static std::array units{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; - - int index = 0; - auto size = static_cast(value); - while (size > 1024) { - size /= 1024; - index++; - } - return std::to_string(size) + ' ' + units.at(index); - } - -}; - -/** - * @brief Trait to check if a type has a `to_string()` method that returns a `std::string`. - * - * @tparam T The type to check. - */ -template > -struct has_to_string : std::false_type {}; - -template -struct has_to_string().to_string())>> - : std::is_same().to_string()), std::string> {}; - } // namespace detail // These values must be kept in sync with spdlog! @@ -152,9 +114,7 @@ class logger { * @brief Log a message at the specified level. * * This public log API allows users to pass format arguments to this function - * a la printf. Any custom objects may be logged as long as the type - * implements a `to_string` method. The corresponding format specifier in the - * format string should simply be `%s` like for a normal string. + * a la printf. * * @param lvl The log level * @param format The format string @@ -162,16 +122,7 @@ class logger { */ template void log(level_enum lvl, std::string const& format, Args&&... args) { - auto convert_to_string = [](auto&& arg) -> decltype(auto) { - using ArgType = std::decay_t; - if constexpr (detail::has_to_string::value) { - return arg.to_string(); - } else { - return std::forward(arg); - } - }; - - this->formatted_log(lvl, format, convert_to_string(std::forward(args))...); + this->formatted_log(lvl, format, std::forward(args)...); }; /** From b102d62c0d14fb8e84c3edd84befac2209a52ec7 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:44:04 +0000 Subject: [PATCH 062/120] Move implementation of formatted_log from rmm to rapids_logger --- include/rmm/detail/format.hpp | 44 ------------------- .../rmm/mr/device/arena_memory_resource.hpp | 3 +- include/rmm/mr/device/detail/arena.hpp | 22 ++++------ .../mr/device/logging_resource_adaptor.hpp | 10 ++--- rapids_logger/logger.hpp.in | 22 +++++++--- 5 files changed, 29 insertions(+), 72 deletions(-) diff --git a/include/rmm/detail/format.hpp b/include/rmm/detail/format.hpp index 21acac032..11478d00a 100644 --- a/include/rmm/detail/format.hpp +++ b/include/rmm/detail/format.hpp @@ -30,50 +30,6 @@ namespace RMM_NAMESPACE { namespace detail { -/** - * @brief Format a message string with printf-style formatting - * - * This function performs printf-style formatting to avoid the need for fmt - * or spdlog's own templated APIs (which would require exposing spdlog - * symbols publicly) and returns the formatted message as a `std::string`. - * - * @param format The format string - * @param args The format arguments - * @return The formatted message - * @throw rmm::logic_error if an error occurs during formatting - */ -template -std::string formatted_log(std::string const& format, Args&&... args) -{ - auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { - using ArgType = std::decay_t; - if constexpr (std::is_same_v) { - return arg.c_str(); - } else { - return std::forward(arg); - } - }; - - // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg) - auto retsize = - std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...); - RMM_EXPECTS(retsize >= 0, "Error during formatting."); - if (retsize == 0) { return {}; } - auto size = static_cast(retsize) + 1; // for null terminator - // NOLINTNEXTLINE(modernize-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) - std::unique_ptr buf(new char[size]); - std::snprintf(buf.get(), size, format.c_str(), convert_to_c_string(std::forward(args))...); - // NOLINTEND(cppcoreguidelines-pro-type-vararg) - return {buf.get(), buf.get() + size - 1}; // drop '\0' -} - -// specialization for no arguments -template <> -inline std::string formatted_log(std::string const& format) -{ - return format; -} - // Stringify a size in bytes to a human-readable value inline std::string format_bytes(std::size_t value) { diff --git a/include/rmm/mr/device/arena_memory_resource.hpp b/include/rmm/mr/device/arena_memory_resource.hpp index 4aa4f1ff1..fe07aab04 100644 --- a/include/rmm/mr/device/arena_memory_resource.hpp +++ b/include/rmm/mr/device/arena_memory_resource.hpp @@ -323,8 +323,7 @@ class arena_memory_resource final : public device_memory_resource { void dump_memory_log(size_t bytes) { logger_->info("**************************************************"); - logger_->info(rmm::detail::formatted_log("Ran out of memory trying to allocate %s.", - rmm::detail::format_bytes(bytes))); + logger_->info("Ran out of memory trying to allocate %s.", rmm::detail::format_bytes(bytes)); logger_->info("**************************************************"); logger_->info("Global arena:"); global_arena_.dump_memory_log(logger_); diff --git a/include/rmm/mr/device/detail/arena.hpp b/include/rmm/mr/device/detail/arena.hpp index 57f48c4e4..20095d504 100644 --- a/include/rmm/mr/device/detail/arena.hpp +++ b/include/rmm/mr/device/detail/arena.hpp @@ -649,27 +649,23 @@ class global_arena final { { std::lock_guard lock(mtx_); - logger->info(rmm::detail::formatted_log(" Arena size: %s", - rmm::detail::format_bytes(upstream_block_.size()))); - logger->info(rmm::detail::formatted_log(" # superblocks: %zu", superblocks_.size())); + logger->info(" Arena size: %s", rmm::detail::format_bytes(upstream_block_.size())); + logger->info(" # superblocks: %zu", superblocks_.size()); if (!superblocks_.empty()) { - logger->debug( - rmm::detail::formatted_log(" Total size of superblocks: %s", - rmm::detail::format_bytes(total_memory_size(superblocks_)))); + logger->debug(" Total size of superblocks: %s", + rmm::detail::format_bytes(total_memory_size(superblocks_))); auto const total_free = total_free_size(superblocks_); auto const max_free = max_free_size(superblocks_); auto const fragmentation = (1 - max_free / static_cast(total_free)) * 100; - logger->info(rmm::detail::formatted_log(" Total free memory: %s", - rmm::detail::format_bytes(total_free))); - logger->info(rmm::detail::formatted_log(" Largest block of free memory: %s", - rmm::detail::format_bytes(max_free))); - logger->info(rmm::detail::formatted_log(" Fragmentation: %0.2f", fragmentation)); + logger->info(" Total free memory: %s", rmm::detail::format_bytes(total_free)); + logger->info(" Largest block of free memory: %s", rmm::detail::format_bytes(max_free)); + logger->info(" Fragmentation: %0.2f", fragmentation); auto index = decltype(superblocks_.size()){0}; char* prev_end{}; for (auto const& sblk : superblocks_) { if (prev_end == nullptr) { prev_end = sblk.pointer(); } - logger->debug(rmm::detail::formatted_log( + logger->debug( " Superblock %zu: start=%p, end=%p, size=%s, empty=%s, # free blocks=%zu, max " "free=%s, " "gap=%s", @@ -680,7 +676,7 @@ class global_arena final { sblk.empty() ? "T" : "F", sblk.free_blocks(), rmm::detail::format_bytes(sblk.max_free_size()), - rmm::detail::format_bytes(static_cast(sblk.pointer() - prev_end)))); + rmm::detail::format_bytes(static_cast(sblk.pointer() - prev_end))); prev_end = sblk.end(); index++; } diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index fd30ec66a..716c4b49e 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -301,12 +301,11 @@ class logging_resource_adaptor final : public device_memory_resource { { try { auto const ptr = get_upstream_resource().allocate_async(bytes, stream); - logger_->info(rmm::detail::formatted_log( - "allocate,%p,%zu,%s", ptr, bytes, rmm::detail::format_stream(stream))); + logger_->info("allocate,%p,%zu,%s", ptr, bytes, rmm::detail::format_stream(stream)); return ptr; } catch (...) { - logger_->info(rmm::detail::formatted_log( - "allocate failure,%p,%zu,%s", nullptr, bytes, rmm::detail::format_stream(stream))); + logger_->info( + "allocate failure,%p,%zu,%s", nullptr, bytes, rmm::detail::format_stream(stream)); throw; } } @@ -327,8 +326,7 @@ class logging_resource_adaptor final : public device_memory_resource { */ void do_deallocate(void* ptr, std::size_t bytes, cuda_stream_view stream) override { - logger_->info( - rmm::detail::formatted_log("free,%p,%zu,%s", ptr, bytes, rmm::detail::format_stream(stream))); + logger_->info("free,%p,%zu,%s", ptr, bytes, rmm::detail::format_stream(stream)); get_upstream_resource().deallocate_async(ptr, bytes, stream); } diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index d7461debc..662e92f89 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -201,18 +201,20 @@ class logger { // TODO: When we migrate to C++20 we can use std::format and format strings // instead of the printf-style printing used here. /** - * @brief Format and log a message. + * @brief Format a message string with printf-style formatting * * This function performs printf-style formatting to avoid the need for fmt * or spdlog's own templated APIs (which would require exposing spdlog - * symbols publicly) and then logs the formatted message. + * symbols publicly) and returns the formatted message as a `std::string`. * - * @param lvl The log level * @param format The format string * @param args The format arguments + * @return The formatted message + * @throw rmm::logic_error if an error occurs during formatting */ template - void formatted_log(level_enum lvl, std::string const& format, Args&&... args) { + void formatted_log(level_enum lvl, std::string const& format, Args&&... args) + { auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { using ArgType = std::decay_t; if constexpr (std::is_same_v) { @@ -222,11 +224,17 @@ class logger { } }; - auto size = static_cast(std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...) + 1); - if (size <= 0) { throw std::runtime_error("Error during formatting."); } + // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg) + auto formatted_size = + std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...); + RMM_EXPECTS(formatted_size >= 0, "Error during formatting."); + if (formatted_size == 0) { log(lvl, {}); } + auto size = static_cast(formatted_size) + 1; // for null terminator + // NOLINTNEXTLINE(modernize-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) std::unique_ptr buf(new char[size]); std::snprintf(buf.get(), size, format.c_str(), convert_to_c_string(std::forward(args))...); - log(lvl, {buf.get(), buf.get() + size - 1}); + // NOLINTEND(cppcoreguidelines-pro-type-vararg) + log(lvl, {buf.get(), buf.get() + size - 1}); // drop '\0' } // Everything below here is conditionally compiled based on whether logging is supported. From 1b3add324aa90ddd952eb8e015af9ad514cb1075 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:47:24 +0000 Subject: [PATCH 063/120] Inline formatted_log into log --- rapids_logger/logger.hpp.in | 72 ++++++++++++++----------------------- 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 662e92f89..5fd65f2da 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -110,11 +110,15 @@ class logger { logger(logger&&); ///< @default_move_constructor logger& operator=(logger&&); ///< @default_move_assignment{logger} + // TODO: When we migrate to C++20 we can use std::format and format strings + // instead of the printf-style printing used here. /** - * @brief Log a message at the specified level. + * @brief Format and log a message at the specified level. * - * This public log API allows users to pass format arguments to this function - * a la printf. + * This function performs printf-style formatting to avoid the need for fmt + * or spdlog's own templated APIs (which would require exposing spdlog + * symbols publicly) and then invokes the base implementation with the + * preformatted string. * * @param lvl The log level * @param format The format string @@ -122,7 +126,26 @@ class logger { */ template void log(level_enum lvl, std::string const& format, Args&&... args) { - this->formatted_log(lvl, format, std::forward(args)...); + auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { + using ArgType = std::decay_t; + if constexpr (std::is_same_v) { + return arg.c_str(); + } else { + return std::forward(arg); + } + }; + + // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg) + auto formatted_size = + std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...); + RMM_EXPECTS(formatted_size >= 0, "Error during formatting."); + if (formatted_size == 0) { log(lvl, {}); } + auto size = static_cast(formatted_size) + 1; // for null terminator + // NOLINTNEXTLINE(modernize-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) + std::unique_ptr buf(new char[size]); + std::snprintf(buf.get(), size, format.c_str(), convert_to_c_string(std::forward(args))...); + // NOLINTEND(cppcoreguidelines-pro-type-vararg) + log(lvl, {buf.get(), buf.get() + size - 1}); // drop '\0' }; /** @@ -197,48 +220,7 @@ class logger { log(level_enum::critical, format, std::forward(args)...); } - private: - // TODO: When we migrate to C++20 we can use std::format and format strings - // instead of the printf-style printing used here. - /** - * @brief Format a message string with printf-style formatting - * - * This function performs printf-style formatting to avoid the need for fmt - * or spdlog's own templated APIs (which would require exposing spdlog - * symbols publicly) and returns the formatted message as a `std::string`. - * - * @param format The format string - * @param args The format arguments - * @return The formatted message - * @throw rmm::logic_error if an error occurs during formatting - */ - template - void formatted_log(level_enum lvl, std::string const& format, Args&&... args) - { - auto convert_to_c_string = [](auto&& arg) -> decltype(auto) { - using ArgType = std::decay_t; - if constexpr (std::is_same_v) { - return arg.c_str(); - } else { - return std::forward(arg); - } - }; - - // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg) - auto formatted_size = - std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...); - RMM_EXPECTS(formatted_size >= 0, "Error during formatting."); - if (formatted_size == 0) { log(lvl, {}); } - auto size = static_cast(formatted_size) + 1; // for null terminator - // NOLINTNEXTLINE(modernize-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) - std::unique_ptr buf(new char[size]); - std::snprintf(buf.get(), size, format.c_str(), convert_to_c_string(std::forward(args))...); - // NOLINTEND(cppcoreguidelines-pro-type-vararg) - log(lvl, {buf.get(), buf.get() + size - 1}); // drop '\0' - } - // Everything below here is conditionally compiled based on whether logging is supported. - public: #ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING /** * @brief Construct a new logger object From 6379a729ca4f295e083e4cc7312c5c432c0b41b6 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:49:43 +0000 Subject: [PATCH 064/120] More consolidation and remove unnecessary init_logger impl --- rapids_logger/logger.hpp.in | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 5fd65f2da..1214af0bf 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -330,6 +330,10 @@ class logger { * @return true if the logger supports logging, false otherwise */ static constexpr bool supports_logging() { return true; } + + private: + std::unique_ptr impl; ///< The spdlog logger + void init_logger(); #else logger(std::string name, std::string filename) {} logger(std::string name, std::ostream& stream) {} @@ -351,14 +355,6 @@ class logger { void set_pattern(std::string pattern) {} static constexpr bool supports_logging() { return false; } #endif - - private: -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - std::unique_ptr impl; ///< The spdlog logger - void init_logger(); -#else - void init_logger() {} -#endif }; From 4ef279d0d0b057618013dbd841f2eac5c33a8f0a Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:51:37 +0000 Subject: [PATCH 065/120] Remove use of rmm error-handling macro --- rapids_logger/logger.hpp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 1214af0bf..b585975fc 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -138,7 +138,7 @@ class logger { // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg) auto formatted_size = std::snprintf(nullptr, 0, format.c_str(), convert_to_c_string(std::forward(args))...); - RMM_EXPECTS(formatted_size >= 0, "Error during formatting."); + if (formatted_size < 0) { throw std::runtime_error("Error during formatting."); } if (formatted_size == 0) { log(lvl, {}); } auto size = static_cast(formatted_size) + 1; // for null terminator // NOLINTNEXTLINE(modernize-avoid-c-arrays, cppcoreguidelines-avoid-c-arrays) From eb6ef9f43bb4aed4744bf8ed8159d57c5a591782 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 22:59:40 +0000 Subject: [PATCH 066/120] Clean up some includes --- include/rmm/detail/format.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/rmm/detail/format.hpp b/include/rmm/detail/format.hpp index 11478d00a..6cd1dd9d2 100644 --- a/include/rmm/detail/format.hpp +++ b/include/rmm/detail/format.hpp @@ -20,11 +20,7 @@ #include #include -#include -#include -#include #include -#include #include namespace RMM_NAMESPACE { From 00f55779744915a0da4ac73f265a6744366cdd01 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 16 Nov 2024 23:01:58 +0000 Subject: [PATCH 067/120] Expose the default log filename publicly --- rapids_logger/logger.hpp.in | 38 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index b585975fc..1912a58a3 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -36,26 +36,6 @@ using sink_ptr = std::shared_ptr; namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { -namespace detail { - -/** - * @brief Returns the default log filename for the RMM global logger. - * - * If the environment variable `RAPIDS_DEBUG_LOG_FILE` is defined, its value is used as the path and - * name of the log file. Otherwise, the file `@_RAPIDS_LOGGER_NAMESPACE@_log.txt` in the current working directory is used. - * - * @return std::string The default log file name. - */ -inline std::string default_log_filename() -{ - auto* filename = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEBUG_LOG_FILE"); - // TODO: Do we prefer rmm's default (a file rmm_log.txt) or cudf's default (a - // stderr sink)? I think the latter is better. - return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; -} - -} // namespace detail - // These values must be kept in sync with spdlog! #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE 0 #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG 1 @@ -358,6 +338,22 @@ class logger { }; +/** + * @brief Returns the default log filename for the global logger. + * + * If the environment variable `@_RAPIDS_LOGGER_NAMESPACE@_DEBUG_LOG_FILE` is defined, its value is used as the path and + * name of the log file. Otherwise, the file `@_RAPIDS_LOGGER_NAMESPACE@_log.txt` in the current working directory is used. + * + * @return std::string The default log file name. + */ +inline std::string default_log_filename() +{ + auto* filename = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEBUG_LOG_FILE"); + // TODO: Do we prefer rmm's default (a file rmm_log.txt) or cudf's default (a + // stderr sink)? I think the latter is better. + return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; +} + /** * @brief Get the default logger. * @@ -367,7 +363,7 @@ inline logger& default_logger() { static logger logger_ = [] { logger logger_ { - "RAPIDS", detail::default_log_filename() + "RAPIDS", default_log_filename() }; #if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO #ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM From cd71f30544fffeb4f446a795361ba1366ea92f20 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 18:13:36 +0000 Subject: [PATCH 068/120] Enable dynamic linking to spdlog --- CMakeLists.txt | 4 +--- cmake/thirdparty/get_spdlog.cmake | 28 ++++++++++++++++------------ rapids_logger/CMakeLists.txt | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe7a467ba..f74b50f89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,9 +59,7 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) option(RMM_SUPPORTS_LOGGING "Enable logging support" ON) -# cmake-format: off -#option(RMM_SPDLOG_DYNAMIC "Use dynamic linking for spdlog" OFF) -# cmake-format: on +option(RMM_SPDLOG_DYNAMIC "Use dynamic linking for spdlog" OFF) # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 0dbf0306d..0ec5d6e0b 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -12,26 +12,30 @@ # the License. # ============================================================================= -# Use CPM to find or clone speedlog +# Use CPM to find or clone speedlog TODO: The logic here should be upstreamed into rapids-logger and +# probably removed from rapids-cmake. Note that it is not possible to build with two different modes +# for different projects in the same build environment, so this functionality must be kept +# independent of the rapids_make_logger function. Alternatively, we could update the cpm calls for +# spdlog to not promote targets to global scope and instead allow each project to find and configure +# spdlog independently. function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) - set(_options) - # TODO: Figure out how to use this variable properly inside rapids_cpm_spdlog. The way quotes are - # being interpolated is almost certainly not what I expect. set(_options OPTIONS - # "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF") if(RMM_SPDLOG_DYNAMIC) - # Has no effect as of yet. - set(_options OPTIONS "SPDLOG_BUILD_SHARED ON" "BUILD_SHARED_LIBS ON") + rapids_cpm_spdlog( + INSTALL_EXPORT_SET rmm-exports BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED ON" + "BUILD_SHARED_LIBS ON") else() + # For static spdlog usage assume that we want to hide as many symbols as possible, so do not use + # pre-built libraries. It's quick enough to build that there is no real benefit to supporting + # the alternative. set(CPM_DOWNLOAD_spdlog ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") + rapids_cpm_spdlog( + INSTALL_EXPORT_SET rmm-exports + BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" + EXCLUDE_FROM_ALL) endif() - rapids_cpm_spdlog( - INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" - EXCLUDE_FROM_ALL) - endfunction() find_and_configure_spdlog() diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 715c66e15..453150744 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -174,7 +174,7 @@ function(rapids_make_logger logger_namespace) INTERFACE $ $) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) - # TODO: Figure out whether to use this or the visibility settings at compile-time. + # TODO: Figure out whether to use this or the visibility settings at compile-time or both. target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") endif() From 073e179a720f926376db412680c1a688a7585f68 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 18:45:40 +0000 Subject: [PATCH 069/120] Make logging macros project-specific --- README.md | 4 +- benchmarks/CMakeLists.txt | 2 +- include/rmm/detail/logging_assert.hpp | 2 +- .../detail/stream_ordered_memory_resource.hpp | 2 +- .../mr/device/tracking_resource_adaptor.hpp | 4 +- python/rmm/CMakeLists.txt | 2 +- rapids_logger/logger.hpp.in | 44 +++++++++---------- tests/CMakeLists.txt | 2 +- tests/mr/device/tracking_mr_tests.cpp | 2 +- 9 files changed, 31 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 0a25cd348..d72d411f5 100644 --- a/README.md +++ b/README.md @@ -658,8 +658,8 @@ of more detailed logging. The default is `INFO`. Available levels are `TRACE`, ` The log relies on the [spdlog](https://github.com/gabime/spdlog.git) library. Note that to see logging below the `INFO` level, the application must also set the logging level at -run time. C++ applications must must call `rmm::logger().set_level()`, for example to enable all -levels of logging down to `TRACE`, call `rmm::logger().set_level(spdlog::level::trace)` (and compile +run time. C++ applications must must call `rmm::default_logger().set_level()`, for example to enable all +levels of logging down to `TRACE`, call `rmm::default_logger().set_level(spdlog::level::trace)` (and compile librmm with `-DRMM_LOGGING_LEVEL=TRACE`). Python applications must call `rmm.set_logging_level()`, for example to enable all levels of logging down to `TRACE`, call `rmm.set_logging_level("trace")` (and compile the RMM Python module with `-DRMM_LOGGING_LEVEL=TRACE`). diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 715a06890..272b47f6e 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -36,7 +36,7 @@ function(ConfigureBench BENCH_NAME) INSTALL_RPATH "\$ORIGIN/../../../lib") target_link_libraries(${BENCH_NAME} PRIVATE benchmark::benchmark pthread rmm) target_compile_definitions(${BENCH_NAME} - PUBLIC "SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") + PUBLIC "RMM_LOG_ACTIVE_LEVEL=RMM_LOG_LEVEL_${RMM_LOGGING_LEVEL}") if(PER_THREAD_DEFAULT_STREAM) target_compile_definitions(${BENCH_NAME} PUBLIC CUDA_API_PER_THREAD_DEFAULT_STREAM) diff --git a/include/rmm/detail/logging_assert.hpp b/include/rmm/detail/logging_assert.hpp index 4d702ee2b..c3b12ffe3 100644 --- a/include/rmm/detail/logging_assert.hpp +++ b/include/rmm/detail/logging_assert.hpp @@ -31,7 +31,7 @@ */ #ifdef NDEBUG #define RMM_LOGGING_ASSERT(_expr) (void)0 -#elif SPDLOG_ACTIVE_LEVEL < SPDLOG_LEVEL_OFF +#elif RMM_LOG_ACTIVE_LEVEL < RMM_LOG_LEVEL_OFF #define RMM_LOGGING_ASSERT(_expr) \ do { \ bool const success = (_expr); \ diff --git a/include/rmm/mr/device/detail/stream_ordered_memory_resource.hpp b/include/rmm/mr/device/detail/stream_ordered_memory_resource.hpp index f177504f2..0900d44b2 100644 --- a/include/rmm/mr/device/detail/stream_ordered_memory_resource.hpp +++ b/include/rmm/mr/device/detail/stream_ordered_memory_resource.hpp @@ -458,7 +458,7 @@ class stream_ordered_memory_resource : public crtp, public device_ void log_summary_trace() { -#if (SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE) +#if (RMM_LOG_ACTIVE_LEVEL <= RMM_LOG_LEVEL_TRACE) std::size_t num_blocks{0}; std::size_t max_block{0}; std::size_t free_mem{0}; diff --git a/include/rmm/mr/device/tracking_resource_adaptor.hpp b/include/rmm/mr/device/tracking_resource_adaptor.hpp index 8131eef4d..09631960e 100644 --- a/include/rmm/mr/device/tracking_resource_adaptor.hpp +++ b/include/rmm/mr/device/tracking_resource_adaptor.hpp @@ -185,9 +185,9 @@ class tracking_resource_adaptor final : public device_memory_resource { */ void log_outstanding_allocations() const { -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +#if RMM_LOG_ACTIVE_LEVEL <= RMM_LOG_LEVEL_DEBUG RMM_LOG_DEBUG("Outstanding Allocations: %s", get_outstanding_allocations_str()); -#endif // SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +#endif // RMM_LOG_ACTIVE_LEVEL <= RMM_LOG_LEVEL_DEBUG } private: diff --git a/python/rmm/CMakeLists.txt b/python/rmm/CMakeLists.txt index cf1383573..d407cec6d 100644 --- a/python/rmm/CMakeLists.txt +++ b/python/rmm/CMakeLists.txt @@ -27,7 +27,7 @@ include(rapids-cython-core) rapids_cython_init() # pass through logging level to spdlog -add_compile_definitions("SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") +add_compile_definitions("RMM_LOG_ACTIVE_LEVEL=RMM_LOG_LEVEL_${RMM_LOGGING_LEVEL}") # Create an object library for the logger so that we don't have to recompile it. This assumes that # we always have logging enabled when we built the C++ library since the targets that are created diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 1912a58a3..7c5b1b83b 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -37,13 +37,13 @@ using sink_ptr = std::shared_ptr; namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { // These values must be kept in sync with spdlog! -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE 0 -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG 1 -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_INFO 2 -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_WARN 3 -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_ERROR 4 -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_CRITICAL 5 -#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_OFF 6 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_TRACE 0 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_DEBUG 1 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_INFO 2 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_WARN 3 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_ERROR 4 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_CRITICAL 5 +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_OFF 6 /** * @brief The log levels supported by the logger. @@ -51,13 +51,13 @@ namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { * These levels correspond to the levels defined by spdlog. */ enum class level_enum : int32_t { - trace = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_TRACE, - debug = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_DEBUG, - info = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_INFO, - warn = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_WARN, - error = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_ERROR, - critical = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_CRITICAL, - off = @_RAPIDS_LOGGER_MACRO_PREFIX@_LEVEL_OFF, + trace = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_TRACE, + debug = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_DEBUG, + info = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_INFO, + warn = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_WARN, + error = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_ERROR, + critical = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_CRITICAL, + off = @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_OFF, n_levels }; @@ -365,7 +365,7 @@ inline logger& default_logger() logger logger_ { "RAPIDS", default_log_filename() }; -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_INFO #ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM logger_.info("----- RAPIDS LOG BEGIN [PTDS ENABLED] -----"); #else @@ -378,44 +378,42 @@ inline logger& default_logger() } // Macros for easier logging, similar to spdlog. -// TODO: The macros below assume that we want to respect spdlog's level macros -// rather than the ones defined by this file. #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_TRACE #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_TRACE(...) \ @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::trace, __VA_ARGS__) #else #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_TRACE(...) (void)0 #endif -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_DEBUG #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_DEBUG(...) \ @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::debug, __VA_ARGS__) #else #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_DEBUG(...) (void)0 #endif -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_INFO #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_INFO(...) @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::info, __VA_ARGS__) #else #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_INFO(...) (void)0 #endif -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_WARN #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_WARN(...) @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::warn, __VA_ARGS__) #else #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_WARN(...) (void)0 #endif -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_ERROR #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ERROR(...) \ @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::error, __VA_ARGS__) #else #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ERROR(...) (void)0 #endif -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL +#if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_CRITICAL #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_CRITICAL(...) \ @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(@_RAPIDS_LOGGER_NAMESPACE@::default_logger(), @_RAPIDS_LOGGER_NAMESPACE@::level_enum::critical, __VA_ARGS__) #else diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ceba933f9..611944cc1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -41,7 +41,7 @@ function(ConfigureTestInternal TEST_NAME) CUDA_STANDARD 17 CUDA_STANDARD_REQUIRED ON) target_compile_definitions(${TEST_NAME} - PUBLIC "SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${RMM_LOGGING_LEVEL}") + PUBLIC "RMM_LOG_ACTIVE_LEVEL=RMM_LOG_LEVEL_${RMM_LOGGING_LEVEL}") target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror>) if(TARGET rmm_test_logger) diff --git a/tests/mr/device/tracking_mr_tests.cpp b/tests/mr/device/tracking_mr_tests.cpp index 14c9cc9a7..aca0fe8c8 100644 --- a/tests/mr/device/tracking_mr_tests.cpp +++ b/tests/mr/device/tracking_mr_tests.cpp @@ -216,7 +216,7 @@ TEST(TrackingTest, LogOutstandingAllocations) rmm::default_logger().set_level(rmm::level_enum::debug); EXPECT_NO_THROW(mr.log_outstanding_allocations()); -#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG +#if RMM_LOG_ACTIVE_LEVEL <= RMM_LOG_LEVEL_DEBUG EXPECT_NE(oss.str().find("Outstanding Allocations"), std::string::npos); #endif From 853b8a10fc425fe8b13dbc532457da459767df4b Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 18:59:49 +0000 Subject: [PATCH 070/120] Add README --- rapids_logger/CMakeLists.txt | 2 -- rapids_logger/README.md | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 rapids_logger/README.md diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 453150744..ea332360e 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -32,8 +32,6 @@ rapids_cmake_build_type(Release) rapids_cpm_init() -# Make sure install logic is handled correctly, namely that nothing is installed from these. I think -# we'll need to both not specify an export set and EXCLUDE_FROM_ALL. include(../cmake/thirdparty/get_spdlog.cmake) #[=======================================================================[.rst: diff --git a/rapids_logger/README.md b/rapids_logger/README.md new file mode 100644 index 000000000..5c4354d88 --- /dev/null +++ b/rapids_logger/README.md @@ -0,0 +1,26 @@ +# About + +The `rapids-logger` project defines an easy way to produce a project-specific logger using the excellent [spdlog](https://github.com/gabime/spdlog) package. +The goal of this project is to ensure that projects wishing to provide their own logger may do so easily without needing to reimplement their own custom wrappers around spdlog. +A core goal of the project is to ensure that the custom logger implementation does not leak any spdlog symbols, allowing the safe coexistence of different projects in the same environment even if they use different versions of spdlog. +That goal is the primary reason to prefer using this project rather than directly exposing a specialized instance of a spdlog logger in your own project. + +`rapids-logger` is designed to be used via CMake. +Its CMake defines a function `rapids_make_logger` that can be used to produce a project-specific logger class in a provided namespace. +The resulting logger exposes spdlog-like functionality via the [PImpl idiom](https://en.cppreference.com/w/cpp/language/pimpl) to avoid exposing spdlog symbols publicly. +It uses CMake and template C++ files to generate a public header file to describe the user interface and an inline header that should be placed in a single TU by consumers to compile the implementation. +To simplify usage, each invocation of the function produces two CMake targets, one representing the public header and one representing a trivial source file including the inline header. +Projects using `rapids-logger` should make the first target part of their public link interface while the latter should be linked to privately so that it is compiled into the project's library without public exposure. + +To support transitive usage in header-only libraries that may not wish to enforce the spdlog requirement on their consumers, `rapids-logger` may be compiled with `SUPPORTS_LOGGING=OFF`, in which case a nonfunctional logger is produced instead. +In this case the inline header is never used, and spdlog is not required at build-time. +All logging functions and macros are defined, so any code written using the logger will still compile, but no actual logging will take place (and any code that assumes logs have been written will fail at runtime). + +To mirror spdlog, each generated logger also ships with a set of logging macros `_LOG_` that may be used to control logging at compile-time as well as runtime using a compile-time variable `_LOG_ACTIVE_LEVEL`. +For example, a project called "rapids" will be able to write code like this: +``` +RAPIDS_LOG_WARN("Some message to be shown when the warning level is enabled"); +``` +and control whether that warning is shown by compiling the code with `RAPIDS_LOG_ACTIVE_LEVEL=RAPIDS_LOG_LEVEL_WARN`. +Each project is endowed with its own definition of levels, so different projects in the same environment may be safely configured independently of each other and of spdlog. +Each project is also given a `default_logger` function that produces a global logger that may be used anywhere, but projects may also freely instantiate additional loggers as needed. From 92d5e21b5f4a9cabfdbcb6c0c521f0e00aaf259d Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:03:33 +0000 Subject: [PATCH 071/120] Define default logging level --- rapids_logger/logger.hpp.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 7c5b1b83b..698fad907 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -378,6 +378,10 @@ inline logger& default_logger() } // Macros for easier logging, similar to spdlog. +#if !defined(@_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL) +#define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_INFO +#endif + #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOGGER_CALL(logger, level, ...) (logger).log(level, __VA_ARGS__) #if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_TRACE From 1ca5e8d611fdb9fb884f0a85f558b967636b7261 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:05:56 +0000 Subject: [PATCH 072/120] Try removing the exclude-libs --- rapids_logger/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index ea332360e..0f7515d5a 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -173,7 +173,7 @@ function(rapids_make_logger logger_namespace) $) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) # TODO: Figure out whether to use this or the visibility settings at compile-time or both. - target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") + # target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") endif() set(_install_export) From 7bd2086dcdb9b4e97b0e531d8adc0b06a04f0986 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:17:38 +0000 Subject: [PATCH 073/120] Compile spdlog with fpic --- cmake/thirdparty/get_spdlog.cmake | 5 +++++ rapids_logger/CMakeLists.txt | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 0ec5d6e0b..002fda242 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -35,6 +35,11 @@ function(find_and_configure_spdlog) INSTALL_EXPORT_SET rmm-exports BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" EXCLUDE_FROM_ALL) + set_target_properties( + spdlog + PROPERTIES CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON) endif() endfunction() diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 0f7515d5a..ea332360e 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -173,7 +173,7 @@ function(rapids_make_logger logger_namespace) $) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) # TODO: Figure out whether to use this or the visibility settings at compile-time or both. - # target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") + target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") endif() set(_install_export) From 7928515e6949a2b0bb2cef59eeed68c37e48bff2 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:22:11 +0000 Subject: [PATCH 074/120] Make sure spdlog is available for compiling tests that need it. --- tests/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 611944cc1..3e3fa26f7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -129,6 +129,11 @@ if(RMM_SUPPORTS_LOGGING) target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) endif() +# TODO: Should we use CPM here, or since it's just tests should we assume spdlog is provided in the +# environment? Even if we want to use CPM, we should probably simplify the logic to not need to +# recompile spdlog with the same flags as rmm. +include(../cmake/thirdparty/get_spdlog.cmake) + # test sources # device mr_ref tests @@ -137,6 +142,7 @@ ConfigureTest(DEVICE_MR_REF_TEST mr/device/mr_ref_tests.cpp # general adaptor tests ConfigureTest(ADAPTOR_TEST mr/device/adaptor_tests.cpp) +target_link_libraries(ADAPTOR_TEST PRIVATE spdlog::spdlog) # pool mr tests ConfigureTest(POOL_MR_TEST mr/device/pool_mr_tests.cpp GPUS 1 PERCENT 100) @@ -194,6 +200,7 @@ ConfigureTest(PREFETCH_TEST prefetch_tests.cpp) # logger tests ConfigureTest(LOGGER_TEST logger_tests.cpp) +target_link_libraries(LOGGER_TEST PRIVATE spdlog::spdlog) # arena MR tests ConfigureTest(ARENA_MR_TEST mr/device/arena_mr_tests.cpp GPUS 1 PERCENT 100) From 6d6a4e44b215e4052aab8863a3e05ef846446add Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:26:37 +0000 Subject: [PATCH 075/120] Fix test that needs spdlog --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3e3fa26f7..02d81a92a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -142,7 +142,6 @@ ConfigureTest(DEVICE_MR_REF_TEST mr/device/mr_ref_tests.cpp # general adaptor tests ConfigureTest(ADAPTOR_TEST mr/device/adaptor_tests.cpp) -target_link_libraries(ADAPTOR_TEST PRIVATE spdlog::spdlog) # pool mr tests ConfigureTest(POOL_MR_TEST mr/device/pool_mr_tests.cpp GPUS 1 PERCENT 100) @@ -164,6 +163,7 @@ ConfigureTest(STATISTICS_TEST mr/device/statistics_mr_tests.cpp) # tracking adaptor tests ConfigureTest(TRACKING_TEST mr/device/tracking_mr_tests.cpp) +target_link_libraries(TRACKING_TEST PRIVATE spdlog::spdlog) # out-of-memory callback adaptor tests ConfigureTest(FAILURE_CALLBACK_TEST mr/device/failure_callback_mr_tests.cpp) From cc2c1f9156ea7f9923821e730f00ca8922354d48 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:35:14 +0000 Subject: [PATCH 076/120] Remove redundant flag --- cmake/thirdparty/get_spdlog.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 002fda242..b8fabb2ab 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -30,7 +30,6 @@ function(find_and_configure_spdlog) # pre-built libraries. It's quick enough to build that there is no real benefit to supporting # the alternative. set(CPM_DOWNLOAD_spdlog ON) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") rapids_cpm_spdlog( INSTALL_EXPORT_SET rmm-exports BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" From 098500699303fc5388255c2b134463361aa2a477 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:37:48 +0000 Subject: [PATCH 077/120] Always set fpic --- cmake/thirdparty/get_spdlog.cmake | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index b8fabb2ab..14cb5a4a4 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -34,12 +34,12 @@ function(find_and_configure_spdlog) INSTALL_EXPORT_SET rmm-exports BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" EXCLUDE_FROM_ALL) - set_target_properties( - spdlog - PROPERTIES CXX_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN ON - POSITION_INDEPENDENT_CODE ON) + # Can't make both cmake-format and cmake-lint happy here. + # cmake-format: off + set_target_properties(spdlog PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) + # cmake-format: on endif() + set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON) endfunction() find_and_configure_spdlog() From 3ca0f106083e27819148220ec03230226871a301 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:43:21 +0000 Subject: [PATCH 078/120] Also set up linkage for PTDS tests --- tests/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 02d81a92a..063f23eda 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -164,6 +164,7 @@ ConfigureTest(STATISTICS_TEST mr/device/statistics_mr_tests.cpp) # tracking adaptor tests ConfigureTest(TRACKING_TEST mr/device/tracking_mr_tests.cpp) target_link_libraries(TRACKING_TEST PRIVATE spdlog::spdlog) +target_link_libraries(TRACKING_PTDS_TEST PRIVATE spdlog::spdlog) # out-of-memory callback adaptor tests ConfigureTest(FAILURE_CALLBACK_TEST mr/device/failure_callback_mr_tests.cpp) @@ -201,6 +202,7 @@ ConfigureTest(PREFETCH_TEST prefetch_tests.cpp) # logger tests ConfigureTest(LOGGER_TEST logger_tests.cpp) target_link_libraries(LOGGER_TEST PRIVATE spdlog::spdlog) +target_link_libraries(LOGGER_PTDS_TEST PRIVATE spdlog::spdlog) # arena MR tests ConfigureTest(ARENA_MR_TEST mr/device/arena_mr_tests.cpp GPUS 1 PERCENT 100) From 46e650b2e5594b10c3c5f9f6457b8f57a8d8e29e Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:57:51 +0000 Subject: [PATCH 079/120] Also compile the logger itself with fpic --- rapids_logger/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index ea332360e..1adf5feea 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -174,6 +174,11 @@ function(rapids_make_logger logger_namespace) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) # TODO: Figure out whether to use this or the visibility settings at compile-time or both. target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") + set_target_properties( + ${impl_target} + PROPERTIES POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON) endif() set(_install_export) From b450cfbcfbea74ab6ccefb234da2c912c5dd1156 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:58:01 +0000 Subject: [PATCH 080/120] Remove unnecessary inline. --- rapids_logger/logger_impl.hpp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 4aca3b1b8..c6e6591a8 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -31,7 +31,7 @@ namespace __attribute__((visibility("hidden"))) @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { -inline level_enum string_to_level(std::string_view const env_lvl_str) +level_enum string_to_level(std::string_view const env_lvl_str) { if (env_lvl_str == "TRACE") return level_enum::trace; if (env_lvl_str == "DEBUG") return level_enum::debug; From dd906e09a1dea506c44a4919a1aae8eaa4057b92 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 19:58:23 +0000 Subject: [PATCH 081/120] Switch to using bundled fmt --- cmake/thirdparty/get_spdlog.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 14cb5a4a4..476d2ca9b 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -23,14 +23,19 @@ function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) if(RMM_SPDLOG_DYNAMIC) rapids_cpm_spdlog( - INSTALL_EXPORT_SET rmm-exports BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED ON" - "BUILD_SHARED_LIBS ON") + FMT_OPTION "BUNDLED" + INSTALL_EXPORT_SET rmm-exports + BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED ON" "BUILD_SHARED_LIBS ON") else() # For static spdlog usage assume that we want to hide as many symbols as possible, so do not use # pre-built libraries. It's quick enough to build that there is no real benefit to supporting # the alternative. set(CPM_DOWNLOAD_spdlog ON) rapids_cpm_spdlog( + # TODO: Is this safe to set up for all projects? Do we have to worry about the fmt patch + # currently in rapids-cmake? We should never be compiling files using spdlog under nvcc + # anymore. + FMT_OPTION "BUNDLED" INSTALL_EXPORT_SET rmm-exports BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" EXCLUDE_FROM_ALL) From aed83203194d5c36ac531a8369c36bfec7355388 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sun, 17 Nov 2024 20:07:15 +0000 Subject: [PATCH 082/120] Also set interface_position_independent_code --- rapids_logger/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 1adf5feea..8f66d7526 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -177,6 +177,7 @@ function(rapids_make_logger logger_namespace) set_target_properties( ${impl_target} PROPERTIES POSITION_INDEPENDENT_CODE ON + INTERFACE_POSITION_INDEPENDENT_CODE ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) endif() From f5830c73393786db06a2ef2821e1c0aa2de8d882 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 18 Nov 2024 07:32:19 +0000 Subject: [PATCH 083/120] Fix title name --- rapids_logger/logger.hpp.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 698fad907..19e822499 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -363,13 +363,13 @@ inline logger& default_logger() { static logger logger_ = [] { logger logger_ { - "RAPIDS", default_log_filename() + "@_RAPIDS_LOGGER_MACRO_PREFIX@", default_log_filename() }; #if @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_ACTIVE_LEVEL <= @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_INFO #ifdef CUDA_API_PER_THREAD_DEFAULT_STREAM - logger_.info("----- RAPIDS LOG BEGIN [PTDS ENABLED] -----"); + logger_.info("----- @_RAPIDS_LOGGER_MACRO_PREFIX@ LOG BEGIN [PTDS ENABLED] -----"); #else - logger_.info("----- RAPIDS LOG BEGIN [PTDS DISABLED] -----"); + logger_.info("----- @_RAPIDS_LOGGER_MACRO_PREFIX@ LOG BEGIN [PTDS DISABLED] -----"); #endif #endif return logger_; From 7020b9b647f3fa83958212489bcc44a7685dce75 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 18 Nov 2024 18:30:11 +0000 Subject: [PATCH 084/120] Don't fail on symbol errors to see if CI passes --- ci/check_symbols.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/check_symbols.sh b/ci/check_symbols.sh index 1d73a082b..47d8295c2 100755 --- a/ci/check_symbols.sh +++ b/ci/check_symbols.sh @@ -18,7 +18,8 @@ See https://cmake.org/cmake/help/latest/prop_tgt/LANG_VISIBILITY_PRESET.html and echo "" echo "${err_msg}" - exit 1 + # TODO: Put this back once we decide what to check. + #exit 1 } WHEEL_EXPORT_DIR="$(mktemp -d)" From e068335f7bd9ff0b205e3dbfed3eab7a630b3207 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 20 Nov 2024 03:32:06 +0000 Subject: [PATCH 085/120] Don't use CMAKE_INSTALL_PREFIX --- rapids_logger/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 8f66d7526..4bd984935 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -129,7 +129,8 @@ function(rapids_make_logger logger_namespace) # function is invoked. As a result we cannot use relative paths here because CMake will root these # paths incorrectly for configure_file/install. set(BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/${_RAPIDS_LOGGER_HEADER_DIR}) - set(INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${_RAPIDS_LOGGER_HEADER_DIR}) + # TODO: Verify that installation works correctly with prefix removed. + set(INSTALL_DIR ${_RAPIDS_LOGGER_HEADER_DIR}) set(LOGGER_OUTPUT_FILE ${BUILD_DIR}/logger.hpp) configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.hpp.in ${LOGGER_OUTPUT_FILE}) From 4520ccb44c5ecf75317d3052e17eb7f0108f9752 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Wed, 20 Nov 2024 03:32:35 +0000 Subject: [PATCH 086/120] Add support for callbacks --- rapids_logger/logger.hpp.in | 24 ++++++++++++++++++++++++ rapids_logger/logger_impl.hpp.in | 18 +++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 19e822499..831761287 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -76,6 +76,8 @@ class sink { friend class logger; }; +typedef void (*CallbackType)(int lvl, const char* msg); + /** * @class logger * @brief A logger class that either uses the real implementation (via spdlog) or performs no-ops if @@ -253,6 +255,13 @@ class logger { */ void add_sink(spdlog::sink_ptr sink); + /** + * @brief Add a sink calling this callback to the logger. + * + * @param callback The callable to invoke + */ + void set_callback(CallbackType callback); + /** * @brief Remove a sink from the logger. * @@ -260,6 +269,11 @@ class logger { */ void remove_sink(spdlog::sink_ptr sink); + /** + * @brief Remove the callback sink from the logger. + */ + void remove_callback(); + /** * @brief Get the current log level. * @@ -313,6 +327,7 @@ class logger { private: std::unique_ptr impl; ///< The spdlog logger + spdlog::sink_ptr callback_sink; ///< The callback sink void init_logger(); #else logger(std::string name, std::string filename) {} @@ -324,8 +339,10 @@ class logger { // when this function is, so a template is used to capture the user's type. template void add_sink(Sink sink) {} + void set_callback(CallbackType callback) {} template void remove_sink(Sink sink) {} + void remove_callback() {} level_enum level() const { return level_enum::off; } void set_level(level_enum log_level) {} void flush() {} @@ -354,6 +371,13 @@ inline std::string default_log_filename() return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; } +/** + * @brief Returns the default log pattern for the global logger. + * + * @return std::string The default log pattern. + */ +inline std::string default_pattern() { return "[%6t][%H:%M:%S:%f][%-6l] %v"; } + /** * @brief Get the default logger. * diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index c6e6591a8..39041ec88 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -18,8 +18,11 @@ #include "../logger.hpp" +#include +#include #include #include +#include #include #include @@ -101,7 +104,7 @@ logger::logger(std::string name, std::vector> sinks) } void logger::init_logger() { - impl->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); + impl->set_pattern(default_pattern()); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { set_level(detail::string_to_level(env_logging_level)); @@ -124,10 +127,23 @@ void logger::flush_on(level_enum log_level) { impl->flush_on(detail::to_spdlog_l level_enum logger::flush_level() const { return detail::from_spdlog_level(impl->flush_level()); } bool logger::should_log(level_enum lvl) const { return impl->should_log(detail::to_spdlog_level(lvl)); } void logger::add_sink(spdlog::sink_ptr sink) { impl->sinks().push_back(sink); } +void logger::set_callback(CallbackType callback) { + auto _callback = [&callback](const spdlog::details::log_msg &msg_) { + spdlog::memory_buf_t formatted; + spdlog::pattern_formatter().format(msg_, formatted); + std::string msg_string = fmt::to_string(formatted); + callback(static_cast(msg_.level), msg_string.c_str()); + }; + callback_sink = std::make_shared(_callback); +} void logger::remove_sink(spdlog::sink_ptr sink) { auto& sinks = impl->sinks(); sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); } +void logger::remove_callback() { + remove_sink(callback_sink); + callback_sink.reset(); +} level_enum logger::level() const { return detail::from_spdlog_level(impl->level()); } void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } From 0abd94c5fcbc635deacd0727c948efa52ede2a22 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 22 Nov 2024 16:59:04 +0000 Subject: [PATCH 087/120] Remove dynamic spdlog --- CMakeLists.txt | 1 - cmake/thirdparty/get_spdlog.cmake | 38 ++++++++++++------------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f74b50f89..280205a67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,6 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) option(RMM_SUPPORTS_LOGGING "Enable logging support" ON) -option(RMM_SPDLOG_DYNAMIC "Use dynamic linking for spdlog" OFF) # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 476d2ca9b..8406020fa 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -21,29 +21,21 @@ function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) - if(RMM_SPDLOG_DYNAMIC) - rapids_cpm_spdlog( - FMT_OPTION "BUNDLED" - INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED ON" "BUILD_SHARED_LIBS ON") - else() - # For static spdlog usage assume that we want to hide as many symbols as possible, so do not use - # pre-built libraries. It's quick enough to build that there is no real benefit to supporting - # the alternative. - set(CPM_DOWNLOAD_spdlog ON) - rapids_cpm_spdlog( - # TODO: Is this safe to set up for all projects? Do we have to worry about the fmt patch - # currently in rapids-cmake? We should never be compiling files using spdlog under nvcc - # anymore. - FMT_OPTION "BUNDLED" - INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" - EXCLUDE_FROM_ALL) - # Can't make both cmake-format and cmake-lint happy here. - # cmake-format: off - set_target_properties(spdlog PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) - # cmake-format: on - endif() + # For static spdlog usage assume that we want to hide as many symbols as possible, so do not use + # pre-built libraries. It's quick enough to build that there is no real benefit to supporting the + # alternative. + set(CPM_DOWNLOAD_spdlog ON) + rapids_cpm_spdlog( + # TODO: Is this safe to set up for all projects? Do we have to worry about the fmt patch + # currently in rapids-cmake? We should never be compiling files using spdlog under nvcc anymore. + FMT_OPTION "BUNDLED" + INSTALL_EXPORT_SET rmm-exports + BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" + EXCLUDE_FROM_ALL) + # Can't make both cmake-format and cmake-lint happy here. + # cmake-format: off + set_target_properties(spdlog PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) + # cmake-format: on set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON) endfunction() From fe19b2be41717fe7846ae2e44d209ec0a5959482 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 22 Nov 2024 17:05:35 +0000 Subject: [PATCH 088/120] Remove support for building without logging support --- CMakeLists.txt | 8 +--- benchmarks/CMakeLists.txt | 13 ++---- cmake/thirdparty/get_spdlog.cmake | 7 +--- python/rmm/CMakeLists.txt | 7 +--- python/rmm/rmm/tests/test_rmm.py | 9 ----- rapids_logger/CMakeLists.txt | 65 +++++++++++++----------------- rapids_logger/README.md | 4 -- rapids_logger/logger.hpp.in | 35 ---------------- tests/CMakeLists.txt | 13 ++---- tests/logger_tests.cpp | 6 --- tests/mr/device/arena_mr_tests.cpp | 2 - 11 files changed, 39 insertions(+), 130 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 280205a67..cbf31851e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,8 +58,6 @@ message(STATUS "RMM: RMM_LOGGING_LEVEL = '${RMM_LOGGING_LEVEL}'") # cudart can be linked statically or dynamically option(CUDA_STATIC_RUNTIME "Statically link the CUDA runtime" OFF) -option(RMM_SUPPORTS_LOGGING "Enable logging support" ON) - # ################################################################################################## # * compiler options ------------------------------------------------------------------------------- @@ -76,12 +74,8 @@ rapids_find_package( rapids_cpm_init() add_subdirectory(rapids_logger) -set(_logging_support_flag) -if(RMM_SUPPORTS_LOGGING) - set(_logging_support_flag "SUPPORTS_LOGGING") -endif() rapids_make_logger(rmm EXPORT_SET rmm-exports VISIBILITY_MACRO - "__attribute__((visibility(\"default\")))" ${_logging_support_flag}) + "__attribute__((visibility(\"default\")))") include(cmake/thirdparty/get_cccl.cmake) include(cmake/thirdparty/get_nvtx.cmake) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 272b47f6e..b3b60cfcb 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -45,9 +45,7 @@ function(ConfigureBench BENCH_NAME) target_compile_options(${BENCH_NAME} PUBLIC $<$:-Wall -Werror -Wno-unknown-pragmas>) - if(TARGET rmm_bench_logger) - target_link_libraries(${BENCH_NAME} PRIVATE rmm_bench_logger) - endif() + target_link_libraries(${BENCH_NAME} PRIVATE rmm_bench_logger) if(DISABLE_DEPRECATION_WARNING) target_compile_options( @@ -63,12 +61,9 @@ function(ConfigureBench BENCH_NAME) EXCLUDE_FROM_ALL) endfunction(ConfigureBench) -# Create an object library for the logger so that we don't have to recompile it. This is not -# necessary if logging is unsupported since then the header-only implementation is sufficient. -if(RMM_SUPPORTS_LOGGING) - add_library(rmm_bench_logger OBJECT) - target_link_libraries(rmm_bench_logger PRIVATE rmm_logger_impl) -endif() +# Create an object library for the logger so that we don't have to recompile it. +add_library(rmm_bench_logger OBJECT) +target_link_libraries(rmm_bench_logger PRIVATE rmm_logger_impl) # random allocations benchmark ConfigureBench(RANDOM_ALLOCATIONS_BENCH random_allocations/random_allocations.cpp) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 8406020fa..0ad6286e3 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -12,12 +12,7 @@ # the License. # ============================================================================= -# Use CPM to find or clone speedlog TODO: The logic here should be upstreamed into rapids-logger and -# probably removed from rapids-cmake. Note that it is not possible to build with two different modes -# for different projects in the same build environment, so this functionality must be kept -# independent of the rapids_make_logger function. Alternatively, we could update the cpm calls for -# spdlog to not promote targets to global scope and instead allow each project to find and configure -# spdlog independently. +# Use CPM to find or clone speedlog. function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) diff --git a/python/rmm/CMakeLists.txt b/python/rmm/CMakeLists.txt index d407cec6d..a39ac8868 100644 --- a/python/rmm/CMakeLists.txt +++ b/python/rmm/CMakeLists.txt @@ -29,12 +29,7 @@ rapids_cython_init() # pass through logging level to spdlog add_compile_definitions("RMM_LOG_ACTIVE_LEVEL=RMM_LOG_LEVEL_${RMM_LOGGING_LEVEL}") -# Create an object library for the logger so that we don't have to recompile it. This assumes that -# we always have logging enabled when we built the C++ library since the targets that are created -# when we find_package(rmm) already have that setting baked in. TODO: Figure out how to use -# define_property in the C++ build to make SUPPORTS_LOGGING a queryable property that can be checked -# here. Otherwise we just assume that the Python package is never built against a C++ rmm without -# logging support. +# Create an object library for the logger so that we don't have to recompile it. add_library(cpp_logger OBJECT) target_link_libraries(cpp_logger PRIVATE rmm::rmm_logger_impl) diff --git a/python/rmm/rmm/tests/test_rmm.py b/python/rmm/rmm/tests/test_rmm.py index bbe44aef0..0fe21c299 100644 --- a/python/rmm/rmm/tests/test_rmm.py +++ b/python/rmm/rmm/tests/test_rmm.py @@ -130,9 +130,6 @@ def test_rmm_modes_system_memory(dtype, nelem, alloc, system, pool, headroom): array_tester(dtype, nelem, alloc) -# TODO: This won't work when logging is disabled in C++, but I think we should -# assume that the Python package is always built against a librmm with logging -# support. @pytest.mark.parametrize("dtype", _dtypes) @pytest.mark.parametrize("nelem", _nelems) @pytest.mark.parametrize("alloc", _allocs) @@ -574,9 +571,6 @@ def test_reinitialize_with_invalid_str_arg_pool_size(): assert "Could not parse" in str(e.value) -# TODO: This won't work when logging is disabled in C++, but I think we should -# assume that the Python package is always built against a librmm with logging -# support. @pytest.mark.parametrize("dtype", _dtypes) @pytest.mark.parametrize("nelem", _nelems) @pytest.mark.parametrize("alloc", _allocs) @@ -1062,9 +1056,6 @@ def test_rmm_device_buffer_copy(cuda_ary, make_copy): np.testing.assert_equal(expected, result) -# TODO: This won't work when logging is disabled in C++, but I think we should -# assume that the Python package is always built against a librmm with logging -# support. @pytest.mark.parametrize("level", level_enum) def test_valid_logging_level(level): default_level = level_enum.info diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 4bd984935..9b637d949 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -48,12 +48,11 @@ Generate a logger implementation customized for the specified namespace. [LOGGER_HEADER_DIR ] [LOGGER_MACRO_PREFIX ] [VISIBILITY_MACRO ] - [SUPPORTS_LOGGING] ) This function produces an interface target named that, when linked to by other targets, provides them a header file that defines a logger interface for the specified namespace. The logger is generated from the provided template files and is configured to use the specified namespace and macro prefix. The generated logger is placed in the specified header directory. -The logger implementation lives in a separate header file that is not included in the declaration header. If `SUPPORTS_LOGGING` is off, the logger target is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. If `SUPPORTS_LOGGING` is on, the logger implementation is compiled into a separate target that must be linked to by any target that uses the logger. +The logger implementation lives in a separate header file that is not included in the declaration header. The logger implementation is compiled into a separate target that must be linked to by any target that uses the logger. ``logger_namespace`` @@ -74,14 +73,11 @@ The logger implementation lives in a separate header file that is not included i ``VISIBILITY_MACRO`` The macro to use for visibility annotations. If not specified, no visibility annotations are added to the logger interface. -``SUPPORTS_LOGGING`` - If specified, the logger target is configured to support logging. If not specified, the resulting logger is entirely nonfunctional. In that case, all operations are still defined (as no-ops) so that consumers may write the same logging code regardless of whether logging is enabled or disabled. This setting is required for the logger implementation to be generated. - Result Targets ^^^^^^^^^^^^^^^^ is an interface target that provides the logger interface for the specified namespace. - _impl is an interface target that provides the logger implementation for the specified namespace. This target must be linked to by any target that uses the logger. It is only defined `SUPPORTS_LOGGING` is on. Targets linking to this target will have the logger implementation compiled into them. + _impl is an interface target that provides the logger implementation for the specified namespace. This target must be linked to by any target that uses the logger. Targets linking to this target will have the logger implementation compiled into them. Examples ^^^^^^^^ @@ -94,7 +90,6 @@ Example on how to use :cmake:command:`rapids_make_logger`. # Generate a logger for the namespace "rapids" and associate it with the # export set "rapids-exports". rapids_make_logger(rapids - SUPPORTS_LOGGING EXPORT_SET rapids-exports ) @@ -106,7 +101,7 @@ Example on how to use :cmake:command:`rapids_make_logger`. function(rapids_make_logger logger_namespace) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") - set(_rapids_options SUPPORTS_LOGGING) + set(_rapids_options) set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX VISIBILITY_MACRO) set(_rapids_multi_value) @@ -153,35 +148,31 @@ function(rapids_make_logger logger_namespace) INTERFACE "$" "$") target_compile_features(${_RAPIDS_LOGGER_TARGET} INTERFACE cxx_std_17) - if(_RAPIDS_SUPPORTS_LOGGING) - target_compile_definitions(${_RAPIDS_LOGGER_TARGET} - INTERFACE "${_RAPIDS_LOGGER_MACRO_PREFIX}_SUPPORTS_LOGGING") - - # Create an interface target that will trigger compilation of the logger implementation in any - # target that is linked to it. - set(LOGGER_IMPL_SRC_OUTPUT_FILE ${BUILD_DIR}/logger_impl/logger.cpp) - configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.cpp.in ${LOGGER_IMPL_SRC_OUTPUT_FILE}) - install(FILES ${LOGGER_IMPL_SRC_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) - - # Note that we cannot specify the source files directly in add_library, see the CMake - # documentation explaining that these do not populate INTERFACE_SOURCES. - # https://cmake.org/cmake/help/latest/command/add_library.html#interface-with-sources - set(impl_target ${_RAPIDS_LOGGER_TARGET}_impl) - add_library(${impl_target} INTERFACE) - target_sources( - ${impl_target} - INTERFACE $ - $) - target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) - # TODO: Figure out whether to use this or the visibility settings at compile-time or both. - target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") - set_target_properties( - ${impl_target} - PROPERTIES POSITION_INDEPENDENT_CODE ON - INTERFACE_POSITION_INDEPENDENT_CODE ON - CXX_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN ON) - endif() + + # Create an interface target that will trigger compilation of the logger implementation in any + # target that is linked to it. + set(LOGGER_IMPL_SRC_OUTPUT_FILE ${BUILD_DIR}/logger_impl/logger.cpp) + configure_file(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/logger.cpp.in ${LOGGER_IMPL_SRC_OUTPUT_FILE}) + install(FILES ${LOGGER_IMPL_SRC_OUTPUT_FILE} DESTINATION ${INSTALL_DIR}/logger_impl) + + # Note that we cannot specify the source files directly in add_library, see the CMake + # documentation explaining that these do not populate INTERFACE_SOURCES. + # https://cmake.org/cmake/help/latest/command/add_library.html#interface-with-sources + set(impl_target ${_RAPIDS_LOGGER_TARGET}_impl) + add_library(${impl_target} INTERFACE) + target_sources( + ${impl_target} + INTERFACE $ + $) + target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) + # TODO: Figure out whether to use this or the visibility settings at compile-time or both. + target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") + set_target_properties( + ${impl_target} + PROPERTIES POSITION_INDEPENDENT_CODE ON + INTERFACE_POSITION_INDEPENDENT_CODE ON + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON) set(_install_export) if(_RAPIDS_EXPORT_SET) diff --git a/rapids_logger/README.md b/rapids_logger/README.md index 5c4354d88..00e505fc7 100644 --- a/rapids_logger/README.md +++ b/rapids_logger/README.md @@ -12,10 +12,6 @@ It uses CMake and template C++ files to generate a public header file to describ To simplify usage, each invocation of the function produces two CMake targets, one representing the public header and one representing a trivial source file including the inline header. Projects using `rapids-logger` should make the first target part of their public link interface while the latter should be linked to privately so that it is compiled into the project's library without public exposure. -To support transitive usage in header-only libraries that may not wish to enforce the spdlog requirement on their consumers, `rapids-logger` may be compiled with `SUPPORTS_LOGGING=OFF`, in which case a nonfunctional logger is produced instead. -In this case the inline header is never used, and spdlog is not required at build-time. -All logging functions and macros are defined, so any code written using the logger will still compile, but no actual logging will take place (and any code that assumes logs have been written will fail at runtime). - To mirror spdlog, each generated logger also ships with a set of logging macros `_LOG_` that may be used to control logging at compile-time as well as runtime using a compile-time variable `_LOG_ACTIVE_LEVEL`. For example, a project called "rapids" will be able to write code like this: ``` diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 831761287..fb8b3ea23 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -21,8 +21,6 @@ #include #include -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING - // Forward declare spdlog types that are part of our public API. namespace spdlog { class logger; @@ -32,8 +30,6 @@ class sink; using sink_ptr = std::shared_ptr; } // namespace spdlog -#endif - namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { // These values must be kept in sync with spdlog! @@ -62,17 +58,10 @@ enum class level_enum : int32_t { }; class sink { -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING public: sink(spdlog::sink_ptr); private: spdlog::sink_ptr impl; -#else - public: - // Use a template to avoid needing a definition of spdlog's sink_ptr type. - template - sink(Sink) {} -#endif friend class logger; }; @@ -203,7 +192,6 @@ class logger { } // Everything below here is conditionally compiled based on whether logging is supported. -#ifdef @_RAPIDS_LOGGER_MACRO_PREFIX@_SUPPORTS_LOGGING /** * @brief Construct a new logger object * @@ -329,29 +317,6 @@ class logger { std::unique_ptr impl; ///< The spdlog logger spdlog::sink_ptr callback_sink; ///< The callback sink void init_logger(); -#else - logger(std::string name, std::string filename) {} - logger(std::string name, std::ostream& stream) {} - logger(std::string name, std::vector> sinks) {} - ~logger() = default; - void log(level_enum lvl, std::string const& message) {} - // When logging is not supported we won't have a spdlog sink_ptr type defined - // when this function is, so a template is used to capture the user's type. - template - void add_sink(Sink sink) {} - void set_callback(CallbackType callback) {} - template - void remove_sink(Sink sink) {} - void remove_callback() {} - level_enum level() const { return level_enum::off; } - void set_level(level_enum log_level) {} - void flush() {} - void flush_on(level_enum log_level) {} - level_enum flush_level() { return level_enum::off; } - bool should_log(level_enum msg_level) const { return false; } - void set_pattern(std::string pattern) {} - static constexpr bool supports_logging() { return false; } -#endif }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 063f23eda..5f7785d0d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,9 +44,7 @@ function(ConfigureTestInternal TEST_NAME) PUBLIC "RMM_LOG_ACTIVE_LEVEL=RMM_LOG_LEVEL_${RMM_LOGGING_LEVEL}") target_compile_options(${TEST_NAME} PUBLIC $<$:-Wall -Werror>) - if(TARGET rmm_test_logger) - target_link_libraries(${TEST_NAME} PRIVATE rmm_test_logger) - endif() + target_link_libraries(${TEST_NAME} PRIVATE rmm_test_logger) if(DISABLE_DEPRECATION_WARNING) target_compile_options( @@ -122,12 +120,9 @@ function(ConfigureTest TEST_NAME) endfunction() -# Create an object library for the logger so that we don't have to recompile it. This is not -# necessary if logging is unsupported since then the header-only implementation is sufficient. -if(RMM_SUPPORTS_LOGGING) - add_library(rmm_test_logger OBJECT) - target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) -endif() +# Create an object library for the logger so that we don't have to recompile it. +add_library(rmm_test_logger OBJECT) +target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) # TODO: Should we use CPM here, or since it's just tests should we assume spdlog is provided in the # environment? Even if we want to use CPM, we should probably simplify the logic to not need to diff --git a/tests/logger_tests.cpp b/tests/logger_tests.cpp index 7dcefb4bc..c42753fe8 100644 --- a/tests/logger_tests.cpp +++ b/tests/logger_tests.cpp @@ -101,7 +101,6 @@ class raii_temp_directory { void expect_log_events(std::string const& filename, std::vector const& expected_events) { -#ifdef SUPPORTS_LOGGING auto actual_events = rmm::detail::parse_csv(filename); std::equal(expected_events.begin(), @@ -118,7 +117,6 @@ void expect_log_events(std::string const& filename, EXPECT_EQ(expected.pointer, actual.pointer); return true; }); -#endif } TEST(Adaptor, FilenameConstructor) @@ -292,9 +290,7 @@ TEST(Adaptor, STDOUT) std::string output = testing::internal::GetCapturedStdout(); std::string header = output.substr(0, output.find('\n')); -#ifdef SUPPORTS_LOGGING ASSERT_EQ(header, log_mr.header()); -#endif } TEST(Adaptor, STDERR) @@ -312,9 +308,7 @@ TEST(Adaptor, STDERR) std::string output = testing::internal::GetCapturedStderr(); std::string header = output.substr(0, output.find('\n')); -#ifdef SUPPORTS_LOGGING ASSERT_EQ(header, log_mr.header()); -#endif } } // namespace diff --git a/tests/mr/device/arena_mr_tests.cpp b/tests/mr/device/arena_mr_tests.cpp index dd5c4e6ba..67f183a23 100644 --- a/tests/mr/device/arena_mr_tests.cpp +++ b/tests/mr/device/arena_mr_tests.cpp @@ -588,11 +588,9 @@ TEST_F(ArenaTest, DumpLogOnFailure) // NOLINT // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto) EXPECT_THROW(mr.allocate(8_MiB), rmm::out_of_memory); -#ifdef SUPPORTS_LOGGING struct stat file_status {}; EXPECT_EQ(stat("rmm_arena_memory_dump.log", &file_status), 0); EXPECT_GE(file_status.st_size, 0); -#endif } } // namespace From 2ffc82745b5e1395da7263a37592725fbaf7db7b Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 22 Nov 2024 17:06:50 +0000 Subject: [PATCH 089/120] Go back to checking symbols --- ci/check_symbols.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci/check_symbols.sh b/ci/check_symbols.sh index 47d8295c2..1d73a082b 100755 --- a/ci/check_symbols.sh +++ b/ci/check_symbols.sh @@ -18,8 +18,7 @@ See https://cmake.org/cmake/help/latest/prop_tgt/LANG_VISIBILITY_PRESET.html and echo "" echo "${err_msg}" - # TODO: Put this back once we decide what to check. - #exit 1 + exit 1 } WHEEL_EXPORT_DIR="$(mktemp -d)" From 2731a539d9c0869c09c8e73286513f08c99284fb Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 22 Nov 2024 17:13:53 +0000 Subject: [PATCH 090/120] Switch back to header-only spdlog --- cmake/thirdparty/get_spdlog.cmake | 16 ++-------------- rapids_logger/CMakeLists.txt | 5 ++--- tests/CMakeLists.txt | 11 ++++------- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/cmake/thirdparty/get_spdlog.cmake b/cmake/thirdparty/get_spdlog.cmake index 0ad6286e3..212f604c3 100644 --- a/cmake/thirdparty/get_spdlog.cmake +++ b/cmake/thirdparty/get_spdlog.cmake @@ -16,22 +16,10 @@ function(find_and_configure_spdlog) include(${rapids-cmake-dir}/cpm/spdlog.cmake) - # For static spdlog usage assume that we want to hide as many symbols as possible, so do not use - # pre-built libraries. It's quick enough to build that there is no real benefit to supporting the - # alternative. - set(CPM_DOWNLOAD_spdlog ON) rapids_cpm_spdlog( - # TODO: Is this safe to set up for all projects? Do we have to worry about the fmt patch - # currently in rapids-cmake? We should never be compiling files using spdlog under nvcc anymore. - FMT_OPTION "BUNDLED" + FMT_OPTION "EXTERNAL_FMT_HO" INSTALL_EXPORT_SET rmm-exports - BUILD_EXPORT_SET rmm-exports OPTIONS "SPDLOG_BUILD_SHARED OFF" "BUILD_SHARED_LIBS OFF" - EXCLUDE_FROM_ALL) - # Can't make both cmake-format and cmake-lint happy here. - # cmake-format: off - set_target_properties(spdlog PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) - # cmake-format: on - set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON) + BUILD_EXPORT_SET rmm-exports) endfunction() find_and_configure_spdlog() diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 9b637d949..c8f98d8d1 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -164,9 +164,8 @@ function(rapids_make_logger logger_namespace) ${impl_target} INTERFACE $ $) - target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog) - # TODO: Figure out whether to use this or the visibility settings at compile-time or both. - target_link_options(${impl_target} INTERFACE "LINKER:--exclude-libs,libspdlog") + target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} + spdlog::spdlog_header_only) set_target_properties( ${impl_target} PROPERTIES POSITION_INDEPENDENT_CODE ON diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5f7785d0d..151a054eb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -124,9 +124,6 @@ endfunction() add_library(rmm_test_logger OBJECT) target_link_libraries(rmm_test_logger PRIVATE rmm_logger_impl) -# TODO: Should we use CPM here, or since it's just tests should we assume spdlog is provided in the -# environment? Even if we want to use CPM, we should probably simplify the logic to not need to -# recompile spdlog with the same flags as rmm. include(../cmake/thirdparty/get_spdlog.cmake) # test sources @@ -158,8 +155,8 @@ ConfigureTest(STATISTICS_TEST mr/device/statistics_mr_tests.cpp) # tracking adaptor tests ConfigureTest(TRACKING_TEST mr/device/tracking_mr_tests.cpp) -target_link_libraries(TRACKING_TEST PRIVATE spdlog::spdlog) -target_link_libraries(TRACKING_PTDS_TEST PRIVATE spdlog::spdlog) +target_link_libraries(TRACKING_TEST PRIVATE spdlog::spdlog_header_only) +target_link_libraries(TRACKING_PTDS_TEST PRIVATE spdlog::spdlog_header_only) # out-of-memory callback adaptor tests ConfigureTest(FAILURE_CALLBACK_TEST mr/device/failure_callback_mr_tests.cpp) @@ -196,8 +193,8 @@ ConfigureTest(PREFETCH_TEST prefetch_tests.cpp) # logger tests ConfigureTest(LOGGER_TEST logger_tests.cpp) -target_link_libraries(LOGGER_TEST PRIVATE spdlog::spdlog) -target_link_libraries(LOGGER_PTDS_TEST PRIVATE spdlog::spdlog) +target_link_libraries(LOGGER_TEST PRIVATE spdlog::spdlog_header_only) +target_link_libraries(LOGGER_PTDS_TEST PRIVATE spdlog::spdlog_header_only) # arena MR tests ConfigureTest(ARENA_MR_TEST mr/device/arena_mr_tests.cpp GPUS 1 PERCENT 100) From 0a7b337847a5d3f22b6eaeaf4551f1fe03654bf6 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 22 Nov 2024 17:20:34 +0000 Subject: [PATCH 091/120] Revert "Add support for callbacks" This reverts commit 4520ccb44c5ecf75317d3052e17eb7f0108f9752. --- rapids_logger/logger.hpp.in | 22 ---------------------- rapids_logger/logger_impl.hpp.in | 18 +----------------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index fb8b3ea23..49f5046f2 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -65,8 +65,6 @@ class sink { friend class logger; }; -typedef void (*CallbackType)(int lvl, const char* msg); - /** * @class logger * @brief A logger class that either uses the real implementation (via spdlog) or performs no-ops if @@ -243,13 +241,6 @@ class logger { */ void add_sink(spdlog::sink_ptr sink); - /** - * @brief Add a sink calling this callback to the logger. - * - * @param callback The callable to invoke - */ - void set_callback(CallbackType callback); - /** * @brief Remove a sink from the logger. * @@ -257,11 +248,6 @@ class logger { */ void remove_sink(spdlog::sink_ptr sink); - /** - * @brief Remove the callback sink from the logger. - */ - void remove_callback(); - /** * @brief Get the current log level. * @@ -315,7 +301,6 @@ class logger { private: std::unique_ptr impl; ///< The spdlog logger - spdlog::sink_ptr callback_sink; ///< The callback sink void init_logger(); }; @@ -336,13 +321,6 @@ inline std::string default_log_filename() return (filename == nullptr) ? std::string{"@_RAPIDS_LOGGER_NAMESPACE@_log.txt"} : std::string{filename}; } -/** - * @brief Returns the default log pattern for the global logger. - * - * @return std::string The default log pattern. - */ -inline std::string default_pattern() { return "[%6t][%H:%M:%S:%f][%-6l] %v"; } - /** * @brief Get the default logger. * diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 39041ec88..c6e6591a8 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -18,11 +18,8 @@ #include "../logger.hpp" -#include -#include #include #include -#include #include #include @@ -104,7 +101,7 @@ logger::logger(std::string name, std::vector> sinks) } void logger::init_logger() { - impl->set_pattern(default_pattern()); + impl->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { set_level(detail::string_to_level(env_logging_level)); @@ -127,23 +124,10 @@ void logger::flush_on(level_enum log_level) { impl->flush_on(detail::to_spdlog_l level_enum logger::flush_level() const { return detail::from_spdlog_level(impl->flush_level()); } bool logger::should_log(level_enum lvl) const { return impl->should_log(detail::to_spdlog_level(lvl)); } void logger::add_sink(spdlog::sink_ptr sink) { impl->sinks().push_back(sink); } -void logger::set_callback(CallbackType callback) { - auto _callback = [&callback](const spdlog::details::log_msg &msg_) { - spdlog::memory_buf_t formatted; - spdlog::pattern_formatter().format(msg_, formatted); - std::string msg_string = fmt::to_string(formatted); - callback(static_cast(msg_.level), msg_string.c_str()); - }; - callback_sink = std::make_shared(_callback); -} void logger::remove_sink(spdlog::sink_ptr sink) { auto& sinks = impl->sinks(); sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); } -void logger::remove_callback() { - remove_sink(callback_sink); - callback_sink.reset(); -} level_enum logger::level() const { return detail::from_spdlog_level(impl->level()); } void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } From 4f6b98c8bfe4064ce16f728f458e5c851f36d0ed Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Fri, 22 Nov 2024 17:36:49 +0000 Subject: [PATCH 092/120] Revert "Go back to checking symbols" This reverts commit 2ffc82745b5e1395da7263a37592725fbaf7db7b. --- ci/check_symbols.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/check_symbols.sh b/ci/check_symbols.sh index 1d73a082b..47d8295c2 100755 --- a/ci/check_symbols.sh +++ b/ci/check_symbols.sh @@ -18,7 +18,8 @@ See https://cmake.org/cmake/help/latest/prop_tgt/LANG_VISIBILITY_PRESET.html and echo "" echo "${err_msg}" - exit 1 + # TODO: Put this back once we decide what to check. + #exit 1 } WHEEL_EXPORT_DIR="$(mktemp -d)" From 02212f1a453b5bf793d43a052fc1a565849728cf Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 23 Nov 2024 02:26:57 +0000 Subject: [PATCH 093/120] Make sure symbols are not exported (required on both compile and link lines). --- rapids_logger/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index c8f98d8d1..769161286 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -172,6 +172,11 @@ function(rapids_make_logger logger_namespace) INTERFACE_POSITION_INDEPENDENT_CODE ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) + target_link_options(${impl_target} INTERFACE + "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") + target_compile_options( + ${impl_target} + INTERFACE "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") set(_install_export) if(_RAPIDS_EXPORT_SET) From 4e7eba78ab86391a8d1eabfc362bd579f0677654 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 23 Nov 2024 02:33:40 +0000 Subject: [PATCH 094/120] Put back symbol check, adapted for new functions --- ci/check_symbols.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/check_symbols.sh b/ci/check_symbols.sh index 47d8295c2..09d9a62e0 100755 --- a/ci/check_symbols.sh +++ b/ci/check_symbols.sh @@ -18,8 +18,7 @@ See https://cmake.org/cmake/help/latest/prop_tgt/LANG_VISIBILITY_PRESET.html and echo "" echo "${err_msg}" - # TODO: Put this back once we decide what to check. - #exit 1 + exit 1 } WHEEL_EXPORT_DIR="$(mktemp -d)" @@ -72,7 +71,8 @@ for dso_file in ${dso_files}; do # echo "checking for 'spdlog::' symbols..." if grep -E 'spdlog\:\:' < "${symbol_file}" \ - | grep -v 'std\:\:_Destroy_aux' + | grep -v 'std\:\:_Destroy_aux' \ + | grep -v 'rmm::.*spdlog' then raise-symbols-found-error 'spdlog::' fi From 2fcfc7090a54b79c9747b0004e5015b342f4c631 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Sat, 23 Nov 2024 09:16:26 +0000 Subject: [PATCH 095/120] Remove unnecessary link option --- rapids_logger/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index 769161286..eca71751e 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -172,8 +172,6 @@ function(rapids_make_logger logger_namespace) INTERFACE_POSITION_INDEPENDENT_CODE ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) - target_link_options(${impl_target} INTERFACE - "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") target_compile_options( ${impl_target} INTERFACE "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") From 49368cfc40da14317536ca66612f7f1d8f263123 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 25 Nov 2024 16:09:12 +0000 Subject: [PATCH 096/120] Add notes --- rapids_logger/CMakeLists.txt | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index eca71751e..d58585f5a 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -166,14 +166,31 @@ function(rapids_make_logger logger_namespace) $) target_link_libraries(${impl_target} INTERFACE ${_RAPIDS_LOGGER_TARGET} spdlog::spdlog_header_only) - set_target_properties( - ${impl_target} - PROPERTIES POSITION_INDEPENDENT_CODE ON - INTERFACE_POSITION_INDEPENDENT_CODE ON - CXX_VISIBILITY_PRESET hidden - VISIBILITY_INLINES_HIDDEN ON) + set_target_properties(${impl_target} PROPERTIES POSITION_INDEPENDENT_CODE ON + INTERFACE_POSITION_INDEPENDENT_CODE ON) + # cmake-format: off + # This is what I want to do, but the scope isn't large enough to propagate to targets linking to + # impl_target + # set_source_files_properties( + # $ + # TARGET ${impl_target} "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") + # set_source_files_properties( + # $ + # TARGET ${impl_target} "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") + # The below works, but breaks any consumer linking to the impl target that + # does not have proper visibility markup set because the visibility flags are + # set on that target too. I thought linking to this target via LINK_ONLY + # could work to preserve these flags for these files without propagating to + # consumers, but in practice I think LINK_ONLY also drops INTERFACE_SOURCES + # so we lose the main thing that we want to propagate. In the worst case I + # can require creating an intermediate OBJECT target that links to the impl + # target privately and then linking to that target to avoid undesirable + # propagation of the flags. + # cmake-format: on target_compile_options( ${impl_target} + # What I want is "PRIVATE" in the sense of "apply only to the files specified in these + # INTERFACE_SOURCES", not "PRIVATE" in the sense of "apply only to this target's SOURCES". INTERFACE "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") set(_install_export) From 46786c62fafcd11d381e7b16e8a32a2ac3bca04f Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 25 Nov 2024 17:38:37 +0000 Subject: [PATCH 097/120] Full PImpl for the logger --- rapids_logger/logger.hpp.in | 10 ++- rapids_logger/logger_impl.hpp.in | 124 +++++++++++++++++-------------- 2 files changed, 77 insertions(+), 57 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 49f5046f2..7af36681a 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -57,12 +57,17 @@ enum class level_enum : int32_t { n_levels }; +namespace detail { +// Forward declare the logger implementation class. +class logger_impl; +} + class sink { public: sink(spdlog::sink_ptr); private: spdlog::sink_ptr impl; - friend class logger; + friend class detail::logger_impl; }; /** @@ -300,8 +305,7 @@ class logger { static constexpr bool supports_logging() { return true; } private: - std::unique_ptr impl; ///< The spdlog logger - void init_logger(); + std::unique_ptr impl; ///< The logger implementation }; diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index c6e6591a8..48b1f01f5 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -55,53 +55,56 @@ level_enum from_spdlog_level(spdlog::level::level_enum lvl) return static_cast(static_cast(lvl)); } -} // namespace detail - - -// Sink methods -sink::sink(spdlog::sink_ptr sink) : impl{sink} {} +// Define a logger_impl class with all of the methods that the logger exposes. All the implementations should be trivial pass-throughs to the owned instance of the spdlog::logger class. The only exception is that all of the log level inputs should be our log level and they should be converted via to_spdlog_level, and all returned log levels should be converted via from_spdlog_level. +class logger_impl { +public: + logger_impl(std::string name, std::string filename) + : underlying{std::make_unique( + name, + std::make_shared(filename, true // truncate file + ))} + { + init_logger(); + } -// Logger methods -// TODO: This constructor and the one below introduce some undesirable -// vtable/typeinfo public symbols for basic_file_sink and ostream_sink. I'm not -// sure how to avoid this since they come from std::shared_ptr having inline -// methods that require injection into the global symbol table for -// disambiguation across TUs. I'm also not sure that we entirely need to -// support this kind of constructor, so we might just want to remove it. At -// minimum we will always have to expose the -// std::shared_ptr add_sink/remove_sink functions, but -// those don't introduce any vtable or tbypeinfo entries (presumably because -// the class doesn't actually implement any virtual functions). -logger::logger(std::string name, std::string filename) - : impl{std::make_unique( - name, - std::make_shared(filename, true // truncate file - ))} -{ - init_logger(); -} + logger_impl(std::string name, std::ostream& stream) + : underlying{std::make_unique( + name, + std::make_shared(stream))} + { + init_logger(); + } -logger::logger(std::string name, std::ostream& stream) - : impl{std::make_unique( - name, - std::make_shared(stream))} -{ + logger_impl(std::string name, std::vector> sinks) + { + std::vector spdlog_sinks; + spdlog_sinks.reserve(sinks.size()); + for (auto const& s : sinks) { + spdlog_sinks.emplace_back(s->impl); + } + underlying = std::make_unique(name, spdlog_sinks.begin(), spdlog_sinks.end()); init_logger(); -} - -logger::logger(std::string name, std::vector> sinks) -{ - std::vector spdlog_sinks; - spdlog_sinks.reserve(sinks.size()); - for (auto const& s : sinks) { - spdlog_sinks.emplace_back(s->impl); } - impl = std::make_unique(name, spdlog_sinks.begin(), spdlog_sinks.end()); - init_logger(); -} -void logger::init_logger() { - impl->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); + void log(level_enum lvl, std::string const& message) { underlying->log(to_spdlog_level(lvl), message); } + void set_level(level_enum log_level) { underlying->set_level(to_spdlog_level(log_level)); } + void flush() { underlying->flush(); } + void flush_on(level_enum log_level) { underlying->flush_on(to_spdlog_level(log_level)); } + level_enum flush_level() const { return from_spdlog_level(underlying->flush_level()); } + bool should_log(level_enum lvl) const { return underlying->should_log(to_spdlog_level(lvl)); } + void add_sink(spdlog::sink_ptr sink) { underlying->sinks().push_back(sink); } + void remove_sink(spdlog::sink_ptr sink) { + auto& sinks = underlying->sinks(); + sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); + } + level_enum level() const { return from_spdlog_level(underlying->level()); } + void set_pattern(std::string pattern) { underlying->set_pattern(pattern); } + +private: + std::unique_ptr underlying; ///< The spdlog logger + /// + void init_logger() { + underlying->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { set_level(detail::string_to_level(env_logging_level)); @@ -111,24 +114,37 @@ void logger::init_logger() { flush_on(detail::string_to_level(env_flush_level)); } } +}; + +} // namespace detail + + +// Sink methods +sink::sink(spdlog::sink_ptr sink) : impl{sink} {} + +// Logger methods +logger::logger(std::string name, std::string filename) + : impl{std::make_unique(name, filename)} {} + +logger::logger(std::string name, std::ostream& stream) + : impl{std::make_unique(name, stream)} {} + +logger::logger(std::string name, std::vector> sinks) + : impl{std::make_unique(name, sinks)} {} logger::~logger() = default; logger::logger(logger&&) = default; logger& logger::operator=(logger&&) = default; -void logger::log(level_enum lvl, std::string const& message) { impl->log(detail::to_spdlog_level(lvl), message); } - -void logger::set_level(level_enum log_level) { impl->set_level(detail::to_spdlog_level(log_level)); } +void logger::log(level_enum lvl, std::string const& message) { impl->log(lvl, message); } +void logger::set_level(level_enum log_level) { impl->set_level(log_level); } void logger::flush() { impl->flush(); } -void logger::flush_on(level_enum log_level) { impl->flush_on(detail::to_spdlog_level(log_level)); } -level_enum logger::flush_level() const { return detail::from_spdlog_level(impl->flush_level()); } -bool logger::should_log(level_enum lvl) const { return impl->should_log(detail::to_spdlog_level(lvl)); } -void logger::add_sink(spdlog::sink_ptr sink) { impl->sinks().push_back(sink); } -void logger::remove_sink(spdlog::sink_ptr sink) { - auto& sinks = impl->sinks(); - sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); -} -level_enum logger::level() const { return detail::from_spdlog_level(impl->level()); } +void logger::flush_on(level_enum log_level) { impl->flush_on(log_level); } +level_enum logger::flush_level() const { return impl->flush_level(); } +bool logger::should_log(level_enum lvl) const { return impl->should_log(lvl); } +void logger::add_sink(spdlog::sink_ptr sink) { impl->add_sink(sink); } +void logger::remove_sink(spdlog::sink_ptr sink) { impl->remove_sink(sink); } +level_enum logger::level() const { return impl->level(); } void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } } // namespace @_RAPIDS_LOGGER_NAMESPACE@ From 8f6d03c775346b1045544c564d36904ec72bb77c Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 25 Nov 2024 17:38:58 +0000 Subject: [PATCH 098/120] Remove now superfluous function supports_logging --- rapids_logger/logger.hpp.in | 7 ------- 1 file changed, 7 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 7af36681a..e8cd3ff61 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -297,13 +297,6 @@ class logger { */ void set_pattern(std::string pattern); - /** - * @brief Check if the logger supports logging. - * - * @return true if the logger supports logging, false otherwise - */ - static constexpr bool supports_logging() { return true; } - private: std::unique_ptr impl; ///< The logger implementation }; From f88e65a4fc8c22ac2217fbd826fdf9d3de13f64b Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Mon, 25 Nov 2024 17:41:44 +0000 Subject: [PATCH 099/120] Hide more in anonymous namespace --- rapids_logger/logger_impl.hpp.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 48b1f01f5..1eeb18202 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -30,6 +30,7 @@ namespace __attribute__((visibility("hidden"))) @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { +namespace { level_enum string_to_level(std::string_view const env_lvl_str) { @@ -54,6 +55,7 @@ level_enum from_spdlog_level(spdlog::level::level_enum lvl) { return static_cast(static_cast(lvl)); } +} // Define a logger_impl class with all of the methods that the logger exposes. All the implementations should be trivial pass-throughs to the owned instance of the spdlog::logger class. The only exception is that all of the log level inputs should be our log level and they should be converted via to_spdlog_level, and all returned log levels should be converted via from_spdlog_level. class logger_impl { @@ -102,7 +104,7 @@ public: private: std::unique_ptr underlying; ///< The spdlog logger - /// + void init_logger() { underlying->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); From 82443bdcab59d71a31f2637ff99f0408159e79d4 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 00:44:06 +0000 Subject: [PATCH 100/120] Create a sink_impl --- rapids_logger/logger.hpp.in | 37 +++++++++----------------------- rapids_logger/logger_impl.hpp.in | 23 ++++++++++---------- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index e8cd3ff61..44f324c9e 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -21,15 +21,6 @@ #include #include -// Forward declare spdlog types that are part of our public API. -namespace spdlog { -class logger; -namespace sinks { -class sink; -} // namespace sinks -using sink_ptr = std::shared_ptr; -} // namespace spdlog - namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { // These values must be kept in sync with spdlog! @@ -60,16 +51,22 @@ enum class level_enum : int32_t { namespace detail { // Forward declare the logger implementation class. class logger_impl; +class sink_impl; } +// Forward declare for the sink to make it a friend. +class logger; + class sink { - public: - sink(spdlog::sink_ptr); private: - spdlog::sink_ptr impl; + std::unique_ptr impl; + // TODO: Determine if we really need both friends. + friend class logger; friend class detail::logger_impl; }; +using sink_ptr = std::shared_ptr; + /** * @class logger * @brief A logger class that either uses the real implementation (via spdlog) or performs no-ops if @@ -222,7 +219,7 @@ class logger { * iterator-based API would require templating and thus exposing spdlog * types. */ - logger(std::string name, std::vector> sinks); + logger(std::string name, std::vector sinks); /** * @brief Destroy the logger object @@ -239,20 +236,6 @@ class logger { */ void log(level_enum lvl, std::string const& message); - /** - * @brief Add a sink to the logger. - * - * @param sink The sink to add - */ - void add_sink(spdlog::sink_ptr sink); - - /** - * @brief Remove a sink from the logger. - * - * @param sink The sink to remove - */ - void remove_sink(spdlog::sink_ptr sink); - /** * @brief Get the current log level. * diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 1eeb18202..a848683f6 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -57,6 +57,12 @@ level_enum from_spdlog_level(spdlog::level::level_enum lvl) } } +class sink_impl { +private: + std::shared_ptr underlying; + friend class detail::logger_impl; +}; + // Define a logger_impl class with all of the methods that the logger exposes. All the implementations should be trivial pass-throughs to the owned instance of the spdlog::logger class. The only exception is that all of the log level inputs should be our log level and they should be converted via to_spdlog_level, and all returned log levels should be converted via from_spdlog_level. class logger_impl { public: @@ -77,12 +83,12 @@ public: init_logger(); } - logger_impl(std::string name, std::vector> sinks) + logger_impl(std::string name, std::vector sinks) { std::vector spdlog_sinks; spdlog_sinks.reserve(sinks.size()); for (auto const& s : sinks) { - spdlog_sinks.emplace_back(s->impl); + spdlog_sinks.emplace_back(s->impl->underlying); } underlying = std::make_unique(name, spdlog_sinks.begin(), spdlog_sinks.end()); init_logger(); @@ -94,15 +100,11 @@ public: void flush_on(level_enum log_level) { underlying->flush_on(to_spdlog_level(log_level)); } level_enum flush_level() const { return from_spdlog_level(underlying->flush_level()); } bool should_log(level_enum lvl) const { return underlying->should_log(to_spdlog_level(lvl)); } - void add_sink(spdlog::sink_ptr sink) { underlying->sinks().push_back(sink); } - void remove_sink(spdlog::sink_ptr sink) { - auto& sinks = underlying->sinks(); - sinks.erase(std::remove(sinks.begin(), sinks.end(), sink), sinks.end()); - } level_enum level() const { return from_spdlog_level(underlying->level()); } void set_pattern(std::string pattern) { underlying->set_pattern(pattern); } private: + // TODO: Could this be stack-allocated? std::unique_ptr underlying; ///< The spdlog logger void init_logger() { @@ -122,7 +124,6 @@ private: // Sink methods -sink::sink(spdlog::sink_ptr sink) : impl{sink} {} // Logger methods logger::logger(std::string name, std::string filename) @@ -131,8 +132,8 @@ logger::logger(std::string name, std::string filename) logger::logger(std::string name, std::ostream& stream) : impl{std::make_unique(name, stream)} {} -logger::logger(std::string name, std::vector> sinks) - : impl{std::make_unique(name, sinks)} {} +logger::logger(std::string name, std::vector sinks) + : impl{std::make_unique(name, sinks)} {} logger::~logger() = default; logger::logger(logger&&) = default; @@ -144,8 +145,6 @@ void logger::flush() { impl->flush(); } void logger::flush_on(level_enum log_level) { impl->flush_on(log_level); } level_enum logger::flush_level() const { return impl->flush_level(); } bool logger::should_log(level_enum lvl) const { return impl->should_log(lvl); } -void logger::add_sink(spdlog::sink_ptr sink) { impl->add_sink(sink); } -void logger::remove_sink(spdlog::sink_ptr sink) { impl->remove_sink(sink); } level_enum logger::level() const { return impl->level(); } void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } From 483bdfc2ba25fa043c07799eacef52f2cbef59b4 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 00:46:49 +0000 Subject: [PATCH 101/120] Implement a sink_vector as the primary intermediary for sinks. --- rapids_logger/logger.hpp.in | 21 +++++++++- rapids_logger/logger_impl.hpp.in | 72 +++++++++++++++++++------------- 2 files changed, 62 insertions(+), 31 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 44f324c9e..dfd157413 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -78,8 +78,24 @@ class logger { logger(logger const&) = delete; ///< Not copy constructible logger& operator=(logger const&) = delete; ///< Not copy assignable - logger(logger&&); ///< @default_move_constructor - logger& operator=(logger&&); ///< @default_move_assignment{logger} + logger(logger&& other); ///< @default_move_constructor + logger& operator=(logger&& other); ///< @default_move_assignment{logger} + + class sink_vector { + public: + explicit sink_vector(logger& parent, std::vector sinks={}) : parent{parent}, sinks_{sinks} {} + void push_back(sink_ptr const& sink); + void push_back(sink_ptr&& sink); + void pop_back(); + private: + logger& parent; + std::vector sinks_; + // TODO: Can we do without this? The place it's used is in the assignment + // operator for the logger, but in that case I don't think implementing a + // corresponding assignment for sink_vector makes sense because we want the + // parent attribute to remain different but the sinks_ to be copied over. + friend class logger; + }; // TODO: When we migrate to C++20 we can use std::format and format strings // instead of the printf-style printing used here. @@ -282,6 +298,7 @@ class logger { private: std::unique_ptr impl; ///< The logger implementation + sink_vector sinks_; ///< The sinks for the logger }; diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index a848683f6..f9a99c4b0 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -58,39 +58,20 @@ level_enum from_spdlog_level(spdlog::level::level_enum lvl) } class sink_impl { +public: + sink_impl(std::shared_ptr sink) : underlying{sink} {} private: std::shared_ptr underlying; + // TODO: Reassess all friends, too much is leaking everywhere. friend class detail::logger_impl; + friend class logger::sink_vector; }; // Define a logger_impl class with all of the methods that the logger exposes. All the implementations should be trivial pass-throughs to the owned instance of the spdlog::logger class. The only exception is that all of the log level inputs should be our log level and they should be converted via to_spdlog_level, and all returned log levels should be converted via from_spdlog_level. class logger_impl { public: - logger_impl(std::string name, std::string filename) - : underlying{std::make_unique( - name, - std::make_shared(filename, true // truncate file - ))} - { - init_logger(); - } - - logger_impl(std::string name, std::ostream& stream) - : underlying{std::make_unique( - name, - std::make_shared(stream))} + logger_impl(std::string name) : underlying{std::make_unique(name)} { - init_logger(); - } - - logger_impl(std::string name, std::vector sinks) - { - std::vector spdlog_sinks; - spdlog_sinks.reserve(sinks.size()); - for (auto const& s : sinks) { - spdlog_sinks.emplace_back(s->impl->underlying); - } - underlying = std::make_unique(name, spdlog_sinks.begin(), spdlog_sinks.end()); init_logger(); } @@ -102,6 +83,8 @@ public: bool should_log(level_enum lvl) const { return underlying->should_log(to_spdlog_level(lvl)); } level_enum level() const { return from_spdlog_level(underlying->level()); } void set_pattern(std::string pattern) { underlying->set_pattern(pattern); } + const std::vector &sinks() const { return underlying->sinks(); } + std::vector &sinks() { return underlying->sinks(); } private: // TODO: Could this be stack-allocated? @@ -122,22 +105,53 @@ private: } // namespace detail +// Sink vector functions +void logger::sink_vector::push_back(sink_ptr const& sink) { + sinks_.push_back(sink); + parent.impl->sinks().push_back(sink->impl->underlying); +} +void logger::sink_vector::push_back(sink_ptr&& sink) { + sinks_.push_back(sink); + parent.impl->sinks().push_back(sink->impl->underlying); +} +void logger::sink_vector::pop_back() { + sinks_.pop_back(); + parent.impl->sinks().pop_back(); +} // Sink methods // Logger methods logger::logger(std::string name, std::string filename) - : impl{std::make_unique(name, filename)} {} + : impl{std::make_unique(name)}, sinks_{*this} { + auto s = std::make_shared(); + auto spdlog_sink = std::make_shared(filename, true); + s->impl = std::make_unique(spdlog_sink);; + sinks_.push_back(s); +} logger::logger(std::string name, std::ostream& stream) - : impl{std::make_unique(name, stream)} {} + : impl{std::make_unique(name)}, sinks_{*this} { + auto s = std::make_shared(); + auto spdlog_sink = std::make_shared(stream); + s->impl = std::make_unique(spdlog_sink);; + sinks_.push_back(s); +} logger::logger(std::string name, std::vector sinks) - : impl{std::make_unique(name, sinks)} {} + : impl{std::make_unique(name)}, sinks_{*this} { + for (auto const& s : sinks) { + sinks_.push_back(s); + } +} logger::~logger() = default; -logger::logger(logger&&) = default; -logger& logger::operator=(logger&&) = default; +logger::logger(logger&& other) = default; +logger& logger::operator=(logger&& other) { + impl = std::move(impl); + sinks_.sinks_ = other.sinks_.sinks_; + return *this; +} void logger::log(level_enum lvl, std::string const& message) { impl->log(lvl, message); } void logger::set_level(level_enum log_level) { impl->set_level(log_level); } From 316b1f9543e6a9e8239654aefe2c6f4969b4f288 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 00:49:55 +0000 Subject: [PATCH 102/120] Comment --- rapids_logger/logger.hpp.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index dfd157413..9344f44ab 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -81,6 +81,11 @@ class logger { logger(logger&& other); ///< @default_move_constructor logger& operator=(logger&& other); ///< @default_move_assignment{logger} + /** + * @brief A class to manage a vector of sinks. + * + * This class is used internally by the logger class to manage its sinks. It handles synchronization of the sinks with the sinks in the underlying spdlog logger such that all vector-like operations performed on this class are reflected in the underlying spdlog logger's set of sinks. + */ class sink_vector { public: explicit sink_vector(logger& parent, std::vector sinks={}) : parent{parent}, sinks_{sinks} {} From a6bc3a797e0e34f9dde01bd75ad2f3817e4697fb Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 00:54:09 +0000 Subject: [PATCH 103/120] Convert the underlying logger to a stack-allocated one. --- rapids_logger/logger_impl.hpp.in | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index f9a99c4b0..96eb36795 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -70,28 +70,27 @@ private: // Define a logger_impl class with all of the methods that the logger exposes. All the implementations should be trivial pass-throughs to the owned instance of the spdlog::logger class. The only exception is that all of the log level inputs should be our log level and they should be converted via to_spdlog_level, and all returned log levels should be converted via from_spdlog_level. class logger_impl { public: - logger_impl(std::string name) : underlying{std::make_unique(name)} + logger_impl(std::string name) : underlying{spdlog::logger{name}} { init_logger(); } - void log(level_enum lvl, std::string const& message) { underlying->log(to_spdlog_level(lvl), message); } - void set_level(level_enum log_level) { underlying->set_level(to_spdlog_level(log_level)); } - void flush() { underlying->flush(); } - void flush_on(level_enum log_level) { underlying->flush_on(to_spdlog_level(log_level)); } - level_enum flush_level() const { return from_spdlog_level(underlying->flush_level()); } - bool should_log(level_enum lvl) const { return underlying->should_log(to_spdlog_level(lvl)); } - level_enum level() const { return from_spdlog_level(underlying->level()); } - void set_pattern(std::string pattern) { underlying->set_pattern(pattern); } - const std::vector &sinks() const { return underlying->sinks(); } - std::vector &sinks() { return underlying->sinks(); } + void log(level_enum lvl, std::string const& message) { underlying.log(to_spdlog_level(lvl), message); } + void set_level(level_enum log_level) { underlying.set_level(to_spdlog_level(log_level)); } + void flush() { underlying.flush(); } + void flush_on(level_enum log_level) { underlying.flush_on(to_spdlog_level(log_level)); } + level_enum flush_level() const { return from_spdlog_level(underlying.flush_level()); } + bool should_log(level_enum lvl) const { return underlying.should_log(to_spdlog_level(lvl)); } + level_enum level() const { return from_spdlog_level(underlying.level()); } + void set_pattern(std::string pattern) { underlying.set_pattern(pattern); } + const std::vector &sinks() const { return underlying.sinks(); } + std::vector &sinks() { return underlying.sinks(); } private: - // TODO: Could this be stack-allocated? - std::unique_ptr underlying; ///< The spdlog logger + spdlog::logger underlying; ///< The spdlog logger void init_logger() { - underlying->set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); + underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); if (env_logging_level != nullptr) { set_level(detail::string_to_level(env_logging_level)); From 3cf107432f3aa7813efbf4ed8bfb467ef25abcc9 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 00:56:48 +0000 Subject: [PATCH 104/120] Remove one unnecessary friend --- rapids_logger/logger_impl.hpp.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 96eb36795..ad8d27c6e 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -62,8 +62,7 @@ public: sink_impl(std::shared_ptr sink) : underlying{sink} {} private: std::shared_ptr underlying; - // TODO: Reassess all friends, too much is leaking everywhere. - friend class detail::logger_impl; + // The sink_vector needs to be able to pass the underlying sink to the spdlog logger. friend class logger::sink_vector; }; From 155c93483e478fc110480953914dcb1155059f6e Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 01:06:55 +0000 Subject: [PATCH 105/120] Remove one more friend --- rapids_logger/logger.hpp.in | 16 ++++++++++------ rapids_logger/logger_impl.hpp.in | 9 ++++++++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 9344f44ab..5140efe8d 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -62,7 +62,6 @@ class sink { std::unique_ptr impl; // TODO: Determine if we really need both friends. friend class logger; - friend class detail::logger_impl; }; using sink_ptr = std::shared_ptr; @@ -88,18 +87,23 @@ class logger { */ class sink_vector { public: + using Iterator = std::vector::iterator; + using ConstIterator = std::vector::const_iterator; + explicit sink_vector(logger& parent, std::vector sinks={}) : parent{parent}, sinks_{sinks} {} void push_back(sink_ptr const& sink); void push_back(sink_ptr&& sink); void pop_back(); + void clear(); + Iterator begin() { return sinks_.begin(); } + Iterator end() { return sinks_.end(); } + ConstIterator begin() const { return sinks_.begin(); } + ConstIterator end() const { return sinks_.end(); } + ConstIterator cbegin() const { return sinks_.cbegin(); } + ConstIterator cend() const { return sinks_.cend(); } private: logger& parent; std::vector sinks_; - // TODO: Can we do without this? The place it's used is in the assignment - // operator for the logger, but in that case I don't think implementing a - // corresponding assignment for sink_vector makes sense because we want the - // parent attribute to remain different but the sinks_ to be copied over. - friend class logger; }; // TODO: When we migrate to C++20 we can use std::format and format strings diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index ad8d27c6e..a407ab447 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -116,6 +116,10 @@ void logger::sink_vector::pop_back() { sinks_.pop_back(); parent.impl->sinks().pop_back(); } +void logger::sink_vector::clear() { + sinks_.clear(); + parent.impl->sinks().clear(); +} // Sink methods @@ -147,7 +151,10 @@ logger::~logger() = default; logger::logger(logger&& other) = default; logger& logger::operator=(logger&& other) { impl = std::move(impl); - sinks_.sinks_ = other.sinks_.sinks_; + sinks_.clear(); + for (auto const& s : other.sinks_) { + sinks_.push_back(s); + } return *this; } From b175d681f841b6e8a3153edaddeb1acb0eba12d1 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 01:23:27 +0000 Subject: [PATCH 106/120] Make things consistent so that the sink_vector is the only friend that intermediates between the implementation details. --- rapids_logger/logger.hpp.in | 27 ++++++++++++++++++--------- rapids_logger/logger_impl.hpp.in | 15 +++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 5140efe8d..1bf58416e 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -55,15 +55,7 @@ class sink_impl; } // Forward declare for the sink to make it a friend. -class logger; - -class sink { - private: - std::unique_ptr impl; - // TODO: Determine if we really need both friends. - friend class logger; -}; - +class sink; using sink_ptr = std::shared_ptr; /** @@ -310,6 +302,23 @@ class logger { sink_vector sinks_; ///< The sinks for the logger }; +class sink { + protected: + explicit sink(std::unique_ptr impl) : impl{std::move(impl)} {} + std::unique_ptr impl; + friend class logger::sink_vector; +}; + +class basic_file_sink_mt : public sink { + public: + basic_file_sink_mt(std::string const& filename, bool truncate = false); +}; + +class ostream_sink_mt : public sink { + public: + ostream_sink_mt(std::ostream& stream, bool force_flush = false); +}; + /** * @brief Returns the default log filename for the global logger. diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index a407ab447..e95fc9253 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -122,22 +122,21 @@ void logger::sink_vector::clear() { } // Sink methods +basic_file_sink_mt::basic_file_sink_mt(std::string const& filename, bool truncate) + : sink{std::make_unique(std::make_shared(filename, truncate))} {} + +ostream_sink_mt::ostream_sink_mt(std::ostream& stream, bool force_flush) + : sink{std::make_unique(std::make_shared(stream, force_flush))} {} // Logger methods logger::logger(std::string name, std::string filename) : impl{std::make_unique(name)}, sinks_{*this} { - auto s = std::make_shared(); - auto spdlog_sink = std::make_shared(filename, true); - s->impl = std::make_unique(spdlog_sink);; - sinks_.push_back(s); + sinks_.push_back(std::make_shared(filename, true)); } logger::logger(std::string name, std::ostream& stream) : impl{std::make_unique(name)}, sinks_{*this} { - auto s = std::make_shared(); - auto spdlog_sink = std::make_shared(stream); - s->impl = std::make_unique(spdlog_sink);; - sinks_.push_back(s); + sinks_.push_back(std::make_shared(stream)); } logger::logger(std::string name, std::vector sinks) From 9619e51c538219deda6f5955aca10a9f0e058971 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 01:29:43 +0000 Subject: [PATCH 107/120] Add documentation --- rapids_logger/logger.hpp.in | 89 ++++++++++++++++++++++++++++++-- rapids_logger/logger_impl.hpp.in | 30 ++++++++++- 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 1bf58416e..174583253 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -79,23 +79,85 @@ class logger { */ class sink_vector { public: - using Iterator = std::vector::iterator; - using ConstIterator = std::vector::const_iterator; - + using Iterator = std::vector::iterator; ///< The iterator type + using ConstIterator = std::vector::const_iterator; ///< The const iterator type + + /** + * @brief Construct a new sink_vector object + * + * @param parent The logger whose sinks are being managed + * @param sinks The sinks to manage + */ explicit sink_vector(logger& parent, std::vector sinks={}) : parent{parent}, sinks_{sinks} {} + + /** + * @brief Add a sink to the vector. + * + * @param sink The sink to add + */ void push_back(sink_ptr const& sink); + + /** + * @brief Add a sink to the vector. + * + * @param sink The sink to add + */ void push_back(sink_ptr&& sink); + + /** + * @brief Remove the last sink from the vector. + */ void pop_back(); + + /** + * @brief Remove all sinks from the vector. + */ void clear(); + + /** + * @brief Get an iterator to the beginning of the vector. + * + * @return Iterator The iterator + */ Iterator begin() { return sinks_.begin(); } + + /** + * @brief Get an iterator to the end of the vector. + * + * @return Iterator The iterator + */ Iterator end() { return sinks_.end(); } + + /** + * @brief Get a const iterator to the beginning of the vector. + * + * @return ConstIterator The const iterator + */ ConstIterator begin() const { return sinks_.begin(); } + + /** + * @brief Get a const iterator to the end of the vector. + * + * @return ConstIterator The const iterator + */ ConstIterator end() const { return sinks_.end(); } + + /** + * @brief Get a const iterator to the beginning of the vector. + * + * @return ConstIterator The const iterator + */ ConstIterator cbegin() const { return sinks_.cbegin(); } + + /** + * @brief Get a const iterator to the end of the vector. + * + * @return ConstIterator The const iterator + */ ConstIterator cend() const { return sinks_.cend(); } private: - logger& parent; - std::vector sinks_; + logger& parent; ///< The logger this vector belongs to + std::vector sinks_; ///< The sinks }; // TODO: When we migrate to C++20 we can use std::format and format strings @@ -302,18 +364,35 @@ class logger { sink_vector sinks_; ///< The sinks for the logger }; +/** + * @brief A sink for the logger. + * + * These sinks are wrappers around the spdlog sinks that allow us to keep the + * spdlog types private and avoid exposing them in the public API. + */ class sink { protected: explicit sink(std::unique_ptr impl) : impl{std::move(impl)} {} std::unique_ptr impl; + // The sink vector needs to be able to pass the underlying sink to the spdlog logger. friend class logger::sink_vector; }; +/** + * @brief A sink that writes to a file. + * + * See spdlog::sinks::basic_file_sink_mt for more information. + */ class basic_file_sink_mt : public sink { public: basic_file_sink_mt(std::string const& filename, bool truncate = false); }; +/** + * @brief A sink that writes to an ostream. + * + * See spdlog::sinks::ostream_sink_mt for more information. + */ class ostream_sink_mt : public sink { public: ostream_sink_mt(std::ostream& stream, bool force_flush = false); diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index e95fc9253..6a9fc7706 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -32,6 +32,13 @@ namespace __attribute__((visibility("hidden"))) @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { namespace { +/** + * @brief Convert a string to a log level. + * + * This function is used to process env-var specifications of log levels. + * @param env_lvl_str The string to convert. + * @return The log level. + */ level_enum string_to_level(std::string_view const env_lvl_str) { if (env_lvl_str == "TRACE") return level_enum::trace; @@ -46,17 +53,34 @@ level_enum string_to_level(std::string_view const env_lvl_str) throw std::invalid_argument(os.str()); } +/** + * @brief Convert a log level to an spdlog log level. + * + * @param lvl The log level to convert. + * @return The spdlog log level. + */ spdlog::level::level_enum to_spdlog_level(level_enum lvl) { return static_cast(static_cast(lvl)); } +/** + * @brief Convert an spdlog log level to a log level. + * + * @param lvl The spdlog log level to convert. + * @return The log level. + */ level_enum from_spdlog_level(spdlog::level::level_enum lvl) { return static_cast(static_cast(lvl)); } } +/** + * @brief The sink_impl class is a wrapper around an spdlog sink. + * + * This class is the impl part of the PImpl for the sink. + */ class sink_impl { public: sink_impl(std::shared_ptr sink) : underlying{sink} {} @@ -66,7 +90,11 @@ private: friend class logger::sink_vector; }; -// Define a logger_impl class with all of the methods that the logger exposes. All the implementations should be trivial pass-throughs to the owned instance of the spdlog::logger class. The only exception is that all of the log level inputs should be our log level and they should be converted via to_spdlog_level, and all returned log levels should be converted via from_spdlog_level. +/** + * @brief The logger_impl class is a wrapper around an spdlog logger. + * + * This class is the impl part of the PImpl for the logger. + */ class logger_impl { public: logger_impl(std::string name) : underlying{spdlog::logger{name}} From fa3b95e59644b3c96199d9f05d38550492987b1f Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 01:38:01 +0000 Subject: [PATCH 108/120] Bugfix --- rapids_logger/logger_impl.hpp.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 6a9fc7706..5350ffded 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -177,7 +177,7 @@ logger::logger(std::string name, std::vector sinks) logger::~logger() = default; logger::logger(logger&& other) = default; logger& logger::operator=(logger&& other) { - impl = std::move(impl); + impl = std::move(other.impl); sinks_.clear(); for (auto const& s : other.sinks_) { sinks_.push_back(s); From e1fc36a92822ef736ba96ea7caaa216c8afe2e97 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 01:41:23 +0000 Subject: [PATCH 109/120] Inline init_logger --- rapids_logger/logger_impl.hpp.in | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 5350ffded..335069263 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -96,10 +96,14 @@ private: * This class is the impl part of the PImpl for the logger. */ class logger_impl { -public: - logger_impl(std::string name) : underlying{spdlog::logger{name}} - { - init_logger(); + public: + logger_impl(std::string name) : underlying{spdlog::logger{name}} { + underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); + auto const env_logging_level = + std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); + if (env_logging_level != nullptr) { set_level(detail::string_to_level(env_logging_level)); } + auto const env_flush_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_FLUSH_LEVEL"); + if (env_flush_level != nullptr) { flush_on(detail::string_to_level(env_flush_level)); } } void log(level_enum lvl, std::string const& message) { underlying.log(to_spdlog_level(lvl), message); } @@ -115,18 +119,6 @@ public: private: spdlog::logger underlying; ///< The spdlog logger - - void init_logger() { - underlying.set_pattern("[%6t][%H:%M:%S:%f][%-6l] %v"); - auto const env_logging_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_LOGGING_LEVEL"); - if (env_logging_level != nullptr) { - set_level(detail::string_to_level(env_logging_level)); - } - auto const env_flush_level = std::getenv("@_RAPIDS_LOGGER_MACRO_PREFIX@_DEFAULT_FLUSH_LEVEL"); - if (env_flush_level != nullptr) { - flush_on(detail::string_to_level(env_flush_level)); - } - } }; } // namespace detail From c5f56fd3ac3a2bd090de0f830b9959f1ff608698 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 01:42:51 +0000 Subject: [PATCH 110/120] Fix some comments --- rapids_logger/logger.hpp.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 174583253..97b5e6286 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -49,12 +49,12 @@ enum class level_enum : int32_t { }; namespace detail { -// Forward declare the logger implementation class. +// Forward declare the implementation classes. class logger_impl; class sink_impl; } -// Forward declare for the sink to make it a friend. +// Forward declare for the sink for the logger to use. class sink; using sink_ptr = std::shared_ptr; From 15697c7fbd01519e321665a979191e96045c2c74 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 16:12:24 +0000 Subject: [PATCH 111/120] Fixes for tracking_mr test --- rapids_logger/logger.hpp.in | 18 +++++++++++++++++- rapids_logger/logger_impl.hpp.in | 4 ++++ tests/mr/device/tracking_mr_tests.cpp | 6 +++--- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 97b5e6286..5c1f6cad6 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -315,6 +315,20 @@ class logger { */ void log(level_enum lvl, std::string const& message); + /** + * @brief Get the sinks for the logger. + * + * @return The sinks + */ + const std::vector &sinks() const; + + /** + * @brief Get the sinks for the logger. + * + * @return The sinks + */ + std::vector &sinks(); + /** * @brief Get the current log level. * @@ -371,8 +385,10 @@ class logger { * spdlog types private and avoid exposing them in the public API. */ class sink { + public: + ~sink(); protected: - explicit sink(std::unique_ptr impl) : impl{std::move(impl)} {} + explicit sink(std::unique_ptr impl); std::unique_ptr impl; // The sink vector needs to be able to pass the underlying sink to the spdlog logger. friend class logger::sink_vector; diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 335069263..a948a3871 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -142,6 +142,10 @@ void logger::sink_vector::clear() { } // Sink methods +sink::sink(std::unique_ptr impl) : impl{std::move(impl)} {} + +sink::~sink() = default; + basic_file_sink_mt::basic_file_sink_mt(std::string const& filename, bool truncate) : sink{std::make_unique(std::make_shared(filename, truncate))} {} diff --git a/tests/mr/device/tracking_mr_tests.cpp b/tests/mr/device/tracking_mr_tests.cpp index aca0fe8c8..4dc9f31f1 100644 --- a/tests/mr/device/tracking_mr_tests.cpp +++ b/tests/mr/device/tracking_mr_tests.cpp @@ -203,9 +203,9 @@ TEST(TrackingTest, DeallocWrongBytes) TEST(TrackingTest, LogOutstandingAllocations) { std::ostringstream oss; - auto oss_sink = std::make_shared(oss); + auto oss_sink = std::make_shared(oss); auto old_level = rmm::default_logger().level(); - rmm::default_logger().add_sink(oss_sink); + rmm::default_logger().sinks().push_back(oss_sink); tracking_adaptor mr{rmm::mr::get_current_device_resource_ref()}; std::vector allocations; @@ -225,7 +225,7 @@ TEST(TrackingTest, LogOutstandingAllocations) } rmm::default_logger().set_level(old_level); - rmm::default_logger().remove_sink(oss_sink); + rmm::default_logger().sinks().pop_back(); } } // namespace From d12bb93caacda5e86fff04b96d8562b5a8969b95 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 16:18:02 +0000 Subject: [PATCH 112/120] Fix sinks definition --- rapids_logger/logger.hpp.in | 4 ++-- rapids_logger/logger_impl.hpp.in | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 5c1f6cad6..5e4a11c23 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -320,14 +320,14 @@ class logger { * * @return The sinks */ - const std::vector &sinks() const; + const sink_vector& sinks() const; /** * @brief Get the sinks for the logger. * * @return The sinks */ - std::vector &sinks(); + sink_vector& sinks(); /** * @brief Get the current log level. diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index a948a3871..25826a58c 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -189,5 +189,7 @@ level_enum logger::flush_level() const { return impl->flush_level(); } bool logger::should_log(level_enum lvl) const { return impl->should_log(lvl); } level_enum logger::level() const { return impl->level(); } void logger::set_pattern(std::string pattern) { impl->set_pattern(pattern); } +const logger::sink_vector& logger::sinks() const { return sinks_; } +logger::sink_vector& logger::sinks() { return sinks_; } } // namespace @_RAPIDS_LOGGER_NAMESPACE@ From 2d84f2d64d87a9ea27d3df7ca1d6afb96969c103 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 16:19:41 +0000 Subject: [PATCH 113/120] Remove support for mixing in spdlog sinks and update tests accordingly. --- .../mr/device/logging_resource_adaptor.hpp | 25 +++---------------- tests/logger_tests.cpp | 5 ++-- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/include/rmm/mr/device/logging_resource_adaptor.hpp b/include/rmm/mr/device/logging_resource_adaptor.hpp index 716c4b49e..3e6e5babc 100644 --- a/include/rmm/mr/device/logging_resource_adaptor.hpp +++ b/include/rmm/mr/device/logging_resource_adaptor.hpp @@ -112,9 +112,8 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ - template logging_resource_adaptor(Upstream* upstream, - std::initializer_list sinks, + std::initializer_list sinks, bool auto_flush = false) : logging_resource_adaptor{to_device_async_resource_ref_checked(upstream), sinks, auto_flush} { @@ -178,9 +177,8 @@ class logging_resource_adaptor final : public device_memory_resource { * @param auto_flush If true, flushes the log for every (de)allocation. Warning, this will degrade * performance. */ - template logging_resource_adaptor(device_async_resource_ref upstream, - std::initializer_list sinks, + std::initializer_list sinks, bool auto_flush = false) : logging_resource_adaptor{make_logger(sinks), upstream, auto_flush} { @@ -241,24 +239,9 @@ class logging_resource_adaptor final : public device_memory_resource { return std::make_shared("RMM", filename); } - // TODO: See if there is a way to make this function only valid for our sink - // or spdlog's without leaking spdlog symbols. When logging isn't enabled our - // sink type is constructible from anything, so that sort of analysis won't - // help (and fixing that would require the same ideas as fixing this). - template - static auto make_logger(std::initializer_list sinks) + static auto make_logger(std::initializer_list sinks) { - // Support passing either - if constexpr (std::is_same_v) { - return std::make_shared("RMM", sinks); - } else { - std::vector> rmm_sinks; - rmm_sinks.reserve(sinks.size()); - for (const auto& s : sinks) { - rmm_sinks.push_back(std::make_shared(s)); - } - return std::make_shared("RMM", std::move(rmm_sinks)); - } + return std::make_shared("RMM", sinks); } logging_resource_adaptor(std::shared_ptr logger, diff --git a/tests/logger_tests.cpp b/tests/logger_tests.cpp index c42753fe8..619143294 100644 --- a/tests/logger_tests.cpp +++ b/tests/logger_tests.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -153,8 +152,8 @@ TEST(Adaptor, MultiSinkConstructor) std::string filename2{temp_dir.generate_path("test_multi_2.txt")}; rmm::mr::cuda_memory_resource upstream; - auto file_sink1 = std::make_shared(filename1, true); - auto file_sink2 = std::make_shared(filename2, true); + auto file_sink1 = std::make_shared(filename1, true); + auto file_sink2 = std::make_shared(filename2, true); rmm::mr::logging_resource_adaptor log_mr{&upstream, {file_sink1, file_sink2}}; From e7b2d92ac0686b72da837c0801bd05d935c3ece4 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 16:20:10 +0000 Subject: [PATCH 114/120] Remove lingering spdlog include --- tests/mr/device/tracking_mr_tests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/mr/device/tracking_mr_tests.cpp b/tests/mr/device/tracking_mr_tests.cpp index 4dc9f31f1..c40a9127d 100644 --- a/tests/mr/device/tracking_mr_tests.cpp +++ b/tests/mr/device/tracking_mr_tests.cpp @@ -23,7 +23,6 @@ #include #include -#include namespace rmm::test { namespace { From b6af231b5e76f3ab4581cb3739fd40d10440752b Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 16:22:23 +0000 Subject: [PATCH 115/120] Update symbol checking script, we should no longer leak any of these symbols at all. --- ci/check_symbols.sh | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/ci/check_symbols.sh b/ci/check_symbols.sh index 09d9a62e0..155e509da 100755 --- a/ci/check_symbols.sh +++ b/ci/check_symbols.sh @@ -47,33 +47,13 @@ for dso_file in ${dso_files}; do echo " * WEAK: $(grep --count -E ' WEAK ' < ${symbol_file})" echo " * LOCAL: $(grep --count -E ' LOCAL ' < ${symbol_file})" - # Explanation for '-v' uses here: - # - # * 'format_error' symbols are intentionally exported, that type of error - # can be thrown across library boundaries. See "Problems with C++ exceptions" - # at https://gcc.gnu.org/wiki/Visibility. echo "checking for 'fmt::' symbols..." - if grep -E 'fmt\:\:' < "${symbol_file}" \ - | grep -v 'format_error' - then + if grep -E 'fmt\:\:' < "${symbol_file}"; then raise-symbols-found-error 'fmt::' fi - # Explanation for '-v' uses here: - # - # * trivially-destructible objects sometimes get an entry in the symbol table - # for a specialization of `std::_Destroy_aux()` called to destroy them. - # There is one for `spdlog::details::log_msg_buffer like that: - # - # 'std::_Destroy_aux::__destroy' - # - # That should be safe to export. - # echo "checking for 'spdlog::' symbols..." - if grep -E 'spdlog\:\:' < "${symbol_file}" \ - | grep -v 'std\:\:_Destroy_aux' \ - | grep -v 'rmm::.*spdlog' - then + if grep -E 'spdlog\:\:' < "${symbol_file}"; then raise-symbols-found-error 'spdlog::' fi echo "No symbol visibility issues found" From 82f925aa28cb4a6c12a89c56021073064db10022 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 16:31:56 +0000 Subject: [PATCH 116/120] Remove visibility macro configurability from public header since we always want this set --- CMakeLists.txt | 3 +-- rapids_logger/CMakeLists.txt | 31 +------------------------------ rapids_logger/logger.hpp.in | 2 +- 3 files changed, 3 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cbf31851e..9f65d02c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,8 +74,7 @@ rapids_find_package( rapids_cpm_init() add_subdirectory(rapids_logger) -rapids_make_logger(rmm EXPORT_SET rmm-exports VISIBILITY_MACRO - "__attribute__((visibility(\"default\")))") +rapids_make_logger(rmm EXPORT_SET rmm-exports) include(cmake/thirdparty/get_cccl.cmake) include(cmake/thirdparty/get_nvtx.cmake) diff --git a/rapids_logger/CMakeLists.txt b/rapids_logger/CMakeLists.txt index d58585f5a..fd50276ca 100644 --- a/rapids_logger/CMakeLists.txt +++ b/rapids_logger/CMakeLists.txt @@ -47,7 +47,6 @@ Generate a logger implementation customized for the specified namespace. [LOGGER_TARGET ] [LOGGER_HEADER_DIR ] [LOGGER_MACRO_PREFIX ] - [VISIBILITY_MACRO ] ) This function produces an interface target named that, when linked to by other targets, provides them a header file that defines a logger interface for the specified namespace. The logger is generated from the provided template files and is configured to use the specified namespace and macro prefix. The generated logger is placed in the specified header directory. @@ -70,9 +69,6 @@ The logger implementation lives in a separate header file that is not included i ``LOGGER_MACRO_PREFIX`` The prefix to use for the logger macros. If not specified, the macro prefix is the uppercase version of the logger namespace. -``VISIBILITY_MACRO`` - The macro to use for visibility annotations. If not specified, no visibility annotations are added to the logger interface. - Result Targets ^^^^^^^^^^^^^^^^ is an interface target that provides the logger interface for the specified namespace. @@ -102,8 +98,7 @@ function(rapids_make_logger logger_namespace) list(APPEND CMAKE_MESSAGE_CONTEXT "rapids_make_logger") set(_rapids_options) - set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX - VISIBILITY_MACRO) + set(_rapids_one_value EXPORT_SET LOGGER_TARGET LOGGER_HEADER_DIR LOGGER_MACRO_PREFIX) set(_rapids_multi_value) cmake_parse_arguments(_RAPIDS "${_rapids_options}" "${_rapids_one_value}" "${_rapids_multi_value}" ${ARGN}) @@ -168,30 +163,6 @@ function(rapids_make_logger logger_namespace) spdlog::spdlog_header_only) set_target_properties(${impl_target} PROPERTIES POSITION_INDEPENDENT_CODE ON INTERFACE_POSITION_INDEPENDENT_CODE ON) - # cmake-format: off - # This is what I want to do, but the scope isn't large enough to propagate to targets linking to - # impl_target - # set_source_files_properties( - # $ - # TARGET ${impl_target} "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") - # set_source_files_properties( - # $ - # TARGET ${impl_target} "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") - # The below works, but breaks any consumer linking to the impl target that - # does not have proper visibility markup set because the visibility flags are - # set on that target too. I thought linking to this target via LINK_ONLY - # could work to preserve these flags for these files without propagating to - # consumers, but in practice I think LINK_ONLY also drops INTERFACE_SOURCES - # so we lose the main thing that we want to propagate. In the worst case I - # can require creating an intermediate OBJECT target that links to the impl - # target privately and then linking to that target to avoid undesirable - # propagation of the flags. - # cmake-format: on - target_compile_options( - ${impl_target} - # What I want is "PRIVATE" in the sense of "apply only to the files specified in these - # INTERFACE_SOURCES", not "PRIVATE" in the sense of "apply only to this target's SOURCES". - INTERFACE "$<$:-fvisibility=hidden;-fvisibility-inlines-hidden>") set(_install_export) if(_RAPIDS_EXPORT_SET) diff --git a/rapids_logger/logger.hpp.in b/rapids_logger/logger.hpp.in index 5e4a11c23..cd2bb2c79 100644 --- a/rapids_logger/logger.hpp.in +++ b/rapids_logger/logger.hpp.in @@ -21,7 +21,7 @@ #include #include -namespace @_RAPIDS_VISIBILITY_MACRO@ @_RAPIDS_LOGGER_NAMESPACE@ { +namespace __attribute__((visibility("default"))) @_RAPIDS_LOGGER_NAMESPACE@ { // These values must be kept in sync with spdlog! #define @_RAPIDS_LOGGER_MACRO_PREFIX@_LOG_LEVEL_TRACE 0 From 6dfc38a6d9d100ed526044ad99a1c17fc14b6e98 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 17:44:21 +0000 Subject: [PATCH 117/120] Try using macros --- rapids_logger/logger_impl.hpp.in | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 25826a58c..2fdbc0352 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -18,16 +18,18 @@ #include "../logger.hpp" -#include -#include -#include #include #include #include +#pragma GCC visibility push(hidden) + +#include +#include +#include -namespace __attribute__((visibility("hidden"))) @_RAPIDS_LOGGER_NAMESPACE@ { +namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { namespace { @@ -193,3 +195,4 @@ const logger::sink_vector& logger::sinks() const { return sinks_; } logger::sink_vector& logger::sinks() { return sinks_; } } // namespace @_RAPIDS_LOGGER_NAMESPACE@ +#pragma GCC visibility pop From cae6784704707482462fbbb094fb0a8bfd6f572d Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 18:38:51 +0000 Subject: [PATCH 118/120] Make sure that internally needed symbols are exported --- rapids_logger/logger_impl.hpp.in | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 2fdbc0352..7ebb31e90 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -18,10 +18,11 @@ #include "../logger.hpp" - -#include -#include -#include +// Include C headers for which we need symbols to be made public and don't want +// the below symbol hiding pattern to apply. +#include +#include +#include #pragma GCC visibility push(hidden) @@ -29,6 +30,10 @@ #include #include +#include +#include +#include + namespace @_RAPIDS_LOGGER_NAMESPACE@ { namespace detail { From 6bbc174fd75beca9deeae8b2b95ca982090b7529 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 19:03:41 +0000 Subject: [PATCH 119/120] Fix sink_ptr in docs --- python/rmm/docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/rmm/docs/conf.py b/python/rmm/docs/conf.py index 2aad3a82c..99242daa5 100644 --- a/python/rmm/docs/conf.py +++ b/python/rmm/docs/conf.py @@ -238,6 +238,8 @@ def on_missing_reference(app, env, node, contnode): "thrust", "spdlog", "stream_ref", + # logger names (we may eventually want to link out for those) + "sink_ptr", # libcu++ names "cuda", "cuda::mr", From a21dedc1de73bd2c194894c3fc8752de93837230 Mon Sep 17 00:00:00 2001 From: Vyas Ramasubramani Date: Tue, 26 Nov 2024 19:06:20 +0000 Subject: [PATCH 120/120] Add comments --- rapids_logger/logger_impl.hpp.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rapids_logger/logger_impl.hpp.in b/rapids_logger/logger_impl.hpp.in index 7ebb31e90..717a00ac9 100644 --- a/rapids_logger/logger_impl.hpp.in +++ b/rapids_logger/logger_impl.hpp.in @@ -24,6 +24,7 @@ #include #include +// Start hiding before including spdlog headers. #pragma GCC visibility push(hidden) #include @@ -200,4 +201,5 @@ const logger::sink_vector& logger::sinks() const { return sinks_; } logger::sink_vector& logger::sinks() { return sinks_; } } // namespace @_RAPIDS_LOGGER_NAMESPACE@ +// This visibility pragma must be here so that both our logger types and those coming from includes are hidden. #pragma GCC visibility pop