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