100 строки
4.3 KiB
C
100 строки
4.3 KiB
C
/*!
|
|
* Copyright (c) 2018 by Contributors
|
|
* \file logging.h
|
|
* \brief logging utilities on top of dmlc-core
|
|
*/
|
|
#ifndef TVM_LOGGING_H_
|
|
#define TVM_LOGGING_H_
|
|
|
|
// a technique that enables overriding macro names on the number of parameters. This is used
|
|
// to define other macros below
|
|
#define GET_MACRO(_1, _2, _3, _4, _5, NAME, ...) NAME
|
|
|
|
/*!
|
|
* \brief COND_X calls COND_X_N where N is the number of parameters passed to COND_X
|
|
* X can be any of CHECK_GE, CHECK_EQ, CHECK, or LOG (defined dmlc-core/include/dmlc/logging.h.)
|
|
* COND_X (but not COND_X_N) are supposed to be used outside this file.
|
|
* The first parameter of COND_X (and therefore, COND_X_N), which we call 'quit_on_assert',
|
|
* is a boolean. The rest of the parameters of COND_X is the same as the parameters of X.
|
|
* quit_on_assert determines the overall behaviour of COND_X. If it's true COND_X
|
|
* quits the program on assertion failure. If it's false, then it moves on and somehow reports
|
|
* the assertion failure back to the macro caller in an appropriate manner (e.g, 'return false'
|
|
* in a function, or 'continue' or 'break' in a loop)
|
|
* The default behavior when quit_on_assertion is false, is to 'return false'. If this is not
|
|
* desirable, the macro caller can pass one more last parameter to COND_X to tell COND_X what
|
|
* to do when when quit_on_assertion is false and the assertion fails.
|
|
*
|
|
* Rationale: These macros were designed to implement functions that have two behaviours
|
|
* in a concise way. Those behaviours are quitting on assertion failures, or trying to
|
|
* move on from assertion failures. Note that these macros hide lots of control flow in them,
|
|
* and therefore, makes the logic of the whole code slightly harder to understand. However,
|
|
* in pieces of code that use these macros frequently, it will significantly shorten the
|
|
* amount of code needed to be read, and we won't need to clutter the main logic of the
|
|
* function by repetitive control flow structure. The first problem
|
|
* mentioned will be improved over time as the developer gets used to the macro.
|
|
*
|
|
* Here is an example of how to use it
|
|
* \code
|
|
* bool f(..., bool quit_on_assertion) {
|
|
* int a = 0, b = 0;
|
|
* ...
|
|
* a = ...
|
|
* b = ...
|
|
* // if quit_on_assertion is true, if a==b, continue, otherwise quit.
|
|
* // if quit_on_assertion is false, if a==b, continue, otherwise 'return false' (default behaviour)
|
|
* COND_CHECK_EQ(quit_on_assertion, a, b) << "some error message when quiting"
|
|
* ...
|
|
* for (int i = 0; i < N; i++) {
|
|
* a = ...
|
|
* b = ...
|
|
* // if quit_on_assertion is true, if a==b, continue, otherwise quit.
|
|
* // if quit_on_assertion is false, if a==b, continue, otherwise 'break' (non-default
|
|
* // behaviour, therefore, has to be explicitly specified)
|
|
* COND_CHECK_EQ(quit_on_assertion, a, b, break) << "some error message when quiting"
|
|
* }
|
|
* }
|
|
* \endcode
|
|
*/
|
|
#define COND_CHECK_GE(...) \
|
|
GET_MACRO(__VA_ARGS__, COND_CHECK_GE_5, COND_CHECK_GE_4, COND_CHECK_GE_3)(__VA_ARGS__)
|
|
#define COND_CHECK_EQ(...) \
|
|
GET_MACRO(__VA_ARGS__, COND_CHECK_EQ_5, COND_CHECK_EQ_4, COND_CHECK_EQ_3)(__VA_ARGS__)
|
|
#define COND_CHECK(...) \
|
|
GET_MACRO(__VA_ARGS__, COND_CHECK_5, COND_CHECK_4, COND_CHECK_3, COND_CHECK_2)(__VA_ARGS__)
|
|
#define COND_LOG(...) \
|
|
GET_MACRO(__VA_ARGS__, COND_LOG_5, COND_LOG_4, COND_LOG_3, COND_LOG_2)(__VA_ARGS__)
|
|
|
|
// Not supposed to be used by users directly.
|
|
#define COND_CHECK_OP(quit_on_assert, x, y, what, op) \
|
|
if (!quit_on_assert) { \
|
|
if (!((x) op (y))) \
|
|
what; \
|
|
} \
|
|
else /* NOLINT(*) */ \
|
|
CHECK_##op(x, y)
|
|
|
|
#define COND_CHECK_EQ_4(quit_on_assert, x, y, what) COND_CHECK_OP(quit_on_assert, x, y, what, ==)
|
|
#define COND_CHECK_GE_4(quit_on_assert, x, y, what) COND_CHECK_OP(quit_on_assert, x, y, what, >=)
|
|
|
|
#define COND_CHECK_3(quit_on_assert, x, what) \
|
|
if (!quit_on_assert) { \
|
|
if (!(x)) \
|
|
what; \
|
|
} \
|
|
else /* NOLINT(*) */ \
|
|
CHECK(x)
|
|
|
|
#define COND_LOG_3(quit_on_assert, x, what) \
|
|
if (!quit_on_assert) { \
|
|
what; \
|
|
} \
|
|
else /* NOLINT(*) */ \
|
|
LOG(x)
|
|
|
|
#define COND_CHECK_EQ_3(quit_on_assert, x, y) COND_CHECK_EQ_4(quit_on_assert, x, y, return false)
|
|
#define COND_CHECK_GE_3(quit_on_assert, x, y) COND_CHECK_GE_4(quit_on_assert, x, y, return false)
|
|
#define COND_CHECK_2(quit_on_assert, x) COND_CHECK_3(quit_on_assert, x, return false)
|
|
#define COND_LOG_2(quit_on_assert, x) COND_LOG_3(quit_on_assert, x, return false)
|
|
|
|
#endif // TVM_LOGGING_H_
|