Skip to content
Snippets Groups Projects
Commit 7491c8ae authored by Sam Yates's avatar Sam Yates
Browse files

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.
parent 7f0a2564
No related branches found
No related tags found
No related merge requests found
......@@ -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)
......
#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
#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
......
#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
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment