blob: d762026f2b3a3771a24dc7ab088b6e0d22ce151c [file] [log] [blame]
// Copyright (c) 2020, ARM Limited.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef FUNC_DEBUG_H
#define FUNC_DEBUG_H
#include "debug_types.h"
#include <assert.h>
#include <cinttypes>
#include <signal.h>
#include <stdio.h>
#include <string>
#include <vector>
void func_print_backtrace(FILE* out, int sig = SIGABRT);
void func_enable_signal_handlers();
// STRINGIFY2 is needed expand expression passed to STRINGIFY
#define STRINGIFY2(s) #s
#define STRINGIFY(s) STRINGIFY2(s)
// If TRACED_LOG is defined, add file:line to log messages
#if defined(TRACED_LOG)
#define WHERE "@" __FILE__ ":" STRINGIFY(__LINE__)
#else
#define WHERE
#endif
#if defined(COLORIZED_LOG)
#define COL(col, fmt) "\x1b[3" col "m" fmt "\x1b[0m"
#define COL_FATAL(fmt) COL("1;41", fmt)
#define COL_WARN(fmt) COL("1;43", fmt)
#define COL_INFO(fmt) COL("2", fmt)
#define COL_IFACE(fmt) fmt
#define COL_LOW(fmt) COL("35", fmt)
#define COL_MED(fmt) COL("2;33", fmt)
#define COL_HIGH(fmt) COL("2;32", fmt)
#else
#define COL_FATAL(fmt) fmt
#define COL_WARN(fmt) fmt
#define COL_INFO(fmt) fmt
#define COL_IFACE(fmt) fmt
#define COL_LOW(fmt) fmt
#define COL_MED(fmt) fmt
#define COL_HIGH(fmt) fmt
#endif
struct func_debug_t
{
uint32_t func_debug_verbosity = 0; // What verbosity level is set? (bitmask)
uint64_t func_debug_mask = 0; // Which units have debugging enabled? (bitmask)
uint64_t func_debug_inst_mask = 0; // Which instances have debugging enabled (bitmask)
uint64_t inst_id = 0; // The instance id for multiple model instances
FILE* func_debug_file = stderr; // Output file
bool is_output_unbuffered = false; // should log files be opened with unbuffered I/O.
int init_debug(uint64_t inst_id);
int fini_debug();
int set_file(const std::string& filename);
void set_mask(const std::string& str);
void set_mask(const uint64_t mask);
void print_masks(FILE* out);
void set_verbosity(const std::string& str);
void set_verbosity(const uint32_t verb);
void set_inst_mask(const char* mask);
void set_inst_mask(const uint64_t mask);
void set_output_unbuffered(const bool is_unbuffered);
std::string get_debug_mask_help_string();
std::string get_debug_verbosity_help_string();
};
#ifndef ASSERT
#define ASSERT(COND) \
if (!(COND)) \
{ \
fprintf(stderr, COL_FATAL("ASSERTION AT %s:%d %s(): (%s)\n"), __FILE__, __LINE__, __func__, #COND); \
func_print_backtrace(stderr); \
assert(COND); \
}
#endif
#ifndef ASSERT_MSG
#define ASSERT_MSG(COND, fmt, ...) \
if (!(COND)) \
{ \
fprintf(stderr, COL_FATAL("ASSERTION AT %s:%d %s(): (%s)\n"), __FILE__, __LINE__, __func__, #COND); \
fprintf(stderr, COL_FATAL(fmt) "\n", ##__VA_ARGS__); \
func_print_backtrace(stderr); \
assert(COND); \
}
#endif
#ifndef REQUIRE
#define REQUIRE(COND, fmt, ...) \
if (!(COND)) \
{ \
fprintf(g_func_debug.func_debug_file, COL_FATAL("REQUIRE() fails AT %s:%d %s(): (%s)\n"), __FILE__, __LINE__, \
__func__, #COND); \
fprintf(g_func_debug.func_debug_file, COL_FATAL(fmt) "\n", ##__VA_ARGS__); \
this->parent_sgt->setGraphStatus(GraphStatus::TOSA_UNPREDICTABLE); \
}
#endif
#ifndef ERROR_IF
#define ERROR_IF(COND, fmt, ...) \
if ((COND)) \
{ \
if (this->parent_sgt->getGraphStatus() != GraphStatus::TOSA_UNPREDICTABLE) \
{ \
this->parent_sgt->setGraphStatus(GraphStatus::TOSA_ERROR); \
} \
fprintf(g_func_debug.func_debug_file, COL_FATAL("ERROR_IF() fails AT %s:%d %s(): (%s)\n"), __FILE__, __LINE__, \
__func__, #COND); \
fprintf(g_func_debug.func_debug_file, COL_FATAL(fmt) "\n", ##__VA_ARGS__); \
this->dumpNode(g_func_debug.func_debug_file); \
func_print_backtrace(g_func_debug.func_debug_file); \
return 1; \
}
#endif
// Assertion specific to allocating memory
#ifndef ASSERT_MEM
#define ASSERT_MEM(OBJ) \
if (!(OBJ)) \
{ \
fprintf(stderr, COL_FATAL("ASSERTION AT %s:%d %s(): (" #OBJ "): out of memory\n"), __FILE__, __LINE__, \
__func__); \
func_print_backtrace(stderr); \
assert(OBJ); \
}
#endif
#ifndef FATAL_ERROR
#define FATAL_ERROR(fmt, ...) \
fprintf(stderr, COL_FATAL("FATAL ERROR AT %s:%d %s():\n"), __FILE__, __LINE__, __func__); \
fprintf(stderr, COL_FATAL(fmt) "\n", ##__VA_ARGS__); \
func_print_backtrace(stderr); \
abort();
#endif
void func_debug_warning(
func_debug_t* func_debug, const char* file, const char* func, const int line, const char* fmt, ...);
#ifndef WARNING
#define WARNING(...) func_debug_warning(&g_func_debug, __FILE__, __func__, __LINE__, __VA_ARGS__)
#endif
#ifndef WARNING_STDERR
#define WARNING_STDERR(fmt, ...) \
fprintf(stderr, COL_WARN("WARNING AT %s:%d %s():\n"), __FILE__, __LINE__, __func__); \
fprintf(stderr, COL_WARN(fmt) "\n", ##__VA_ARGS__);
#endif
// Is this debug verbosity and unit level enabled?
// Provide compiler hints that this is unlikely
// Two versions, depending on whether DEBUG_INSTANCE_EXPR is defined in a file or not
//
// For .cpp files whose units have discrete instance IDs, define DEBUG_INSTANCE_EXPR to evalute
// to the instance ID variable. The use of this define in header files is discouraged.
#ifdef DEBUG_INSTANCE_EXPR
// Expression for whether the debugging verbosity + debugging unit is enabled for free-form printouts
#ifdef DEBUG_INSTANCE_EXPR_2
#define DEBUG_ENABLED(VERB, LEVEL) \
(__builtin_expect((g_func_debug.func_debug_mask == DEBUG_ALL || g_func_debug.func_debug_mask & (DEBUG_##LEVEL)) && \
(g_func_debug.func_debug_inst_mask & (uint64_t(1) << (DEBUG_INSTANCE_EXPR))) && \
(g_func_debug.func_debug_verbosity & (VERB)), \
0))
// Debug printing macro
#define DEBUG(VERB, LEVEL, FMT, ...) \
if (DEBUG_ENABLED(VERB, LEVEL)) \
{ \
fprintf(g_func_debug.func_debug_file, "[%d:" #LEVEL "_%02d_%02d" WHERE "]: " FMT "\n", \
(int)g_func_debug.inst_id, (int)(DEBUG_INSTANCE_EXPR), (int)(DEBUG_INSTANCE_EXPR_2), ##__VA_ARGS__); \
}
// Prints just the debugging prefix for properly marking free-form printouts
#define DEBUG_PREFIX(LEVEL) \
fprintf(g_func_debug.func_debug_file, "[%d" #LEVEL "_%02d_%02d" WHERE "]: ", (int)g_func_debug.inst_id, \
(int)(DEBUG_INSTANCE_EXPR), (int)(DEBUG_INSTANCE_EXPR_2))
#else // !DEBUG_INSTANCE_EXPR_2
#define DEBUG_ENABLED(VERB, LEVEL) \
(__builtin_expect((g_func_debug.func_debug_mask == DEBUG_ALL || g_func_debug.func_debug_mask & (DEBUG_##LEVEL)) && \
(g_func_debug.func_debug_inst_mask & (uint64_t(1) << (DEBUG_INSTANCE_EXPR))) && \
(g_func_debug.func_debug_verbosity & (VERB)), \
0))
// Debug printing macro
#define DEBUG(VERB, LEVEL, FMT, ...) \
if (DEBUG_ENABLED(VERB, LEVEL)) \
{ \
fprintf(g_func_debug.func_debug_file, "[%d:" #LEVEL "_%02d" WHERE "]: " FMT "\n", (int)g_func_debug.inst_id, \
(int)(DEBUG_INSTANCE_EXPR), ##__VA_ARGS__); \
}
// Prints just the debugging prefix for properly marking free-form printouts
#define DEBUG_PREFIX(LEVEL) \
fprintf(g_func_debug.func_debug_file, "[%d:" #LEVEL "_%02d" WHERE "]: ", (int)g_func_debug.inst_id, \
(int)(DEBUG_INSTANCE_EXPR))
#endif // DEBUG_INSTANCE_EXPR_2
#else // !DEBUG_INSTANCE_EXPR
// Expression for whether the debugging verbosity + debugging unit is enabled for free-form printouts
#define DEBUG_ENABLED(VERB, LEVEL) \
(__builtin_expect((g_func_debug.func_debug_mask == DEBUG_ALL || g_func_debug.func_debug_mask & (DEBUG_##LEVEL)) && \
(g_func_debug.func_debug_verbosity & (VERB)), \
0))
// Debug printing macro
#define DEBUG(VERB, LEVEL, FMT, ...) \
if (DEBUG_ENABLED(VERB, LEVEL)) \
{ \
fprintf(g_func_debug.func_debug_file, "[%d:" #LEVEL WHERE "]: " FMT "\n", (int)g_func_debug.inst_id, \
##__VA_ARGS__); \
}
// Prints just the debugging prefix for properly marking free-form printouts
#define DEBUG_PREFIX(LEVEL) fprintf(g_func_debug.func_debug_file, "[" #LEVEL WHERE "]: ")
#endif
// Macros for different verbosity levels
#define DEBUG_INFO(LEVEL, FMT, ...) DEBUG(DEBUG_VERB_INFO, LEVEL, COL_INFO(FMT), ##__VA_ARGS__)
#define DEBUG_IFACE(LEVEL, FMT, ...) DEBUG(DEBUG_VERB_IFACE, LEVEL, COL_IFACE(FMT), ##__VA_ARGS__)
#define DEBUG_LOW(LEVEL, FMT, ...) DEBUG(DEBUG_VERB_LOW, LEVEL, COL_LOW(FMT), ##__VA_ARGS__)
#define DEBUG_MED(LEVEL, FMT, ...) DEBUG(DEBUG_VERB_MED, LEVEL, COL_MED(FMT), ##__VA_ARGS__)
#define DEBUG_HIGH(LEVEL, FMT, ...) DEBUG(DEBUG_VERB_HIGH, LEVEL, COL_HIGH(FMT), ##__VA_ARGS__)
#endif