From 27061cd1446d1445cd9e0b739b6459e5bde5e5d2 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 23 Jun 2022 10:54:17 +0200 Subject: [PATCH] MEDIUM: debug: improve DEBUG_MEM_STATS to also report pool alloc/free Sometimes using "debug dev memstats" can be frustrating because all pool allocations are reported through pool-os.h and that's all. But in practice there's nothing wrong with also intercepting pool_alloc, pool_free and pool_zalloc and report their call counts and locations, so that's what this patch does. It only uses an alternate set of macroes for these 3 calls when DEBUG_MEM_STATS is defined. The outputs are reported as P_ALLOC (for both pool_malloc() and pool_zalloc()) and P_FREE (for pool_free()). --- include/haproxy/bug.h | 2 ++ include/haproxy/pool.h | 51 ++++++++++++++++++++++++++++++++++++++++++ src/debug.c | 2 ++ 3 files changed, 55 insertions(+) diff --git a/include/haproxy/bug.h b/include/haproxy/bug.h index ce83536ea..6a75177e1 100644 --- a/include/haproxy/bug.h +++ b/include/haproxy/bug.h @@ -233,6 +233,8 @@ enum { MEM_STATS_TYPE_MALLOC, MEM_STATS_TYPE_REALLOC, MEM_STATS_TYPE_STRDUP, + MEM_STATS_TYPE_P_ALLOC, + MEM_STATS_TYPE_P_FREE, }; struct mem_stats { diff --git a/include/haproxy/pool.h b/include/haproxy/pool.h index a13d0eb7c..3640ad112 100644 --- a/include/haproxy/pool.h +++ b/include/haproxy/pool.h @@ -224,6 +224,8 @@ static inline void *pool_get_from_cache(struct pool_head *pool, const void *call /****************** Common high-level code ******************/ +#if !defined(DEBUG_MEM_STATS) + /* * Returns a pointer to type taken from the pool or * dynamically allocated. Memory poisonning is performed if enabled. @@ -247,6 +249,55 @@ static inline void *pool_get_from_cache(struct pool_head *pool, const void *call __pool_free(pool, __ptr); \ } while (0) + +#else /* DEBUG_MEM_STATS is set below */ + +#define pool_free(pool, ptr) ({ \ + struct pool_head *__pool = (pool); \ + typeof(ptr) __ptr = (ptr); \ + static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ + .file = __FILE__, .line = __LINE__, \ + .type = MEM_STATS_TYPE_P_FREE, \ + }; \ + HA_WEAK("__start_mem_stats"); \ + HA_WEAK("__stop_mem_stats"); \ + if (__ptr) { \ + _HA_ATOMIC_INC(&_.calls); \ + _HA_ATOMIC_ADD(&_.size, __pool->size); \ + __pool_free(__pool, __ptr); \ + } \ +}) + +#define pool_alloc(pool) ({ \ + struct pool_head *__pool = (pool); \ + size_t __x = __pool->size; \ + static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ + .file = __FILE__, .line = __LINE__, \ + .type = MEM_STATS_TYPE_P_ALLOC, \ + }; \ + HA_WEAK("__start_mem_stats"); \ + HA_WEAK("__stop_mem_stats"); \ + _HA_ATOMIC_INC(&_.calls); \ + _HA_ATOMIC_ADD(&_.size, __x); \ + __pool_alloc(__pool, 0); \ +}) + +#define pool_zalloc(pool) ({ \ + struct pool_head *__pool = (pool); \ + size_t __x = __pool->size; \ + static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ + .file = __FILE__, .line = __LINE__, \ + .type = MEM_STATS_TYPE_P_ALLOC, \ + }; \ + HA_WEAK("__start_mem_stats"); \ + HA_WEAK("__stop_mem_stats"); \ + _HA_ATOMIC_INC(&_.calls); \ + _HA_ATOMIC_ADD(&_.size, __x); \ + __pool_alloc(__pool, POOL_F_MUST_ZERO); \ +}) + +#endif /* DEBUG_MEM_STATS */ + #endif /* _HAPROXY_POOL_H */ /* diff --git a/src/debug.c b/src/debug.c index 9c23d8a75..308af6710 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1269,6 +1269,8 @@ static int debug_iohandler_memstats(struct appctx *appctx) case MEM_STATS_TYPE_MALLOC: type = "MALLOC"; break; case MEM_STATS_TYPE_REALLOC: type = "REALLOC"; break; case MEM_STATS_TYPE_STRDUP: type = "STRDUP"; break; + case MEM_STATS_TYPE_P_ALLOC: type = "P_ALLOC"; break; + case MEM_STATS_TYPE_P_FREE: type = "P_FREE"; break; default: type = "UNSET"; break; }