sc_report_handler.cc revision 13080:5b49b8664269
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