From 5936f978b22d576620f6664d5713d6afa1a76a43 Mon Sep 17 00:00:00 2001 From: Ewan Miller Date: Thu, 19 Sep 2024 23:19:34 -0400 Subject: [PATCH] fix up so it now compiles with and without pch --- nuTens/instrumentation.hpp | 249 ------------------------------------ nuTens/logging.hpp | 132 ------------------- nuTens/nuTens-pch.hpp | 16 --- nuTens/utils/CMakeLists.txt | 2 +- 4 files changed, 1 insertion(+), 398 deletions(-) delete mode 100644 nuTens/instrumentation.hpp delete mode 100644 nuTens/logging.hpp delete mode 100644 nuTens/nuTens-pch.hpp diff --git a/nuTens/instrumentation.hpp b/nuTens/instrumentation.hpp deleted file mode 100644 index 931fbff..0000000 --- a/nuTens/instrumentation.hpp +++ /dev/null @@ -1,249 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -/*! - * @file instrumentation.hpp - * @brief Define utilities for instrumentation of the code - * - * This is the home of anything that gets placed inside other classes or functions in order to instrument the code. - * e.g. for profiling or debugging. Everything should ideally be macro-fied so it can be included only for certain - * builds, or specified by build time options. - */ - -struct ProfileResult -{ - /// @struct ProfileResult - /// @brief Hold the results of a profiled function to be written out. - - std::string name; - long start; - long end; - uint32_t threadID; -}; - -class ProfileWriter -{ - /*! - * @class ProfileWriter - * @brief Singleton class to collect timing information for functions and write out to a file that can be inspected - * later with visual profiling tool - * - * Writes out profiling information in a json format readable by chrome tracing - * (https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/) Use the macros provided to instrument - * the source code like: - * - * @code{.cpp} - * \\ header.hpp - * - * class ClassName - * { - * returnType func(args); - * } - * - * - * \\ implementation.cpp - * - * ClassName::func(args) - * { - * NT_PROFILE(); - * - * \\ implementation code - * - * } - * @endcode - * - * In order to instantiate the ProfileWriter in an application you will then need to use NT_PROFILE_BEGINSESSION() - * and NT_PROFILE_ENDSESSION() like: - * - * @code{.cpp} - * - * \\ application.cpp - * - * void main() - * { - * NT_PROFILE_BEGINSESSION(sessionName); - * - * \\ ... code ... - * ClassName instance; - * - * instance.func(args); - * - * \\ ... code ... - * - * NT_PROFILE_ENDSSION(); - * } - * - * @endcode - * - * This will save a json file called -profile.json. - * Then you can open up your favourite chromium based browser and go to chrome://tracing. You can then just drag and - * drop the profiling json file and should see a lovely display of the collected profile information. - */ - - /// @todo currently only suppor the format used by chrome tracing. Would be nice to support other formats too. - /// Should just be a case of adding additional option for writeProfile and header and footer - - public: - /// @brief Constructor - ProfileWriter() = default; - - /// @brief Set up the session - /// @param[in] name The name of the timer - /// @param[in] filePath The destination of the output file - void beginSession(const std::string &name, const std::string &filePath = "results.json") - { - _outputStream.open(filePath); - writeHeader(); - _name = name; - } - - /// @brief Close the session and clean up - void endSession() - { - writeFooter(); - _outputStream.close(); - _name = ""; - _profileCount = 0; - } - - /// @brief Write out the results of a profiled function - /// @param[in] result The result to write - void writeProfile(const ProfileResult &result) - { - if (_profileCount++ > 0) - { - _outputStream << ","; - } - - std::string name = result.name; - std::replace(name.begin(), name.end(), '"', '\''); - - _outputStream << "{"; - _outputStream << R"("cat":"function",)"; - _outputStream << "\"dur\":" << (result.end - result.start) << ','; - _outputStream << R"("name":")" << name << "\","; - _outputStream << R"("ph":"X",)"; - _outputStream << "\"pid\":0,"; - _outputStream << "\"tid\":" << result.threadID << ","; - _outputStream << "\"ts\":" << result.start; - _outputStream << "}"; - - _outputStream.flush(); - } - - /// @brief Write the file header - void writeHeader() - { - _outputStream << R"({"otherData": {},"traceEvents":[)"; - _outputStream.flush(); - } - - /// @brief Write the file footer - void writeFooter() - { - _outputStream << "]}"; - _outputStream.flush(); - } - - /// @brief Get a reference to the ProfileWriter, if it has not yet been instantiated, this will do so - static ProfileWriter &get() - { - static ProfileWriter instance; // this will be instantiated the first time ProfileWriter::get() is called and - // killed at the end of the program - return instance; - } - - private: - std::string _name; - std::ofstream _outputStream; - uint _profileCount{0}; -}; - -class InstrumentationTimer -{ - /*! - * @class InstrumentationTimer - * @brief Class to perform timing - * - * Gets created at the start of the scope to time then will be deleted when the scope ends. - * When deleted, will write out timing information to the output stream defined by ProfileWriter. - * - * - */ - - public: - /// @brief Construct an InstrumentationTimer object and start the clock - /// @param[in] name The name of the profile. Typically use __PRETTY_FUNCTION__ so it's clear which part of the code - /// is being profiled. - InstrumentationTimer(std::string name) : _name(std::move(name)), _stopped(false) - { - _startTimepoint = std::chrono::high_resolution_clock::now(); - } - - /// @brief Destroy the timer object and stop the timer by calling stop() - ~InstrumentationTimer() - { - if (!_stopped) - { - stop(); - } - } - - InstrumentationTimer(const InstrumentationTimer &) = delete; - /// @brief Stop the timer and write out the profile result using the ProfileWriter - void stop() - { - auto endTimepoint = std::chrono::high_resolution_clock::now(); - - long long start = - std::chrono::time_point_cast(_startTimepoint).time_since_epoch().count(); - long long end = - std::chrono::time_point_cast(endTimepoint).time_since_epoch().count(); - - uint32_t threadID = std::hash{}(std::this_thread::get_id()); - ProfileWriter::get().writeProfile({_name, start, end, threadID}); - - _stopped = true; - } - - private: - std::string _name; - std::chrono::time_point _startTimepoint; - bool _stopped; -}; - -/// @brief Begin a profiling session -/// Will open up the results json file and set things up. -/// If USE_PROFILING not defined will be empty so that it can be stripped from non-debug builds -/// @param[in] sessionName The name of the session -#ifdef USE_PROFILING -// NOLINTNEXTLINE -#define NT_PROFILE_BEGINSESSION(sessionName) \ - ProfileWriter::get().beginSession(sessionName, std::string(sessionName) + "-profile.json") -#else -#define NT_PROFILE_BEGINSESSION(sessionName) -#endif - -/// @brief Profile the current scope -/// Shold always be used at the very start of the scope. -#ifdef USE_PROFILING -// NOLINTNEXTLINE -#define NT_PROFILE() InstrumentationTimer timer##__LINE__(std::string(__PRETTY_FUNCTION__)) -#else -#define NT_PROFILE() -#endif - -/// @brief End the profiling session -/// Should be used at the very end of an application, after all functions containing a NT_PROFILE() have been called -#ifdef USE_PROFILING -// NOLINTNEXTLINE -#define NT_PROFILE_ENDSESSION() ProfileWriter::get().endSession() -#else -#define NT_PROFILE_ENDSESSION() -#endif \ No newline at end of file diff --git a/nuTens/logging.hpp b/nuTens/logging.hpp deleted file mode 100644 index b04fb84..0000000 --- a/nuTens/logging.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#pragma once - -#include -#include - -/*! \file logging.hpp - \brief Define the logging utilities for nuTens - - Basically just use spdlog interface. - However we define our own log levels and macros and pass them through to - the logging library. This is juuust in case we ever want to change the - logging library we use. This way only this file would need to change. -*/ - -constexpr size_t NT_LOG_LEVEL_TRACE = 0; -constexpr size_t NT_LOG_LEVEL_DEBUG = 1; -constexpr size_t NT_LOG_LEVEL_INFO = 2; -constexpr size_t NT_LOG_LEVEL_WARNING = 3; -constexpr size_t NT_LOG_LEVEL_ERROR = 4; -constexpr size_t NT_LOG_LEVEL_SILENT = 5; - -// define the log level in spdlogger -#if NT_LOG_LEVEL == NT_LOG_LEVEL_TRACE -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE // NOLINT - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_DEBUG -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG // NOLINT - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_INFO -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO // NOLINT - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_WARNING -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_WARNING // NOLINT - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_ERROR -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_ERROR // NOLINT - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_SILENT -#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF // NOLINT - -#endif - -// #include "spdlog.h" has to happen *AFTER* we set SPDLOG_ACTIVE_LEVEL -#include - -// Now define the runtime log level which we will use to set the default log -// level This is needed since for trace or debug, we need to alter the default -// value at runtime see -// https://github.com/gabime/spdlog/wiki/1.-QuickStart#:~:text=Notice%20that%20spdlog%3A%3Aset_level%20is%20also%20necessary%20to%20print%20out%20debug%20or%20trace%20messages. -#if NT_LOG_LEVEL == NT_LOG_LEVEL_TRACE -const static spdlog::level::level_enum runtimeLogLevel = spdlog::level::trace; - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_DEBUG -const static spdlog::level::level_enum runtimeLogLevel = spdlog::level::debug; - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_INFO -const static spdlog::level::level_enum runtimeLogLevel = spdlog::level::info; - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_WARNING -const static spdlog::level::level_enum runtimeLogLevel = spdlog::level::warning; - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_ERROR -const static spdlog::level::level_enum runtimeLogLevel = spdlog::level::error; - -#elif NT_LOG_LEVEL == NT_LOG_LEVEL_SILENT -const static spdlog::level::level_enum runtimeLogLevel = spdlog::level::off; - -#endif - -namespace ntlogging -{ -static std::once_flag - logLevelOnceFlag; // NOLINT: Linter gets angry that this is globally accessible and non-const. Needs to be non-const - // so it can be flipped by the call to std::call_once. Could wrap it up so that it's not global - // but that feels like a bit much for what we're doing here - -/// @brief Set up the logger at runtime, should only be invoked once the very -/// first time any of the logging macros below are called -inline void setup_logging() -{ - std::call_once(logLevelOnceFlag, []() { - std::cout << ":::::::: INFO: Setting default spdlog logging level to " - << spdlog::level::to_string_view(runtimeLogLevel).data() << " ::::::::" << std::endl; - spdlog::set_level(runtimeLogLevel); - }); -} -} // namespace ntlogging - -/// @brief Trace message that will only be displayed if NT_LOG_LEVEL == -/// NT_LOG_LEVEL_TRACE -/// @param[in] ... The message to print. This can consist of just a simple -/// string, or a format string and subsequent variables to format. -// NOLINTNEXTLINE -#define NT_TRACE(...) \ - ntlogging::setup_logging(); \ - SPDLOG_TRACE(__VA_ARGS__) - -/// @brief Debug message that will only be displayed if NT_LOG_LEVEL <= -/// NT_LOG_LEVEL_DEBUG -/// @param[in] ... The message to print. This can consist of just a simple -/// string, or a format string and subsequent variables to format. -// NOLINTNEXTLINE -#define NT_DEBUG(...) \ - ntlogging::setup_logging(); \ - SPDLOG_DEBUG(__VA_ARGS__) - -/// @brief Information message that will only be displayed if NT_LOG_LEVEL <= -/// NT_LOG_LEVEL_INFO -/// @param[in] ... The message to print. This can consist of just a simple -/// string, or a format string and subsequent variables to format. -// NOLINTNEXTLINE -#define NT_INFO(...) \ - ntlogging::setup_logging(); \ - SPDLOG_INFO(__VA_ARGS__) - -/// @brief Warning message that will only be displayed if NT_LOG_LEVEL <= -/// NT_LOG_LEVEL_WARNING -/// @param[in] ... The message to print. This can consist of just a simple -/// string, or a format string and subsequent variables to format. -// NOLINTNEXTLINE -#define NT_WARN(...) \ - ntlogging::setup_logging(); \ - SPDLOG_WARN(__VA_ARGS__) - -/// @brief Error message that will only be displayed if NT_LOG_LEVEL <= -/// NT_LOG_LEVEL_ERROR -/// @param[in] ... The message to print. This can consist of just a simple -/// string, or a format string and subsequent variables to format. -// NOLINTNEXTLINE -#define NT_ERROR(...) \ - ntlogging::setup_logging(); \ - SPDLOG_ERROR(__VA_ARGS__) diff --git a/nuTens/nuTens-pch.hpp b/nuTens/nuTens-pch.hpp deleted file mode 100644 index 973c409..0000000 --- a/nuTens/nuTens-pch.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#if USE_PYTORCH -#include -#endif \ No newline at end of file diff --git a/nuTens/utils/CMakeLists.txt b/nuTens/utils/CMakeLists.txt index 22318a5..97a4dca 100644 --- a/nuTens/utils/CMakeLists.txt +++ b/nuTens/utils/CMakeLists.txt @@ -77,5 +77,5 @@ if(NT_USE_PCH) endif() ## end NT_USE_PCH block add_library(utils INTERFACE) -target_link_libraries(utils INTERFACE logging instrumentation tensor-backend nuTens-pch) +target_link_libraries(utils INTERFACE logging instrumentation tensor-backend) target_include_directories(utils INTERFACE "${CMAKE_SOURCE_DIR}")