From 7491c8ae76e6dc761299617ad67afb12af2882c4 Mon Sep 17 00:00:00 2001 From: Sam Yates <halfflat@gmail.com> Date: Tue, 5 Jul 2016 00:29:02 +0200 Subject: [PATCH] Add basic debugging trace capability. Defines a TRACE(...) macro that, when enabled at compile time with -DWITH_TRACE, prints to std::cerr the location in the source, a time stamp, and the values of any variables given to the macro. Uses a mutex to protect against simultaneous writes to std::cerr when TBB is enabled; it is not optimized for speed. --- CMakeLists.txt | 6 +++++ src/util/debug.cpp | 39 +++++++++++++++++++++++++++++++- src/util/debug.hpp | 55 +++++++++++++++++++++++++++++++++++++++++++-- src/util/ioutil.hpp | 28 +++++++++++++++++++++++ 4 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 src/util/ioutil.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a432f4e8..8ba5a855 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,12 @@ if(WITH_ASSERTIONS) add_definitions("-DWITH_ASSERTIONS") endif() +# enable traces? +set(WITH_TRACE OFF CACHE BOOL "enable TRACE() macros in code") +if(WITH_TRACE) + add_definitions("-DWITH_TRACE") +endif() + # TBB support set(WITH_TBB OFF CACHE BOOL "use TBB for on-node threading" ) if(WITH_TBB) diff --git a/src/util/debug.cpp b/src/util/debug.cpp index 2dd83f56..029fae92 100644 --- a/src/util/debug.cpp +++ b/src/util/debug.cpp @@ -1,9 +1,22 @@ +#include <chrono> #include <cstdlib> +#include <cstring> +#include <iomanip> #include <iostream> +#include <thread> #include "util/debug.hpp" +#include "util/ioutil.hpp" -bool nest::mc::util::failed_assertion(const char *assertion, const char *file, +namespace nest { +namespace mc { +namespace util { + +#ifdef WITH_TBB +std::mutex global_debug_cerr_mutex; +#endif + +bool failed_assertion(const char *assertion, const char *file, int line, const char *func) { // Explicit flush, as we can't assume default buffering semantics on stderr/cerr, @@ -14,3 +27,27 @@ bool nest::mc::util::failed_assertion(const char *assertion, const char *file, std::abort(); return false; } + +std::ostream& debug_emit_trace_leader(std::ostream &out, const char* file, int line, const char* varlist) { + iosfmt_guard _(out); + + const char* leaf = std::strrchr(file, '/'); + out << (leaf?leaf+1:file) << ':' << line << " "; + + using namespace std::chrono; + auto tstamp = system_clock::now().time_since_epoch(); + auto tstamp_usec = duration_cast<microseconds>(tstamp).count(); + + out << std::right << '['; + out << std::setw(11) << std::setfill('0') << (tstamp_usec/1000000) << '.'; + out << std::setw(6) << std::setfill('0') << (tstamp_usec%1000000) << ']'; + + if (varlist && *varlist) { + out << ' ' << varlist << ": "; + } + return out; +} + +} // namespace util +} // namespace mc +} // namespace nest diff --git a/src/util/debug.hpp b/src/util/debug.hpp index 148b3c44..6739c4ff 100644 --- a/src/util/debug.hpp +++ b/src/util/debug.hpp @@ -1,15 +1,66 @@ #pragma once +#include <iostream> +#include <sstream> +#include <mutex> + namespace nest { namespace mc { namespace util { -bool failed_assertion(const char *assertion, const char *file, int line, const char *func); +bool failed_assertion(const char* assertion, const char* file, int line, const char* func); +std::ostream &debug_emit_trace_leader(std::ostream& out, const char* file, int line, const char* varlist); + +inline void debug_emit(std::ostream& out) { + out << "\n"; +} -} +template <typename Head, typename... Tail> +void debug_emit(std::ostream& out, const Head& head, const Tail&... tail) { + out << head; + if (sizeof...(tail)) { + out << ", "; + } + debug_emit(out, tail...); } + +#ifdef WITH_TBB +extern std::mutex global_debug_cerr_mutex; +#endif + +template <typename... Args> +void debug_emit_trace(const char *file, int line, const char *varlist, const Args&... args) { +#ifdef WITH_TBB + std::stringstream out; +#else + auto &out = std::cerr; +#endif + + debug_emit_trace_leader(out, file, line, varlist); + debug_emit(out, args...); + +#ifdef WITH_TBB + std::lock_guard<std::mutex> _(global_debug_cerr_mutex); + std::cerr << out.rdbuf(); +#else + out.flush(); +#endif } +} // namespace util +} // namespace mc +} // namespace nest + +#ifdef WITH_TRACE + +#define TRACE(vars...) nest::mc::util::debug_emit_trace(__FILE__, __LINE__, #vars, ##vars) + +#else + +#define TRACE(...) + +#endif + #ifdef WITH_ASSERTIONS diff --git a/src/util/ioutil.hpp b/src/util/ioutil.hpp new file mode 100644 index 00000000..b6670072 --- /dev/null +++ b/src/util/ioutil.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include <ios> + +namespace nest { +namespace mc { +namespace util { + +class iosfmt_guard { +public: + explicit iosfmt_guard(std::ios &stream): save_(nullptr), stream_(stream) { + save_.copyfmt(stream_); + } + + ~iosfmt_guard() { + stream_.copyfmt(save_); + } + +private: + std::ios save_; + std::ios& stream_; +}; + + +} // namespace util +} // namespace mc +} // namespace nest + -- GitLab