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 %)]
This commit is contained in:
Willy Tarreau 2025-09-11 15:36:13 +02:00
parent 9d8c2a888b
commit 8fb5ae5cc6
3 changed files with 38 additions and 2 deletions

View File

@ -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

View File

@ -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)

View File

@ -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);