summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bardsley <Andrew.Bardsley@arm.com>2014-10-16 05:49:53 -0400
committerAndrew Bardsley <Andrew.Bardsley@arm.com>2014-10-16 05:49:53 -0400
commit960935a5bd31b0a325285beb1deb816429c7fe00 (patch)
treefcd7159f26be72be63bc49242a7648c613232830
parenta2d246b6b8379f9a74dbc56feefc155f615b5ea4 (diff)
downloadgem5-960935a5bd31b0a325285beb1deb816429c7fe00.tar.xz
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.
-rw-r--r--src/base/trace.cc109
-rw-r--r--src/base/trace.hh150
-rw-r--r--src/python/swig/trace.i12
3 files changed, 172 insertions, 99 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 <cctype>
#include <fstream>
#include <iostream>
+#include <sstream>
#include <string>
#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");
+
+ return default_name;
+}
-namespace Trace {
+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;
-
- std::ostream &os = *dprintf_stream;
-
- if (when != MaxTick)
- ccprintf(os, "%7d: ", when);
+ return;
- 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<const char *>(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;
+/** Debug logging base class. Handles formatting and outputting
+ * time/name/message messages */
+class Logger
+{
+ protected:
+ /** Name match for objects to ignore */
+ ObjectMatch ignore;
-std::ostream &output();
-void setOutput(const std::string &filename);
+ public:
+ /** Log a single message */
+ template <typename ...Args>
+ void dprintf(Tick when, const std::string &name, const char *fmt,
+ const Args &...args)
+ {
+ if (!name.empty() && ignore.match(name))
+ return;
+
+ 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() { }
+};
-extern bool enabled;
-bool changeFlag(const char *str, bool value);
-void dumpStatus();
+/** Logging wrapper for ostreams with the format:
+ * <when>: <name>: <message-body> */
+class OstreamLogger : public Logger
+{
+ protected:
+ std::ostream &stream;
-extern ObjectMatch ignore;
-extern const std::string DefaultName;
+ public:
+ OstreamLogger(std::ostream &stream_) : stream(stream_)
+ { }
-bool __dprintf_prologue(Tick when, const std::string &name);
+ void logMessage(Tick when, const std::string &name,
+ const std::string &message) M5_ATTR_OVERRIDE;
-template<typename ...Args> void
-dprintf(Tick when, const std::string &name, const char *format,
- const Args &...args)
-{
- if (!__dprintf_prologue(when, name))
- return;
+ std::ostream &getOstream() M5_ATTR_OVERRIDE { return stream; }
+};
- std::ostream &os(output());
- ccprintf(os, format, args...);
- os.flush();
-}
+/** Get the current global debug logger. This takes ownership of the given
+ * logger which should be allocated using 'new' */
+Logger *getDebugLogger();
-void dump(Tick when, const std::string &name, const void *data, int len);
+/** 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;