logging.hh (12334:e0ab29a34764) | logging.hh (12375:ceeb064dec4a) |
---|---|
1/* 2 * Copyright (c) 2014, 2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 32 unchanged lines hidden (view full) --- 41 * Dave Greene 42 * Andreas Sandberg 43 */ 44 45#ifndef __BASE_LOGGING_HH__ 46#define __BASE_LOGGING_HH__ 47 48#include <cassert> | 1/* 2 * Copyright (c) 2014, 2017 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software --- 32 unchanged lines hidden (view full) --- 41 * Dave Greene 42 * Andreas Sandberg 43 */ 44 45#ifndef __BASE_LOGGING_HH__ 46#define __BASE_LOGGING_HH__ 47 48#include <cassert> |
49#include <cstdlib> 50#include <iostream> | 49#include <sstream> |
51#include <utility> 52 53#include "base/compiler.hh" 54#include "base/cprintf.hh" 55 | 50#include <utility> 51 52#include "base/compiler.hh" 53#include "base/cprintf.hh" 54 |
56#if defined(__SUNPRO_CC) 57#define __FUNCTION__ "how to fix me?" 58#endif 59 | |
60class Logger 61{ 62 public: | 55class Logger 56{ 57 public: |
58 59 // Get a Logger for the specified type of message. 60 static Logger &getPanic(); 61 static Logger &getFatal(); 62 static Logger &getWarn(); 63 static Logger &getInfo(); 64 static Logger &getHack(); 65 |
|
63 enum LogLevel { | 66 enum LogLevel { |
64 PANIC = 0, 65 FATAL, 66 WARN, 67 INFO, 68 HACK, | 67 PANIC, FATAL, WARN, INFO, HACK, |
69 NUM_LOG_LEVELS, 70 }; 71 | 68 NUM_LOG_LEVELS, 69 }; 70 |
72 /** 73 * Set the active log level. 74 * 75 * All levels that are lower or equal to the selected log level 76 * will be activated. 77 * 78 * @param ll Maximum log level to print 79 */ 80 static void setLevel(LogLevel ll); | 71 static void 72 setLevel(LogLevel ll) 73 { 74 getPanic().enabled = (ll >= PANIC); 75 getFatal().enabled = (ll >= FATAL); 76 getWarn().enabled = (ll >= WARN); 77 getInfo().enabled = (ll >= INFO); 78 getHack().enabled = (ll >= HACK); 79 } |
81 | 80 |
82 /** 83 * Get a Logger corresponding to a specific log level 84 * 85 * @param ll Log level to access 86 * @return Reference to the requested logger 87 */ 88 static Logger &get(LogLevel ll); | 81 struct Loc 82 { 83 Loc(const char *file, int line) : file(file), line(line) {} 84 const char *file; 85 int line; 86 }; |
89 | 87 |
90 public: 91 Logger(std::ostream &stream, const char *prefix); | 88 Logger(const char *prefix) : enabled(true), prefix(prefix) 89 { 90 assert(prefix); 91 } 92 |
92 virtual ~Logger() {}; 93 | 93 virtual ~Logger() {}; 94 |
94 template<typename ...Args> void 95 print(const char *func, const char *file, int line, 96 const char *format, const Args &...args) | 95 void 96 print(const Loc &loc, const std::string &str) |
97 { | 97 { |
98 std::stringstream ss; 99 ss << prefix << str; 100 if (str.length() && str.back() != '\n' && str.back() != '\r') 101 ss << std::endl; |
|
98 if (!enabled) 99 return; | 102 if (!enabled) 103 return; |
104 log(loc, ss.str()); 105 } |
|
100 | 106 |
101 if (prefix) 102 stream << prefix << ": "; 103 ccprintf(stream, format, args...); 104 105 printEpilogue(func, file, line, format); | 107 template<typename ...Args> void 108 print(const Loc &loc, const char *format, const Args &...args) 109 { 110 std::stringstream ss; 111 ccprintf(ss, format, args...); 112 print(loc, ss.str()); |
106 } 107 108 template<typename ...Args> void | 113 } 114 115 template<typename ...Args> void |
109 print(const char *func, const char *file, int line, 110 const std::string &format, const Args &...args) | 116 print(const Loc &loc, const std::string &format, const Args &...args) |
111 { | 117 { |
112 print(func, file, line, format.c_str(), args...); | 118 print(loc, format.c_str(), args...); |
113 } 114 | 119 } 120 |
115 protected: 116 virtual void printEpilogue(const char *func, const char *file, int line, 117 const char *format); | 121 // This helper is necessary since noreturn isn't inherited by virtual 122 // functions, and gcc will get mad if a function calls panic and then 123 // doesn't return. 124 void exit_helper() M5_ATTR_NORETURN { exit(); ::abort(); } |
118 | 125 |
119 public: | 126 protected: |
120 bool enabled; | 127 bool enabled; |
121 bool verbose; | |
122 | 128 |
123 protected: 124 std::ostream &stream; | 129 virtual void log(const Loc &loc, std::string s) = 0; 130 virtual void exit() { /* Fall through to the abort in exit_helper. */ } 131 |
125 const char *prefix; 126}; 127 | 132 const char *prefix; 133}; 134 |
128#define exit_message(logger, code, ...) \ 129 do { \ 130 logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); \ 131 if (code < 0) \ 132 ::abort(); \ 133 else \ 134 ::exit(code); \ | 135 136#define base_message(logger, ...) \ 137 logger.print(::Logger::Loc(__FILE__, __LINE__), __VA_ARGS__) 138 139/* 140 * Only print the message the first time this expression is 141 * encountered. i.e. This doesn't check the string itself and 142 * prevent duplicate strings, this prevents the statement from 143 * happening more than once. So, even if the arguments change and that 144 * would have resulted in a different message thoes messages would be 145 * supressed. 146 */ 147#define base_message_once(...) do { \ 148 static bool once = false; \ 149 if (!once) { \ 150 base_message(__VA_ARGS__); \ 151 once = true; \ 152 } \ |
135 } while (0) 136 | 153 } while (0) 154 |
137// 138// This implements a cprintf based panic() function. panic() should 139// be called when something happens that should never ever happen 140// regardless of what the user does (i.e., an acutal m5 bug). panic() 141// calls abort which can dump core or enter the debugger. 142// 143// 144#define panic(...) exit_message(::Logger::get(::Logger::PANIC), -1, \ 145 __VA_ARGS__) | 155#define exit_message(logger, ...) \ 156 do { \ 157 base_message(logger, __VA_ARGS__); \ 158 logger.exit_helper(); \ 159 } while (0) |
146 | 160 |
147// 148// This implements a cprintf based fatal() function. fatal() should 149// be called when the simulation cannot continue due to some condition 150// that is the user's fault (bad configuration, invalid arguments, 151// etc.) and not a simulator bug. fatal() calls abort() like 152// panic() does. 153// 154#define fatal(...) exit_message(::Logger::get(::Logger::FATAL), 1, \ 155 __VA_ARGS__) | 161/** 162 * This implements a cprintf based panic() function. panic() should 163 * be called when something happens that should never ever happen 164 * regardless of what the user does (i.e., an acutal m5 bug). panic() 165 * might call abort which can dump core or enter the debugger. 166 */ 167#define panic(...) exit_message(::Logger::getPanic(), __VA_ARGS__) |
156 157/** | 168 169/** |
170 * This implements a cprintf based fatal() function. fatal() should 171 * be called when the simulation cannot continue due to some condition 172 * that is the user's fault (bad configuration, invalid arguments, 173 * etc.) and not a simulator bug. fatal() might call exit, unlike panic(). 174 */ 175#define fatal(...) exit_message(::Logger::getFatal(), __VA_ARGS__) 176 177/** |
|
158 * Conditional panic macro that checks the supplied condition and only panics 159 * if the condition is true and allows the programmer to specify diagnostic 160 * printout. Useful to replace if + panic, or if + print + assert, etc. 161 * 162 * @param cond Condition that is checked; if true -> panic 163 * @param ... Printf-based format string with arguments, extends printout. 164 */ 165#define panic_if(cond, ...) \ --- 18 unchanged lines hidden (view full) --- 184 do { \ 185 if ((cond)) { \ 186 fatal("fatal condition " # cond " occurred: %s", \ 187 csprintf(__VA_ARGS__)); \ 188 } \ 189 } while (0) 190 191 | 178 * Conditional panic macro that checks the supplied condition and only panics 179 * if the condition is true and allows the programmer to specify diagnostic 180 * printout. Useful to replace if + panic, or if + print + assert, etc. 181 * 182 * @param cond Condition that is checked; if true -> panic 183 * @param ... Printf-based format string with arguments, extends printout. 184 */ 185#define panic_if(cond, ...) \ --- 18 unchanged lines hidden (view full) --- 204 do { \ 205 if ((cond)) { \ 206 fatal("fatal condition " # cond " occurred: %s", \ 207 csprintf(__VA_ARGS__)); \ 208 } \ 209 } while (0) 210 211 |
192#define base_message(logger, ...) \ 193 logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) | 212#define warn(...) base_message(::Logger::getWarn(), __VA_ARGS__) 213#define inform(...) base_message(::Logger::getInfo(), __VA_ARGS__) 214#define hack(...) base_message(::Logger::getHack(), __VA_ARGS__) |
194 | 215 |
195// Only print the message the first time this expression is 196// encountered. i.e. This doesn't check the string itself and 197// prevent duplicate strings, this prevents the statement from 198// happening more than once. So, even if the arguments change and that 199// would have resulted in a different message thoes messages would be 200// supressed. 201#define base_message_once(...) do { \ 202 static bool once = false; \ 203 if (!once) { \ 204 base_message(__VA_ARGS__); \ 205 once = true; \ 206 } \ 207 } while (0) | 216#define warn_once(...) base_message_once(::Logger::getWarn(), __VA_ARGS__) 217#define inform_once(...) base_message_once(::Logger::getInfo(), __VA_ARGS__) 218#define hack_once(...) base_message_once(::Logger::getHack(), __VA_ARGS__) |
208 | 219 |
209 210#define warn(...) \ 211 base_message(::Logger::get(::Logger::WARN), __VA_ARGS__) 212#define inform(...) \ 213 base_message(::Logger::get(::Logger::INFO), __VA_ARGS__) 214#define hack(...) \ 215 base_message(::Logger::get(::Logger::HACK), __VA_ARGS__) 216 217#define warn_once(...) \ 218 base_message_once(::Logger::get(::Logger::WARN), __VA_ARGS__) 219#define inform_once(...) \ 220 base_message_once(::Logger::get(::Logger::INFO), __VA_ARGS__) 221#define hack_once(...) \ 222 base_message_once(::Logger::get(::Logger::HACK), __VA_ARGS__) 223 | |
224/** 225 * Conditional warning macro that checks the supplied condition and 226 * only prints a warning if the condition is true. Useful to replace 227 * if + warn. 228 * 229 * @param cond Condition that is checked; if true -> warn 230 * @param ... Printf-based format string with arguments, extends printout. 231 */ --- 25 unchanged lines hidden --- | 220/** 221 * Conditional warning macro that checks the supplied condition and 222 * only prints a warning if the condition is true. Useful to replace 223 * if + warn. 224 * 225 * @param cond Condition that is checked; if true -> warn 226 * @param ... Printf-based format string with arguments, extends printout. 227 */ --- 25 unchanged lines hidden --- |