From: Willy Tarreau Date: Mon, 21 Oct 2024 16:34:21 +0000 (+0200) Subject: MINOR: debug: add a new debug macro COUNT_IF() X-Git-Tag: v3.1-dev11~87 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=da66c42f657855ec13f918ce37c9431cb2922e8d;p=thirdparty%2Fhaproxy.git MINOR: debug: add a new debug macro COUNT_IF() This macro works exactly like BUG_ON() except that it never logs anything nor crashes, it only implements an atomic counter that is incremented on every call. This can be used to count a number of unlikely events that are worth checking at run time on setups showing unusual and unreproducible behaviors. --- diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h index a08527dc70..556d8167ee 100644 --- a/include/haproxy/bug.h +++ b/include/haproxy/bug.h @@ -157,19 +157,21 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line) } while (0) #endif -/* Counting the number of matches on a given BUG_ON()/WARN_ON()/CHECK_IF() - * invocation requires a special section ("dbg_cnt") hence a modern +/* Counting the number of matches on a given BUG_ON()/WARN_ON()/CHECK_IF()/ + * COUNT_IF() invocation requires a special section ("dbg_cnt") hence a modern * linker. */ #if !defined(USE_OBSOLETE_LINKER) /* type of checks that can be verified. We cannot really distinguish between * BUG/WARN/CHECK_IF as they all pass through __BUG_ON() at a different level, - * but there's at least a difference between __BUG_ON() and __BUG_ON_ONCE(). + * but there's at least a difference between __BUG_ON() and __BUG_ON_ONCE() + * (and of course COUNT_IF). */ enum debug_counter_type { DBG_BUG, DBG_BUG_ONCE, + DBG_COUNT_IF, DBG_COUNTER_TYPES // must be last }; @@ -217,6 +219,16 @@ extern __attribute__((__weak__)) struct debug_count __stop_dbg_cnt HA_SECTION_S _HA_ATOMIC_INC(&__dbg_cnt_##_line.count); \ } while (0) +/* Core of the COUNT_IF() macro, checks the condition and counts one hit if + * true. + */ +#define _COUNT_IF(cond, file, line, ...) do { \ + (void)(unlikely(cond) ? ({ \ + __DBG_COUNT(cond, file, line, DBG_COUNT_IF, __VA_ARGS__); \ + 1; /* let's return the true condition */ \ + }) : 0); } while (0) + + #else /* USE_OBSOLETE_LINKER not defined below */ # define __DBG_COUNT(cond, file, line, type, ...) do { } while (0) # define _COUNT_IF(cond, file, line, ...) do { } while (0) @@ -297,26 +309,31 @@ extern __attribute__((__weak__)) struct debug_count __stop_dbg_cnt HA_SECTION_S # define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 2, "WARNING: bug ", " (not crashing but process is untrusted now, please report to developers)", __VA_ARGS__) # define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: warn ", " (please report to developers)", __VA_ARGS__) # define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) +# define COUNT_IF(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # elif !defined(DEBUG_STRICT_ACTION) || (DEBUG_STRICT_ACTION == 1) /* default level: BUG_ON() crashes, WARN_ON() warns, CHECK_IF() warns */ # define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) # define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 0, "WARNING: warn ", " (please report to developers)", __VA_ARGS__) # define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) +# define COUNT_IF(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION == 2) /* Stricter level: BUG_ON() crashes, WARN_ON() crashes, CHECK_IF() warns */ # define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) # define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: warn ", "", __VA_ARGS__) # define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) +# define COUNT_IF(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION >= 3) /* Developer/CI level: BUG_ON() crashes, WARN_ON() crashes, CHECK_IF() crashes */ # define BUG_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) # define WARN_ON(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 1, "FATAL: warn ", "", __VA_ARGS__) # define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ", "", __VA_ARGS__) +# define COUNT_IF(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # endif #else # define BUG_ON(cond, ...) do { (void)sizeof(cond); } while (0) # define WARN_ON(cond, ...) do { (void)sizeof(cond); } while (0) # define CHECK_IF(cond, ...) do { (void)sizeof(cond); } while (0) +# define COUNT_IF(cond, ...) do { (void)sizeof(cond); } while (0) #endif /* These macros are only for hot paths and remain disabled unless DEBUG_STRICT is 2 or above. @@ -328,18 +345,22 @@ extern __attribute__((__weak__)) struct debug_count __stop_dbg_cnt HA_SECTION_S /* Lowest level: BUG_ON() warns, CHECK_IF() warns */ # define BUG_ON_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 2, "WARNING: bug ", " (not crashing but process is untrusted now, please report to developers)", __VA_ARGS__) # define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) +# define COUNT_IF_HOT(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # elif !defined(DEBUG_STRICT_ACTION) || (DEBUG_STRICT_ACTION < 3) /* default level: BUG_ON() crashes, CHECK_IF() warns */ # define BUG_ON_HOT(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) # define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__) +# define COUNT_IF_HOT(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION >= 3) /* Developer/CI level: BUG_ON() crashes, CHECK_IF() crashes */ # define BUG_ON_HOT(cond, ...) _BUG_ON (cond, __FILE__, __LINE__, 3, "FATAL: bug ", "", __VA_ARGS__) # define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ", "", __VA_ARGS__) +# define COUNT_IF_HOT(cond, ...) _COUNT_IF (cond, __FILE__, __LINE__, __VA_ARGS__) # endif #else # define BUG_ON_HOT(cond, ...) do { (void)sizeof(cond) ; } while (0) # define CHECK_IF_HOT(cond, ...) do { (void)sizeof(cond) ; } while (0) +# define COUNT_IF_HOT(cond, ...) do { (void)sizeof(cond) ; } while (0) #endif