From 8fb5ae5cc66259a616de736d94749b63acda3d4d Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 11 Sep 2025 15:36:13 +0200 Subject: [PATCH] MINOR: activity/memory: count allocations performed under a lock By checking the current thread's locking status, it becomes possible to know during a memory allocation whether it's performed under a lock or not. Both pools and memprofile functions were instrumented to check for this and to increment the memprofile bin's locked_calls counter. This one, when not zero, is reported on "show profiling memory" with a percentage of all allocations that such locked allocations represent. This way it becomes possible to try to target certain code paths that are particularly expensive. Example: $ socat - /tmp/sock1 <<< "show profiling memory"|grep lock 20297301 0 2598054528 0| 0x62a820fa3991 sockaddr_alloc+0x61/0xa3 p_alloc(128) [pool=sockaddr] [locked=54962 (0.2 %)] 0 20297301 0 2598054528| 0x62a820fa3a24 sockaddr_free+0x44/0x59 p_free(-128) [pool=sockaddr] [locked=34300 (0.1 %)] 9908432 0 1268279296 0| 0x62a820eb8524 main+0x81974 p_alloc(128) [pool=task] [locked=9908432 (100.0 %)] 9908432 0 554872192 0| 0x62a820eb85a6 main+0x819f6 p_alloc(56) [pool=tasklet] [locked=9908432 (100.0 %)] 263001 0 63120240 0| 0x62a820fa3c97 conn_new+0x37/0x1b2 p_alloc(240) [pool=connection] [locked=20662 (7.8 %)] 71643 0 47307584 0| 0x62a82105204d pool_get_from_os_noinc+0x12d/0x161 posix_memalign(660) [locked=5393 (7.5 %)] --- include/haproxy/activity-t.h | 2 +- src/activity.c | 32 ++++++++++++++++++++++++++++++++ src/pool.c | 6 +++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/include/haproxy/activity-t.h b/include/haproxy/activity-t.h index ba9241d03..f7ea1f130 100644 --- a/include/haproxy/activity-t.h +++ b/include/haproxy/activity-t.h @@ -76,12 +76,12 @@ struct memprof_stats { const void *caller; enum memprof_method method; /* 4-7 bytes hole here */ + unsigned long long locked_calls; unsigned long long alloc_calls; unsigned long long free_calls; unsigned long long alloc_tot; unsigned long long free_tot; void *info; // for pools, ptr to the pool - void *pad; // pad to 64 }; #endif diff --git a/src/activity.c b/src/activity.c index ad4d60d8b..9f6bd6162 100644 --- a/src/activity.c +++ b/src/activity.c @@ -342,6 +342,8 @@ void *malloc(size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_MALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -367,6 +369,8 @@ void *calloc(size_t nmemb, size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_CALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -400,6 +404,8 @@ void *realloc(void *ptr, size_t size) size += sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_REALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); if (size > size_before) { _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size - size_before); @@ -431,6 +437,8 @@ char *strdup(const char *s) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_STRDUP); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -461,6 +469,8 @@ void free(void *ptr) memprof_free_handler(ptr); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_FREE); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->free_calls, 1); _HA_ATOMIC_ADD(&bin->free_tot, size_before); } @@ -481,6 +491,8 @@ char *strndup(const char *s, size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_STRNDUP); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -500,6 +512,8 @@ void *valloc(size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_VALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -519,6 +533,8 @@ void *pvalloc(size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_PVALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -538,6 +554,8 @@ void *memalign(size_t align, size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_MEMALIGN); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -557,6 +575,8 @@ void *aligned_alloc(size_t align, size_t size) size = malloc_usable_size(ret) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_ALIGNED_ALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -579,6 +599,8 @@ int posix_memalign(void **ptr, size_t align, size_t size) size = malloc_usable_size(*ptr) + sizeof(void *); bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_POSIX_MEMALIGN); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, size); return ret; @@ -715,6 +737,7 @@ static int cli_parse_set_profiling(char **args, char *payload, struct appctx *ap /* also flush current profiling stats */ for (i = 0; i < sizeof(memprof_stats) / sizeof(memprof_stats[0]); i++) { + HA_ATOMIC_STORE(&memprof_stats[i].locked_calls, 0); HA_ATOMIC_STORE(&memprof_stats[i].alloc_calls, 0); HA_ATOMIC_STORE(&memprof_stats[i].free_calls, 0); HA_ATOMIC_STORE(&memprof_stats[i].alloc_tot, 0); @@ -1125,6 +1148,15 @@ static int cli_io_handler_show_profiling(struct appctx *appctx) chunk_appendf(&trash," [pool=%s]", pool->name); } + if (entry->locked_calls) { + unsigned long long tot_calls = entry->alloc_calls + entry->free_calls; + + chunk_appendf(&trash," [locked=%llu (%d.%1d %%)]", + entry->locked_calls, + (int)(100ULL * entry->locked_calls / tot_calls), + (int)((1000ULL * entry->locked_calls / tot_calls) % 10)); + } + chunk_appendf(&trash, "\n"); if (applet_putchk(appctx, &trash) == -1) diff --git a/src/pool.c b/src/pool.c index d824b2b93..bcfb4fdc7 100644 --- a/src/pool.c +++ b/src/pool.c @@ -953,7 +953,7 @@ void pool_gc(struct pool_head *pool_ctx) uint64_t mem_wait_start = 0; int isolated = thread_isolated(); - if (th_ctx->flags & TH_FL_TASK_PROFILING) + if (unlikely(th_ctx->flags & TH_FL_TASK_PROFILING)) mem_wait_start = now_mono_time(); if (!isolated) @@ -1031,6 +1031,8 @@ void *__pool_alloc(struct pool_head *pool, unsigned int flags) struct memprof_stats *bin; bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_P_ALLOC); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_calls, 1); _HA_ATOMIC_ADD(&bin->alloc_tot, pool->size); _HA_ATOMIC_STORE(&bin->info, pool); @@ -1069,6 +1071,8 @@ void __pool_free(struct pool_head *pool, void *ptr) struct memprof_stats *bin; bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_P_FREE); + if (unlikely(th_ctx->lock_level & 0x7F)) + _HA_ATOMIC_ADD(&bin->locked_calls, 1); _HA_ATOMIC_ADD(&bin->free_calls, 1); _HA_ATOMIC_ADD(&bin->free_tot, pool->size); _HA_ATOMIC_STORE(&bin->info, pool);