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.
This commit is contained in:
parent
a2d246b6b8
commit
960935a5bd
3 changed files with 176 additions and 103 deletions
|
@ -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");
|
||||
|
||||
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<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
|
||||
|
|
|
@ -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<typename ...Args> 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))
|
||||
protected:
|
||||
/** Name match for objects to ignore */
|
||||
ObjectMatch ignore;
|
||||
|
||||
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::ostream &os(output());
|
||||
ccprintf(os, format, args...);
|
||||
os.flush();
|
||||
}
|
||||
std::ostringstream line;
|
||||
ccprintf(line, fmt, args...);
|
||||
logMessage(when, name, line.str());
|
||||
}
|
||||
|
||||
void dump(Tick when, const std::string &name, const void *data, int len);
|
||||
/** 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:
|
||||
* <when>: <name>: <message-body> */
|
||||
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
|
||||
|
@ -127,37 +165,43 @@ class Named
|
|||
#define DDUMP(x, data, count) do { \
|
||||
using namespace Debug; \
|
||||
if (DTRACE(x)) \
|
||||
Trace::dump(curTick(), name(), data, count); \
|
||||
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__); \
|
||||
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__); \
|
||||
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__); \
|
||||
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); \
|
||||
Trace::getDebugLogger()->dump(curTick(), name(), data, count); \
|
||||
} while (0)
|
||||
|
||||
#define DPRINTFN(...) do { \
|
||||
Trace::dprintf(curTick(), name(), __VA_ARGS__); \
|
||||
Trace::getDebugLogger()->dprintf(curTick(), name(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DPRINTFNR(...) do { \
|
||||
Trace::dprintf((Tick)-1, string(), __VA_ARGS__); \
|
||||
Trace::getDebugLogger()->dprintf((Tick)-1, string(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#else // !TRACING_ON
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue