sc_report_handler.cc revision 13080
1/* 2 * Copyright 2018 Google, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer; 8 * redistributions in binary form must reproduce the above copyright 9 * notice, this list of conditions and the following disclaimer in the 10 * documentation and/or other materials provided with the distribution; 11 * neither the name of the copyright holders nor the names of its 12 * contributors may be used to endorse or promote products derived from 13 * this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * Authors: Gabe Black 28 */ 29 30#include <fstream> 31#include <map> 32#include <sstream> 33#include <string> 34 35#include "base/logging.hh" 36#include "systemc/core/process.hh" 37#include "systemc/core/scheduler.hh" 38#include "systemc/ext/core/sc_main.hh" 39#include "systemc/ext/utils/sc_report_handler.hh" 40 41namespace sc_core 42{ 43 44namespace 45{ 46 47std::unique_ptr<std::string> logFileName; 48std::unique_ptr<std::ofstream> logFile; 49 50struct ReportCatInfo 51{ 52 explicit ReportCatInfo(sc_actions actions) : 53 actions(actions), count(0), limit(-1) 54 {} 55 ReportCatInfo() : ReportCatInfo(SC_UNSPECIFIED) {} 56 57 bool 58 checkLimit(sc_actions &actions) 59 { 60 if (limit == 0 || count < limit) 61 return false; 62 if (limit != -1) 63 actions |= SC_STOP; 64 return true; 65 } 66 67 sc_actions actions; 68 int count; 69 int limit; 70}; 71 72const char *severityNames[] = { 73 [SC_INFO] = "Info", 74 [SC_WARNING] = "Warning", 75 [SC_ERROR] = "Error", 76 [SC_FATAL] = "Fatal" 77}; 78 79ReportCatInfo catForSeverity[SC_MAX_SEVERITY] = 80{ 81 [SC_INFO] = ReportCatInfo(SC_DEFAULT_INFO_ACTIONS), 82 [SC_WARNING] = ReportCatInfo(SC_DEFAULT_WARNING_ACTIONS), 83 [SC_ERROR] = ReportCatInfo(SC_DEFAULT_ERROR_ACTIONS), 84 [SC_FATAL] = ReportCatInfo(SC_DEFAULT_FATAL_ACTIONS) 85}; 86 87std::map<std::string, ReportCatInfo> catForMsgType; 88std::map<std::pair<std::string, sc_severity>, ReportCatInfo> 89 catForSeverityAndMsgType; 90 91int verbosityLevel = SC_MEDIUM; 92 93sc_actions suppressedActions = SC_UNSPECIFIED; 94sc_actions forcedActions = SC_UNSPECIFIED; 95sc_actions catchActions = SC_UNSPECIFIED; 96 97sc_report_handler_proc reportHandlerProc = &sc_report_handler::default_handler; 98 99sc_actions maxAction = SC_ABORT; 100 101std::unique_ptr<sc_report> globalReportCache; 102 103} // anonymous namespace 104 105void 106sc_report_handler::report(sc_severity severity, const char *msg_type, 107 const char *msg, const char *file, int line) 108{ 109 report(severity, msg_type, msg, SC_MEDIUM, file, line); 110} 111 112void 113sc_report_handler::report(sc_severity severity, const char *msg_type, 114 const char *msg, int verbosity, const char *file, 115 int line) 116{ 117 if (severity == SC_INFO && verbosity > verbosityLevel) 118 return; 119 120 ReportCatInfo &sevInfo = catForSeverity[severity]; 121 ReportCatInfo &msgInfo = catForMsgType[msg_type]; 122 ReportCatInfo &sevMsgInfo = catForSeverityAndMsgType[ 123 std::make_pair(std::string(msg_type), severity)]; 124 125 sevInfo.count++; 126 msgInfo.count++; 127 sevMsgInfo.count++; 128 129 sc_actions actions = SC_UNSPECIFIED; 130 if (sevMsgInfo.actions != SC_UNSPECIFIED) 131 actions = sevMsgInfo.actions; 132 else if (msgInfo.actions != SC_UNSPECIFIED) 133 actions = msgInfo.actions; 134 else if (sevInfo.actions != SC_UNSPECIFIED) 135 actions = sevInfo.actions; 136 137 actions &= ~suppressedActions; 138 actions |= forcedActions; 139 140 if (sevMsgInfo.checkLimit(actions) && msgInfo.checkLimit(actions)) 141 sevInfo.checkLimit(actions); 142 143 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 144 sc_report report(severity, msg_type, msg, verbosity, file, line, 145 sc_time::from_value(::sc_gem5::scheduler.getCurTick()), 146 current ? current->name() : nullptr, -1); 147 148 if (actions & SC_CACHE_REPORT) { 149 if (current) { 150 current->lastReport(&report); 151 } else { 152 globalReportCache = 153 std::unique_ptr<sc_report>(new sc_report(report)); 154 } 155 } 156 157 reportHandlerProc(report, actions); 158} 159 160void 161sc_report_handler::report(sc_severity, int id, const char *msg, 162 const char *file, int line) 163{ 164 warn("%s:%d %s\n", file, line, msg); 165 warn("%s not implemented.\n", __PRETTY_FUNCTION__); 166} 167 168sc_actions 169sc_report_handler::set_actions(sc_severity severity, sc_actions actions) 170{ 171 ReportCatInfo &info = catForSeverity[severity]; 172 sc_actions previous = info.actions; 173 info.actions = actions; 174 return previous; 175} 176 177sc_actions 178sc_report_handler::set_actions(const char *msg_type, sc_actions actions) 179{ 180 ReportCatInfo &info = catForMsgType[msg_type]; 181 sc_actions previous = info.actions; 182 info.actions = actions; 183 return previous; 184} 185 186sc_actions 187sc_report_handler::set_actions( 188 const char *msg_type, sc_severity severity, sc_actions actions) 189{ 190 ReportCatInfo &info = catForSeverityAndMsgType[ 191 std::make_pair(std::string(msg_type), severity)]; 192 sc_actions previous = info.actions; 193 info.actions = actions; 194 return previous; 195} 196 197int 198sc_report_handler::stop_after(sc_severity severity, int limit) 199{ 200 ReportCatInfo &info = catForSeverity[severity]; 201 int previous = info.limit; 202 info.limit = limit; 203 return previous; 204} 205 206int 207sc_report_handler::stop_after(const char *msg_type, int limit) 208{ 209 ReportCatInfo &info = catForMsgType[msg_type]; 210 int previous = info.limit; 211 info.limit = limit; 212 return previous; 213} 214 215int 216sc_report_handler::stop_after( 217 const char *msg_type, sc_severity severity, int limit) 218{ 219 ReportCatInfo &info = catForSeverityAndMsgType[ 220 std::make_pair(std::string(msg_type), severity)]; 221 int previous = info.limit; 222 info.limit = limit; 223 return previous; 224} 225 226int 227sc_report_handler::get_count(sc_severity severity) 228{ 229 return catForSeverity[severity].count; 230} 231 232int 233sc_report_handler::get_count(const char *msg_type) 234{ 235 return catForMsgType[msg_type].count; 236} 237 238int 239sc_report_handler::get_count(const char *msg_type, sc_severity severity) 240{ 241 return catForSeverityAndMsgType[ 242 std::make_pair(std::string(msg_type), severity)].count; 243} 244 245int 246sc_report_handler::set_verbosity_level(int vl) 247{ 248 int previous = verbosityLevel; 249 verbosityLevel = vl; 250 return previous; 251} 252 253int 254sc_report_handler::get_verbosity_level() 255{ 256 return verbosityLevel; 257} 258 259 260sc_actions 261sc_report_handler::suppress(sc_actions actions) 262{ 263 sc_actions previous = suppressedActions; 264 suppressedActions = actions; 265 return previous; 266} 267 268sc_actions 269sc_report_handler::suppress() 270{ 271 return suppress(SC_UNSPECIFIED); 272} 273 274sc_actions 275sc_report_handler::force(sc_actions actions) 276{ 277 sc_actions previous = forcedActions; 278 forcedActions = actions; 279 return previous; 280} 281 282sc_actions 283sc_report_handler::force() 284{ 285 return force(SC_UNSPECIFIED); 286} 287 288 289sc_actions 290sc_report_handler::set_catch_actions(sc_actions actions) 291{ 292 sc_actions previous = catchActions; 293 catchActions = actions; 294 return previous; 295} 296 297sc_actions 298sc_report_handler::get_catch_actions() 299{ 300 return catchActions; 301} 302 303 304void 305sc_report_handler::set_handler(sc_report_handler_proc proc) 306{ 307 reportHandlerProc = proc; 308} 309 310void 311sc_report_handler::default_handler( 312 const sc_report &report, const sc_actions &actions) 313{ 314 if (actions & SC_DISPLAY) 315 cprintf("\n%s\n", sc_report_compose_message(report)); 316 317 if ((actions & SC_LOG) && logFile) { 318 ccprintf(*logFile, "%s: %s\n", report.get_time().to_string(), 319 sc_report_compose_message(report)); 320 } 321 if (actions & SC_STOP) { 322 sc_stop_here(report.get_msg_type(), report.get_severity()); 323 sc_stop(); 324 } 325 if (actions & SC_INTERRUPT) 326 sc_interrupt_here(report.get_msg_type(), report.get_severity()); 327 if (actions & SC_ABORT) 328 sc_abort(); 329 if (actions & SC_THROW) { 330 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 331 if (current) 332 current->isUnwinding(false); 333 throw report; 334 } 335} 336 337sc_actions 338sc_report_handler::get_new_action_id() 339{ 340 maxAction = maxAction << 1; 341 return maxAction; 342} 343 344sc_report * 345sc_report_handler::get_cached_report() 346{ 347 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 348 if (current) 349 return current->lastReport(); 350 return globalReportCache.get(); 351} 352 353void 354sc_report_handler::clear_cached_report() 355{ 356 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 357 if (current) { 358 current->lastReport(nullptr); 359 } else { 360 globalReportCache = nullptr; 361 } 362} 363 364bool 365sc_report_handler::set_log_file_name(const char *new_name) 366{ 367 if (!new_name) { 368 logFile = nullptr; 369 logFileName = nullptr; 370 return false; 371 } else { 372 if (logFileName) 373 return false; 374 logFileName = std::unique_ptr<std::string>(new std::string(new_name)); 375 logFile = std::unique_ptr<std::ofstream>(new std::ofstream(new_name)); 376 return true; 377 } 378} 379 380const char * 381sc_report_handler::get_log_file_name() 382{ 383 if (!logFileName) 384 return nullptr; 385 else 386 return logFileName->c_str(); 387} 388 389void 390sc_interrupt_here(const char *msg_type, sc_severity) 391{ 392 // Purposefully empty, for setting breakpoints supposedly. 393} 394 395void 396sc_stop_here(const char *msg_type, sc_severity) 397{ 398 // Purposefully empty, for setting breakpoints supposedly. 399} 400 401const std::string 402sc_report_compose_message(const sc_report &report) 403{ 404 std::ostringstream str; 405 406 const char *sevName = severityNames[report.get_severity()]; 407 int id = report.get_id(); 408 409 str << sevName << ": "; 410 if (id >= 0) { 411 ccprintf(str, "(%c%d) ", sevName[0], id); 412 } 413 str << report.get_msg_type(); 414 415 const char *msg = report.get_msg(); 416 if (msg && msg[0]) 417 str << ": " << msg; 418 419 if (report.get_severity() > SC_INFO) { 420 ccprintf(str, "\nIn file: %s:%d", report.get_file_name(), 421 report.get_line_number()); 422 423 ::sc_gem5::Process *current = ::sc_gem5::scheduler.current(); 424 const char *name = report.get_process_name(); 425 if (current && sc_is_running() && name) { 426 ccprintf(str, "\nIn process: %s @ %s", name, 427 report.get_time().to_string()); 428 } 429 } 430 431 return str.str(); 432} 433 434bool 435sc_report_close_default_log() 436{ 437 if (logFile) { 438 logFile = nullptr; 439 logFileName = nullptr; 440 return false; 441 } 442 return true; 443} 444 445} // namespace sc_core 446