From 960935a5bd31b0a325285beb1deb816429c7fe00 Mon Sep 17 00:00:00 2001 From: Andrew Bardsley Date: Thu, 16 Oct 2014 05:49:53 -0400 Subject: [PATCH] base: Reimplement the DPRINTF mechanism in a Logger class This patch adds a Logger class encapsulating dprintf. This allows variants of DPRINTF logging to be constructed and substituted in place of the default behaviour. The Logger provides a logMessage(when, name, format, ...) member function like Trace::dprintf and a getOstream member function to use a raw ostream for logging. A class OstreamLogger is provided which generates the customary debugging output with Trace::OstreamLogger::logMessage being the old Trace::dprintf. --- src/base/trace.cc | 109 ++++++++++++++++----------- src/base/trace.hh | 158 +++++++++++++++++++++++++--------------- src/python/swig/trace.i | 12 ++- 3 files changed, 176 insertions(+), 103 deletions(-) diff --git a/src/base/trace.cc b/src/base/trace.cc index 00a4c3e6b..711d49655 100644 --- a/src/base/trace.cc +++ b/src/base/trace.cc @@ -1,4 +1,7 @@ /* + * Copyright (c) 2014 ARM Limited + * All rights reserved + * * Copyright (c) 2001-2006 The Regents of The University of Michigan * All rights reserved. * @@ -27,11 +30,13 @@ * * Authors: Nathan Binkert * Steve Reinhardt + * Andrew Bardsley */ #include #include #include +#include #include #include "base/misc.hh" @@ -39,89 +44,105 @@ #include "base/str.hh" #include "base/trace.hh" -using namespace std; +const std::string &name() +{ + static const std::string default_name("global"); -namespace Trace { + return default_name; +} + +namespace Trace +{ -const string DefaultName("global"); bool enabled = false; -// -// This variable holds the output stream for debug information. Other -// than setting up/redirecting this stream, do *NOT* reference this -// directly; use DebugOut() (see below) to access this stream for -// output. -// -ostream *dprintf_stream = &cerr; -ostream & +// This variable holds the output logger for debug information. Other +// than setting up/redirecting this logger, do *NOT* reference this +// directly + +Logger *debug_logger = NULL; + +Logger * +getDebugLogger() +{ + /* Set a default logger to cerr when no other logger is set */ + if (!debug_logger) + debug_logger = new OstreamLogger(std::cerr); + + return debug_logger; +} + +std::ostream & output() { - return *dprintf_stream; + return getDebugLogger()->getOstream(); } void -setOutput(const string &filename) +setDebugLogger(Logger *logger) { - dprintf_stream = simout.find(filename); - if (!dprintf_stream) - dprintf_stream = simout.create(filename); + if (!logger) + warn("Trying to set debug logger to NULL\n"); + else + debug_logger = logger; } ObjectMatch ignore; - -bool -__dprintf_prologue(Tick when, const std::string &name) +void +Logger::dump(Tick when, const std::string &name, const void *d, int len) { if (!name.empty() && ignore.match(name)) - return false; + return; - std::ostream &os = *dprintf_stream; - - if (when != MaxTick) - ccprintf(os, "%7d: ", when); - - if (!name.empty()) - os << name << ": "; - - return true; -} - -void -dump(Tick when, const std::string &name, const void *d, int len) -{ const char *data = static_cast(d); - std::ostream &os = *dprintf_stream; int c, i, j; for (i = 0; i < len; i += 16) { - if (!__dprintf_prologue(when, name)) - return; + std::ostringstream line; - ccprintf(os, "%08x ", i); + ccprintf(line, "%08x ", i); c = len - i; if (c > 16) c = 16; for (j = 0; j < c; j++) { - ccprintf(os, "%02x ", data[i + j] & 0xff); + ccprintf(line, "%02x ", data[i + j] & 0xff); if ((j & 0xf) == 7 && j > 0) - ccprintf(os, " "); + ccprintf(line, " "); } for (; j < 16; j++) - ccprintf(os, " "); - ccprintf(os, " "); + ccprintf(line, " "); + ccprintf(line, " "); for (j = 0; j < c; j++) { int ch = data[i + j] & 0x7f; - ccprintf(os, "%c", (char)(isprint(ch) ? ch : ' ')); + ccprintf(line, "%c", (char)(isprint(ch) ? ch : ' ')); } - ccprintf(os, "\n"); + ccprintf(line, "\n"); + logMessage(when, name, line.str()); if (c < 16) break; } } +void +OstreamLogger::logMessage(Tick when, const std::string &name, + const std::string &message) +{ + if (!name.empty() && ignore.match(name)) + return; + + if (when != MaxTick) + ccprintf(stream, "%7d: ", when); + + if (!name.empty()) + stream << name << ": "; + + stream << message; + stream.flush(); +} + } // namespace Trace diff --git a/src/base/trace.hh b/src/base/trace.hh index 3e6e37bd3..70e85bf35 100644 --- a/src/base/trace.hh +++ b/src/base/trace.hh @@ -2,15 +2,6 @@ * Copyright (c) 2014 ARM Limited * All rights reserved * - * The license below extends only to copyright in the software and shall - * not be construed as granting a license to any other intellectual - * property including but not limited to intellectual property relating - * to a hardware implementation of the functionality of the software - * licensed hereunder. You may use the software subject to the license - * terms below provided that you ensure that this notice is replicated - * unmodified and in its entirety in all distributions of the software, - * modified or unmodified, in source code or in binary form. - * * Copyright (c) 2001-2006 The Regents of The University of Michigan * All rights reserved. * @@ -39,6 +30,7 @@ * * Authors: Nathan Binkert * Steve Reinhardt + * Andrew Bardsley */ #ifndef __BASE_TRACE_HH__ @@ -54,34 +46,78 @@ namespace Trace { -using Debug::SimpleFlag; -using Debug::CompoundFlag; - -std::ostream &output(); -void setOutput(const std::string &filename); - -extern bool enabled; -bool changeFlag(const char *str, bool value); -void dumpStatus(); - -extern ObjectMatch ignore; -extern const std::string DefaultName; - -bool __dprintf_prologue(Tick when, const std::string &name); - -template void -dprintf(Tick when, const std::string &name, const char *format, - const Args &...args) +/** Debug logging base class. Handles formatting and outputting + * time/name/message messages */ +class Logger { - if (!__dprintf_prologue(when, name)) - return; + protected: + /** Name match for objects to ignore */ + ObjectMatch ignore; - std::ostream &os(output()); - ccprintf(os, format, args...); - os.flush(); -} + public: + /** Log a single message */ + template + void dprintf(Tick when, const std::string &name, const char *fmt, + const Args &...args) + { + if (!name.empty() && ignore.match(name)) + return; -void dump(Tick when, const std::string &name, const void *data, int len); + std::ostringstream line; + ccprintf(line, fmt, args...); + logMessage(when, name, line.str()); + } + + /** Dump a block of data of length len */ + virtual void dump(Tick when, const std::string &name, + const void *d, int len); + + /** Log formatted message */ + virtual void logMessage(Tick when, const std::string &name, + const std::string &message) = 0; + + /** Return an ostream that can be used to send messages to + * the 'same place' as formatted logMessage messages. This + * can be implemented to use a logger's underlying ostream, + * to provide an ostream which formats the output in some + * way, or just set to one of std::cout, std::cerr */ + virtual std::ostream &getOstream() = 0; + + /** Set objects to ignore */ + void setIgnore(ObjectMatch &ignore_) { ignore = ignore_; } + + virtual ~Logger() { } +}; + +/** Logging wrapper for ostreams with the format: + * : : */ +class OstreamLogger : public Logger +{ + protected: + std::ostream &stream; + + public: + OstreamLogger(std::ostream &stream_) : stream(stream_) + { } + + void logMessage(Tick when, const std::string &name, + const std::string &message) M5_ATTR_OVERRIDE; + + std::ostream &getOstream() M5_ATTR_OVERRIDE { return stream; } +}; + +/** Get the current global debug logger. This takes ownership of the given + * logger which should be allocated using 'new' */ +Logger *getDebugLogger(); + +/** Get the ostream from the current global logger */ +std::ostream &output(); + +/** Delete the current global logger and assign a new one */ +void setDebugLogger(Logger *logger); + +/** Enable debug logging */ +extern bool enabled; } // namespace Trace @@ -94,7 +130,9 @@ struct StringWrap const std::string &operator()() const { return str; } }; -inline const std::string &name() { return Trace::DefaultName; } +// Return the global context name "global". This function gets called when +// the DPRINTF macros are used in a context without a visible name() function +const std::string &name(); // Interface for things with names. (cf. SimObject but without other // functionality). This is useful when using DPRINTF @@ -124,40 +162,46 @@ class Named #define DTRACE(x) ((Debug::x) && Trace::enabled) -#define DDUMP(x, data, count) do { \ - using namespace Debug; \ - if (DTRACE(x)) \ - Trace::dump(curTick(), name(), data, count); \ +#define DDUMP(x, data, count) do { \ + using namespace Debug; \ + if (DTRACE(x)) \ + Trace::getDebugLogger()->dump(curTick(), name(), data, count); \ } while (0) -#define DPRINTF(x, ...) do { \ - using namespace Debug; \ - if (DTRACE(x)) \ - Trace::dprintf(curTick(), name(), __VA_ARGS__); \ +#define DPRINTF(x, ...) do { \ + using namespace Debug; \ + if (DTRACE(x)) { \ + Trace::getDebugLogger()->dprintf(curTick(), name(), \ + __VA_ARGS__); \ + } \ } while (0) -#define DPRINTFS(x, s, ...) do { \ - using namespace Debug; \ - if (DTRACE(x)) \ - Trace::dprintf(curTick(), s->name(), __VA_ARGS__); \ +#define DPRINTFS(x, s, ...) do { \ + using namespace Debug; \ + if (DTRACE(x)) { \ + Trace::getDebugLogger()->dprintf(curTick(), s->name(), \ + __VA_ARGS__); \ + } \ } while (0) -#define DPRINTFR(x, ...) do { \ - using namespace Debug; \ - if (DTRACE(x)) \ - Trace::dprintf((Tick)-1, std::string(), __VA_ARGS__); \ +#define DPRINTFR(x, ...) do { \ + using namespace Debug; \ + if (DTRACE(x)) { \ + Trace::getDebugLogger()->dprintf((Tick)-1, std::string(), \ + __VA_ARGS__); \ + } \ } while (0) -#define DDUMPN(data, count) do { \ - Trace::dump(curTick(), name(), data, count); \ +#define DDUMPN(data, count) do { \ + Trace::getDebugLogger()->dump(curTick(), name(), data, count); \ } while (0) -#define DPRINTFN(...) do { \ - Trace::dprintf(curTick(), name(), __VA_ARGS__); \ +#define DPRINTFN(...) do { \ + Trace::getDebugLogger()->dprintf(curTick(), name(), __VA_ARGS__); \ } while (0) -#define DPRINTFNR(...) do { \ - Trace::dprintf((Tick)-1, string(), __VA_ARGS__); \ +#define DPRINTFNR(...) do { \ + Trace::getDebugLogger()->dprintf((Tick)-1, string(), __VA_ARGS__); \ } while (0) #else // !TRACING_ON diff --git a/src/python/swig/trace.i b/src/python/swig/trace.i index 3b049a3d6..6525b3e51 100644 --- a/src/python/swig/trace.i +++ b/src/python/swig/trace.i @@ -33,17 +33,25 @@ %{ #include "base/trace.hh" #include "base/types.hh" +#include "base/output.hh" inline void output(const char *filename) { - Trace::setOutput(filename); + std::ostream *file_stream = simout.find(filename); + + if (!file_stream) + file_stream = simout.create(filename); + + Trace::setDebugLogger(new Trace::OstreamLogger(*file_stream)); } inline void ignore(const char *expr) { - Trace::ignore.setExpression(expr); + ObjectMatch ignore(expr); + + Trace::getDebugLogger()->setIgnore(ignore); } using Trace::enabled;