logging.hh revision 12334
112334Sgabeblack@google.com/*
212334Sgabeblack@google.com * Copyright (c) 2014, 2017 ARM Limited
312334Sgabeblack@google.com * All rights reserved
412334Sgabeblack@google.com *
512334Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612334Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712334Sgabeblack@google.com * property including but not limited to intellectual property relating
812334Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912334Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012334Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112334Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212334Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312334Sgabeblack@google.com *
1412334Sgabeblack@google.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
1512334Sgabeblack@google.com * All rights reserved.
1612334Sgabeblack@google.com *
1712334Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1812334Sgabeblack@google.com * modification, are permitted provided that the following conditions are
1912334Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
2012334Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
2112334Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
2212334Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2312334Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2412334Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2512334Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2612334Sgabeblack@google.com * this software without specific prior written permission.
2712334Sgabeblack@google.com *
2812334Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2912334Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3012334Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3112334Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3212334Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3312334Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3412334Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3512334Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3612334Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3712334Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3812334Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3912334Sgabeblack@google.com *
4012334Sgabeblack@google.com * Authors: Nathan Binkert
4112334Sgabeblack@google.com *          Dave Greene
4212334Sgabeblack@google.com *          Andreas Sandberg
4312334Sgabeblack@google.com */
4412334Sgabeblack@google.com
4512334Sgabeblack@google.com#ifndef __BASE_LOGGING_HH__
4612334Sgabeblack@google.com#define __BASE_LOGGING_HH__
4712334Sgabeblack@google.com
4812334Sgabeblack@google.com#include <cassert>
4912334Sgabeblack@google.com#include <cstdlib>
5012334Sgabeblack@google.com#include <iostream>
5112334Sgabeblack@google.com#include <utility>
5212334Sgabeblack@google.com
5312334Sgabeblack@google.com#include "base/compiler.hh"
5412334Sgabeblack@google.com#include "base/cprintf.hh"
5512334Sgabeblack@google.com
5612334Sgabeblack@google.com#if defined(__SUNPRO_CC)
5712334Sgabeblack@google.com#define __FUNCTION__ "how to fix me?"
5812334Sgabeblack@google.com#endif
5912334Sgabeblack@google.com
6012334Sgabeblack@google.comclass Logger
6112334Sgabeblack@google.com{
6212334Sgabeblack@google.com  public:
6312334Sgabeblack@google.com    enum LogLevel {
6412334Sgabeblack@google.com        PANIC = 0,
6512334Sgabeblack@google.com        FATAL,
6612334Sgabeblack@google.com        WARN,
6712334Sgabeblack@google.com        INFO,
6812334Sgabeblack@google.com        HACK,
6912334Sgabeblack@google.com        NUM_LOG_LEVELS,
7012334Sgabeblack@google.com    };
7112334Sgabeblack@google.com
7212334Sgabeblack@google.com    /**
7312334Sgabeblack@google.com     * Set the active log level.
7412334Sgabeblack@google.com     *
7512334Sgabeblack@google.com     * All levels that are lower or equal to the selected log level
7612334Sgabeblack@google.com     * will be activated.
7712334Sgabeblack@google.com     *
7812334Sgabeblack@google.com     * @param ll Maximum log level to print
7912334Sgabeblack@google.com     */
8012334Sgabeblack@google.com    static void setLevel(LogLevel ll);
8112334Sgabeblack@google.com
8212334Sgabeblack@google.com    /**
8312334Sgabeblack@google.com     * Get a Logger corresponding to a specific log level
8412334Sgabeblack@google.com     *
8512334Sgabeblack@google.com     * @param ll Log level to access
8612334Sgabeblack@google.com     * @return Reference to the requested logger
8712334Sgabeblack@google.com     */
8812334Sgabeblack@google.com    static Logger &get(LogLevel ll);
8912334Sgabeblack@google.com
9012334Sgabeblack@google.com  public:
9112334Sgabeblack@google.com    Logger(std::ostream &stream, const char *prefix);
9212334Sgabeblack@google.com    virtual ~Logger() {};
9312334Sgabeblack@google.com
9412334Sgabeblack@google.com    template<typename ...Args> void
9512334Sgabeblack@google.com    print(const char *func, const char *file, int line,
9612334Sgabeblack@google.com          const char *format, const Args &...args)
9712334Sgabeblack@google.com    {
9812334Sgabeblack@google.com        if (!enabled)
9912334Sgabeblack@google.com            return;
10012334Sgabeblack@google.com
10112334Sgabeblack@google.com        if (prefix)
10212334Sgabeblack@google.com            stream << prefix << ": ";
10312334Sgabeblack@google.com        ccprintf(stream, format, args...);
10412334Sgabeblack@google.com
10512334Sgabeblack@google.com        printEpilogue(func, file, line, format);
10612334Sgabeblack@google.com    }
10712334Sgabeblack@google.com
10812334Sgabeblack@google.com    template<typename ...Args> void
10912334Sgabeblack@google.com    print(const char *func, const char *file, int line,
11012334Sgabeblack@google.com          const std::string &format, const Args &...args)
11112334Sgabeblack@google.com    {
11212334Sgabeblack@google.com        print(func, file, line, format.c_str(), args...);
11312334Sgabeblack@google.com    }
11412334Sgabeblack@google.com
11512334Sgabeblack@google.com  protected:
11612334Sgabeblack@google.com    virtual void printEpilogue(const char *func, const char *file, int line,
11712334Sgabeblack@google.com                               const char *format);
11812334Sgabeblack@google.com
11912334Sgabeblack@google.com  public:
12012334Sgabeblack@google.com    bool enabled;
12112334Sgabeblack@google.com    bool verbose;
12212334Sgabeblack@google.com
12312334Sgabeblack@google.com  protected:
12412334Sgabeblack@google.com    std::ostream &stream;
12512334Sgabeblack@google.com    const char *prefix;
12612334Sgabeblack@google.com};
12712334Sgabeblack@google.com
12812334Sgabeblack@google.com#define exit_message(logger, code, ...)                                 \
12912334Sgabeblack@google.com    do {                                                                \
13012334Sgabeblack@google.com        logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);    \
13112334Sgabeblack@google.com        if (code < 0)                                                   \
13212334Sgabeblack@google.com            ::abort();                                                  \
13312334Sgabeblack@google.com        else                                                            \
13412334Sgabeblack@google.com            ::exit(code);                                               \
13512334Sgabeblack@google.com    } while (0)
13612334Sgabeblack@google.com
13712334Sgabeblack@google.com//
13812334Sgabeblack@google.com// This implements a cprintf based panic() function.  panic() should
13912334Sgabeblack@google.com// be called when something happens that should never ever happen
14012334Sgabeblack@google.com// regardless of what the user does (i.e., an acutal m5 bug).  panic()
14112334Sgabeblack@google.com// calls abort which can dump core or enter the debugger.
14212334Sgabeblack@google.com//
14312334Sgabeblack@google.com//
14412334Sgabeblack@google.com#define panic(...) exit_message(::Logger::get(::Logger::PANIC), -1, \
14512334Sgabeblack@google.com                                __VA_ARGS__)
14612334Sgabeblack@google.com
14712334Sgabeblack@google.com//
14812334Sgabeblack@google.com// This implements a cprintf based fatal() function.  fatal() should
14912334Sgabeblack@google.com// be called when the simulation cannot continue due to some condition
15012334Sgabeblack@google.com// that is the user's fault (bad configuration, invalid arguments,
15112334Sgabeblack@google.com// etc.) and not a simulator bug.  fatal() calls  abort() like
15212334Sgabeblack@google.com// panic() does.
15312334Sgabeblack@google.com//
15412334Sgabeblack@google.com#define fatal(...) exit_message(::Logger::get(::Logger::FATAL), 1, \
15512334Sgabeblack@google.com                                __VA_ARGS__)
15612334Sgabeblack@google.com
15712334Sgabeblack@google.com/**
15812334Sgabeblack@google.com * Conditional panic macro that checks the supplied condition and only panics
15912334Sgabeblack@google.com * if the condition is true and allows the programmer to specify diagnostic
16012334Sgabeblack@google.com * printout.  Useful to replace if + panic, or if + print + assert, etc.
16112334Sgabeblack@google.com *
16212334Sgabeblack@google.com * @param cond Condition that is checked; if true -> panic
16312334Sgabeblack@google.com * @param ...  Printf-based format string with arguments, extends printout.
16412334Sgabeblack@google.com */
16512334Sgabeblack@google.com#define panic_if(cond, ...)                                  \
16612334Sgabeblack@google.com    do {                                                     \
16712334Sgabeblack@google.com        if ((cond)) {                                        \
16812334Sgabeblack@google.com            panic("panic condition " # cond " occurred: %s", \
16912334Sgabeblack@google.com                  csprintf(__VA_ARGS__));                    \
17012334Sgabeblack@google.com        }                                                    \
17112334Sgabeblack@google.com    } while (0)
17212334Sgabeblack@google.com
17312334Sgabeblack@google.com
17412334Sgabeblack@google.com/**
17512334Sgabeblack@google.com * Conditional fatal macro that checks the supplied condition and only causes a
17612334Sgabeblack@google.com * fatal error if the condition is true and allows the programmer to specify
17712334Sgabeblack@google.com * diagnostic printout.  Useful to replace if + fatal, or if + print + assert,
17812334Sgabeblack@google.com * etc.
17912334Sgabeblack@google.com *
18012334Sgabeblack@google.com * @param cond Condition that is checked; if true -> fatal
18112334Sgabeblack@google.com * @param ...  Printf-based format string with arguments, extends printout.
18212334Sgabeblack@google.com */
18312334Sgabeblack@google.com#define fatal_if(cond, ...)                                     \
18412334Sgabeblack@google.com    do {                                                        \
18512334Sgabeblack@google.com        if ((cond)) {                                           \
18612334Sgabeblack@google.com            fatal("fatal condition " # cond " occurred: %s",    \
18712334Sgabeblack@google.com                  csprintf(__VA_ARGS__));                       \
18812334Sgabeblack@google.com        }                                                       \
18912334Sgabeblack@google.com    } while (0)
19012334Sgabeblack@google.com
19112334Sgabeblack@google.com
19212334Sgabeblack@google.com#define base_message(logger, ...)                                       \
19312334Sgabeblack@google.com    logger.print(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
19412334Sgabeblack@google.com
19512334Sgabeblack@google.com// Only print the message the first time this expression is
19612334Sgabeblack@google.com// encountered.  i.e.  This doesn't check the string itself and
19712334Sgabeblack@google.com// prevent duplicate strings, this prevents the statement from
19812334Sgabeblack@google.com// happening more than once. So, even if the arguments change and that
19912334Sgabeblack@google.com// would have resulted in a different message thoes messages would be
20012334Sgabeblack@google.com// supressed.
20112334Sgabeblack@google.com#define base_message_once(...) do {                     \
20212334Sgabeblack@google.com        static bool once = false;                       \
20312334Sgabeblack@google.com        if (!once) {                                    \
20412334Sgabeblack@google.com            base_message(__VA_ARGS__);                  \
20512334Sgabeblack@google.com            once = true;                                \
20612334Sgabeblack@google.com        }                                               \
20712334Sgabeblack@google.com    } while (0)
20812334Sgabeblack@google.com
20912334Sgabeblack@google.com
21012334Sgabeblack@google.com#define warn(...) \
21112334Sgabeblack@google.com    base_message(::Logger::get(::Logger::WARN), __VA_ARGS__)
21212334Sgabeblack@google.com#define inform(...) \
21312334Sgabeblack@google.com    base_message(::Logger::get(::Logger::INFO), __VA_ARGS__)
21412334Sgabeblack@google.com#define hack(...) \
21512334Sgabeblack@google.com    base_message(::Logger::get(::Logger::HACK), __VA_ARGS__)
21612334Sgabeblack@google.com
21712334Sgabeblack@google.com#define warn_once(...) \
21812334Sgabeblack@google.com    base_message_once(::Logger::get(::Logger::WARN), __VA_ARGS__)
21912334Sgabeblack@google.com#define inform_once(...) \
22012334Sgabeblack@google.com    base_message_once(::Logger::get(::Logger::INFO), __VA_ARGS__)
22112334Sgabeblack@google.com#define hack_once(...) \
22212334Sgabeblack@google.com    base_message_once(::Logger::get(::Logger::HACK), __VA_ARGS__)
22312334Sgabeblack@google.com
22412334Sgabeblack@google.com/**
22512334Sgabeblack@google.com * Conditional warning macro that checks the supplied condition and
22612334Sgabeblack@google.com * only prints a warning if the condition is true. Useful to replace
22712334Sgabeblack@google.com * if + warn.
22812334Sgabeblack@google.com *
22912334Sgabeblack@google.com * @param cond Condition that is checked; if true -> warn
23012334Sgabeblack@google.com * @param ...  Printf-based format string with arguments, extends printout.
23112334Sgabeblack@google.com */
23212334Sgabeblack@google.com#define warn_if(cond, ...) \
23312334Sgabeblack@google.com    do { \
23412334Sgabeblack@google.com        if ((cond)) \
23512334Sgabeblack@google.com            warn(__VA_ARGS__); \
23612334Sgabeblack@google.com    } while (0)
23712334Sgabeblack@google.com
23812334Sgabeblack@google.com/**
23912334Sgabeblack@google.com * The chatty assert macro will function like a normal assert, but will allow
24012334Sgabeblack@google.com * the specification of additional, helpful material to aid debugging why the
24112334Sgabeblack@google.com * assertion actually failed.  Like the normal assertion, the chatty_assert
24212334Sgabeblack@google.com * will not be active in fast builds.
24312334Sgabeblack@google.com *
24412334Sgabeblack@google.com * @param cond Condition that is checked; if false -> assert
24512334Sgabeblack@google.com * @param ...  Printf-based format string with arguments, extends printout.
24612334Sgabeblack@google.com */
24712334Sgabeblack@google.com#ifdef NDEBUG
24812334Sgabeblack@google.com#define chatty_assert(cond, ...)
24912334Sgabeblack@google.com#else //!NDEBUG
25012334Sgabeblack@google.com#define chatty_assert(cond, ...)                                        \
25112334Sgabeblack@google.com    do {                                                                \
25212334Sgabeblack@google.com        if (!(cond))                                                    \
25312334Sgabeblack@google.com            panic("assert(" # cond ") failed: %s", csprintf(__VA_ARGS__)); \
25412334Sgabeblack@google.com    } while (0)
25512334Sgabeblack@google.com#endif // NDEBUG
25612334Sgabeblack@google.com#endif // __BASE_LOGGING_HH__
257