1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
|
/*
* This file is part of the Score-P software ecosystem (http://www.score-p.org)
*
* Copyright (c) 2009-2012,
* RWTH Aachen University, Germany
*
* Copyright (c) 2009-2012,
* Gesellschaft fuer numerische Simulation mbH Braunschweig, Germany
*
* Copyright (c) 2009-2012, 2014,
* Technische Universitaet Dresden, Germany
*
* Copyright (c) 2009-2012,
* University of Oregon, Eugene, USA
*
* Copyright (c) 2009-2012, 2016, 2021-2022,
* Forschungszentrum Juelich GmbH, Germany
*
* Copyright (c) 2009-2012,
* German Research School for Simulation Sciences GmbH, Juelich/Aachen, Germany
*
* Copyright (c) 2009-2012,
* Technische Universitaet Muenchen, Germany
*
* This software may be modified and distributed under the terms of
* a BSD-style license. See the COPYING file in the package base
* directory for details.
*
*/
#ifndef UTILS_DEBUG_H
#define UTILS_DEBUG_H
/**
* @file
* @ingroup UTILS_Exception_module
*
* @brief Module for debug output handling in UTILS
*
*/
#include <stdint.h>
#include <stdio.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include <UTILS_Portability.h>
UTILS_BEGIN_C_DECLS
/**
* @defgroup UTILS_Exception_module SCOREP Debug and Error Handling
*
* This module provides an interface for error handling and debugging output.
*
* For invoke error handling, two macros are provided: @ref UTILS_ERROR for generic
* UTILS errors, and UTILS_ERROR_POSIX for handling errors occurred in posix calls.
* To handle an error, own error handlers can be registered using
* @ref UTILS_Error_RegisterCallback. The default error handler prints the error
* message to the standard error output.
*
* For debug output the macro @ref UTILS_DEBUG_PRINTF is provided. For each debug
* message, a debug level must be provided. The print out of the messages can be filtered
* depending on the debug level. By default, debug messages are printed to @c stdout;
* an alternative output stream can be set using @ref UTILS_Debug_SetLogStream.
* The second debug macro is @ref UTILS_ASSERT which ensures that a condition holds.
*
* The debug macros resolve to nothing if HAVE_UTILS_DEBUG is not defined or zero.
* Then no overhead and no debug output is created.
*
* @{
*/
/**
* List of debug levels. Every debug message printed with @ref
* UTILS_DEBUG_PRINTF must provide a debug level. Based on the debug
* level, the debug output can be filtered for the debugged parts. The debug level
* is a bitstring, where every level is represented by one bit. It is
* possible to combine several levels.
*/
enum
{
/*
* add new debug modules to the UTILS_DEBUG_MODULES list in
* src/config-custom.h
*/
#define UTILS_DEFINE_DEBUG_MODULE( name, bit ) \
PACKAGE_MANGLE_NAME( DEBUG_ ## name ) = ( UINT64_C( 1 ) << ( bit ) )
UTILS_DEBUG_MODULES
#undef UTILS_DEFINE_DEBUG_MODULE
};
/* internal flags */
#define UTILS_DEBUG_FUNCTION_ENTRY ( UINT64_C( 1 ) << 62 )
#define UTILS_DEBUG_FUNCTION_EXIT ( UINT64_C( 1 ) << 63 )
#define HAVE_UTILS_DEBUG UTILS_JOIN_SYMS( HAVE_, PACKAGE_MANGLE_NAME( DEBUG ) )
/**
* @def UTILS_DEBUG_PRINTF
* Following prep is the UTILS debug messaging function. It could be used like
* printf, but must get passed a debug level as first parameter. In difference
* to other debug message systems, the debug level is a bit mask where every
* level could be switched of and on individually. To set the correct debug level
* please use the enum UTILS_Debug_Levels.
*
* To set the current debug level, the source must not be recompiled. The current
* debug level bitmask could be set through adding the bit-values of the debug
* level which should be printed and assigning the result to the shell variable
* ${PACKAGE}_DEBUG. For example ${PACKAGE}_DEBUG=7 for debug level 1 and 2 and 4.
* @param debugLevel The debugLevel which must be enabled to print out the message.
* @param ... A format string followed by the parameters defined in the format
* string. The format string and the parameters have the same syntax
* like in the POSIX printf function.
*/
#if HAVE( UTILS_DEBUG )
/* *INDENT-OFF* */
#define UTILS_DEBUG_PRINTF( debugLevel, ... ) \
do \
{ \
if ( UTILS_Debug_IsEnabled( debugLevel ) ) \
{ \
UTILS_Debug_Printf( \
debugLevel, \
AFS_PACKAGE_SRCDIR, \
__FILE__, \
__LINE__, \
UTILS_FUNCTION_NAME, \
__VA_ARGS__ ); \
} \
} \
while ( 0 )
#define HAVE_DEBUG_MODULE_NAME_( sym ) defined( sym ## _DEBUG_MODULE_NAME )
#define HAVE_DEBUG_MODULE_NAME( sym ) HAVE_DEBUG_MODULE_NAME_( sym )
#if HAVE_DEBUG_MODULE_NAME( AFS_PACKAGE_NAME )
#define UTILS_DEBUG( ... ) \
do \
{ \
if ( UTILS_Debug_IsEnabled( UTILS_JOIN_SYMS( AFS_PACKAGE_NAME, \
UTILS_JOIN_SYMS( _DEBUG_, \
PACKAGE_MANGLE_NAME( DEBUG_MODULE_NAME ) ) ) ) ) \
{ \
UTILS_Debug_Printf( \
0, \
AFS_PACKAGE_SRCDIR, \
__FILE__, \
__LINE__, \
UTILS_FUNCTION_NAME, \
"" __VA_ARGS__ ); \
} \
} \
while ( 0 )
#define UTILS_DEBUG_ENTRY( ... ) \
do \
{ \
if ( UTILS_Debug_IsEnabled( UTILS_JOIN_SYMS( AFS_PACKAGE_NAME, \
UTILS_JOIN_SYMS( _DEBUG_, \
PACKAGE_MANGLE_NAME( DEBUG_MODULE_NAME ) ) ) ) ) \
{ \
UTILS_Debug_Printf( \
UTILS_DEBUG_FUNCTION_ENTRY, \
AFS_PACKAGE_SRCDIR, \
__FILE__, \
__LINE__, \
UTILS_FUNCTION_NAME, \
"" __VA_ARGS__ ); \
} \
} \
while ( 0 )
#define UTILS_DEBUG_EXIT( ... ) \
do \
{ \
if ( UTILS_Debug_IsEnabled( UTILS_JOIN_SYMS( AFS_PACKAGE_NAME, \
UTILS_JOIN_SYMS( _DEBUG_, \
PACKAGE_MANGLE_NAME( DEBUG_MODULE_NAME ) ) ) ) ) \
{ \
UTILS_Debug_Printf( \
UTILS_DEBUG_FUNCTION_EXIT, \
AFS_PACKAGE_SRCDIR, \
__FILE__, \
__LINE__, \
UTILS_FUNCTION_NAME, \
"" __VA_ARGS__ ); \
} \
} \
while ( 0 )
#else
#define UTILS_DEBUG( ... ) \
PACKAGE_MANGLE_NAME( DEBUG_MODULE_NAME ) = "You need to define a debug module name before including <UTILS_Debug.h>."
#define UTILS_DEBUG_ENTRY( ... ) \
PACKAGE_MANGLE_NAME( DEBUG_MODULE_NAME ) = "You need to define a debug module name before including <UTILS_Debug.h>."
#define UTILS_DEBUG_EXIT( ... ) \
PACKAGE_MANGLE_NAME( DEBUG_MODULE_NAME ) = "You need to define a debug module name before including <UTILS_Debug.h>."
#endif
/* *INDENT-ON* */
#else
#define UTILS_DEBUG_PRINTF( ... ) do { } while ( 0 )
#define UTILS_DEBUG( ... ) do { } while ( 0 )
#define UTILS_DEBUG_ENTRY( ... ) do { } while ( 0 )
#define UTILS_DEBUG_EXIT( ... ) do { } while ( 0 )
#endif /* HAVE_UTILS_DEBUG */
/**
* Use this to hide code, especially variables, which are only accessed in
* debug mode.
*
* @note You should not use a ';' after this statement. But ... needs to be a
* valid C statement including ';'.
*/
#if HAVE( UTILS_DEBUG )
#define UTILS_DEBUG_ONLY( ... ) __VA_ARGS__
#else
#define UTILS_DEBUG_ONLY( ... )
#endif /* HAVE_UTILS_DEBUG */
/**
* Set the output stream for debug messages to @p stream. Client code is
* responsible for properly opening/closing @p stream. Passing @c NULL
* resets the stream to @c stdout (the default).
*
* @param stream Valid output stream
*/
#define UTILS_Debug_SetLogStream PACKAGE_MANGLE_NAME( UTILS_Debug_SetLogStream )
void
UTILS_Debug_SetLogStream( FILE* stream );
/**
* Checks whether the given debug level is enabled.
*
* @param bitMask The debug level to be tested.
* @return Returns @c true if enabled, @c false otherwise.
*/
#define UTILS_Debug_IsEnabled PACKAGE_MANGLE_NAME( UTILS_Debug_IsEnabled )
static inline bool
UTILS_Debug_IsEnabled( uint64_t bitMask )
{
/* Internal variables set by `utils_debug_init` -- read only! */
#define utils_debug_initialized PACKAGE_MANGLE_name( utils_debug_initialized )
#define utils_debug_level PACKAGE_MANGLE_name( utils_debug_level )
extern bool utils_debug_initialized;
extern uint64_t utils_debug_level;
if ( !utils_debug_initialized )
{
#define utils_debug_init PACKAGE_MANGLE_name( utils_debug_init )
extern void utils_debug_init( void );
utils_debug_init();
}
bitMask &= ~( UTILS_DEBUG_FUNCTION_ENTRY | UTILS_DEBUG_FUNCTION_EXIT );
return ( utils_debug_level & bitMask ) == bitMask;
}
/**
* Function implementation called by @ref UTILS_DEBUG_PRINTF. It prints a debug message
* in the given debug level. Furthermore, it provides the function name, file name and
* line number.
* @param kind The "kind" part of the debug level (zero, UTILS_DEBUG_FUNCTION_ENTRY,
* or UTILS_DEBUG_FUNCTION_EXIT; all other bits are ignored).
* @param function A string containing the name of the function where the debug messages
* was called.
* @param file The file name of the file which contains the source code where the
* message was created.
* @param line The line number of the source code line where the debug message
* was created.
* @param msgFormatString A format string followed by the parameters defined in
* the format string. The format string and the
* parameters have the same syntax like in the POSIX
* printf function.
*/
#define UTILS_Debug_Printf PACKAGE_MANGLE_NAME( UTILS_Debug_Printf )
void
UTILS_Debug_Printf( uint64_t kind,
const char* srcdir,
const char* file,
uint64_t line,
const char* function,
const char* msgFormatString,
... );
UTILS_END_C_DECLS
/** @} */
#if defined( __cplusplus )
#include <UTILS_DebugStream.hpp>
#endif
#endif /* UTILS_DEBUG_H */
|