base: Reimplement the DPRINTF mechanism in a Logger class
authorAndrew Bardsley <Andrew.Bardsley@arm.com>
Thu, 16 Oct 2014 09:49:53 +0000 (05:49 -0400)
committerAndrew Bardsley <Andrew.Bardsley@arm.com>
Thu, 16 Oct 2014 09:49:53 +0000 (05:49 -0400)
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
src/base/trace.hh
src/python/swig/trace.i

index 00a4c3e6b887aeb487d8906d05340295216ae313..711d496554391e928206ce7d5f7841777eb68266 100644 (file)
@@ -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.
  *
  *
  * Authors: Nathan Binkert
  *          Steve Reinhardt
+ *          Andrew Bardsley
  */
 
 #include <cctype>
 #include <fstream>
 #include <iostream>
+#include <sstream>
 #include <string>
 
 #include "base/misc.hh"
 #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
index 3e6e37bd3aee302bff45fef14b150c46811e065c..70e85bf353e357bee47d9a8d090004b54c547895 100644 (file)
@@ -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__
 
 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
index 3b049a3d6901de5ab1952dc95474d42dd10af1fe..6525b3e515cae3ec66caed2c2f53268a22e59f5f 100644 (file)
 %{
 #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;