From eb075d15f67d81c1931dea017c05a5cd69dece05 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 5 Aug 2025 18:03:09 +0200 Subject: [PATCH] MEDIUM: pools: add an alignment property This will be used to declare aligned pools. For now it's not used, but it's properly set from the various registrations that compose a pool, and rounded up to the next power of 2, with a minimum of sizeof(void*). The alignment is returned in the "show pools" part that indicates the entry size. E.g. "(56 bytes/8)" means 56 bytes, aligned by 8. --- include/haproxy/pool-t.h | 1 + src/pool.c | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/haproxy/pool-t.h b/include/haproxy/pool-t.h index 52765a627..883d4d5bc 100644 --- a/include/haproxy/pool-t.h +++ b/include/haproxy/pool-t.h @@ -128,6 +128,7 @@ struct pool_head { unsigned int minavail; /* how many chunks are expected to be used */ unsigned int size; /* chunk size */ unsigned int flags; /* MEM_F_* */ + unsigned int align; /* alignment size */ unsigned int users; /* number of pools sharing this zone */ unsigned int alloc_sz; /* allocated size (includes hidden fields) */ unsigned int sum_size; /* sum of all registered users' size */ diff --git a/src/pool.c b/src/pool.c index 3275bcb9b..cafc51094 100644 --- a/src/pool.c +++ b/src/pool.c @@ -318,13 +318,16 @@ struct pool_head *create_pool_with_loc(const char *name, unsigned int size, unsi } /* create a pool from a pool registration. All configuration is taken from - * there. + * there. The alignment will automatically be raised to sizeof(void*) or the + * next power of two so that it's always possible to lazily pass alignof() or + * sizeof(). Alignments are always respected when merging pools. */ struct pool_head *create_pool_from_reg(const char *name, struct pool_registration *reg) { unsigned int extra_mark, extra_caller, extra; unsigned int flags = reg->flags; unsigned int size = reg->size; + unsigned int alignment = reg->align; struct pool_head *pool = NULL; struct pool_head *entry; struct list *start; @@ -332,6 +335,21 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio unsigned int best_diff; int thr __maybe_unused; + /* extend alignment if needed */ + if (alignment < sizeof(void*)) + alignment = sizeof(void*); + else if (alignment & (alignment - 1)) { + /* not power of two! round up to next power of two by filling + * all LSB in O(log(log(N))) then increment the result. + */ + int shift = 1; + do { + alignment |= alignment >> shift; + shift *= 2; + } while (alignment & (alignment + 1)); + alignment++; + } + extra_mark = (pool_debugging & POOL_DBG_TAG) ? POOL_EXTRA_MARK : 0; extra_caller = (pool_debugging & POOL_DBG_CALLER) ? POOL_EXTRA_CALLER : 0; extra = extra_mark + extra_caller; @@ -427,6 +445,7 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio strlcpy2(pool->name, name, sizeof(pool->name)); pool->alloc_sz = size + extra; pool->size = size; + pool->align = alignment; pool->flags = flags; LIST_APPEND(start, &pool->list); LIST_INIT(&pool->regs); @@ -446,6 +465,8 @@ struct pool_head *create_pool_from_reg(const char *name, struct pool_registratio pool->size = size; pool->alloc_sz = size + extra; } + if (alignment > pool->align) + pool->align = alignment; DPRINTF(stderr, "Sharing %s with %s\n", name, pool->name); } @@ -1310,10 +1331,10 @@ void dump_pools_to_trash(int how, int max, const char *pfx) chunk_appendf(&trash, ". Use SIGQUIT to flush them.\n"); for (i = 0; i < nbpools && i < max; i++) { - chunk_appendf(&trash, " - Pool %s (%lu bytes) : %lu allocated (%lu bytes), %lu used" + chunk_appendf(&trash, " - Pool %s (%u bytes/%u) : %lu allocated (%lu bytes), %lu used" " (~%lu by thread caches)" ", needed_avg %lu, %lu failures, %u users, @%p%s\n", - pool_info[i].entry->name, (ulong)pool_info[i].entry->size, + pool_info[i].entry->name, pool_info[i].entry->size, pool_info[i].entry->align, pool_info[i].alloc_items, pool_info[i].alloc_bytes, pool_info[i].used_items, pool_info[i].cached_items, pool_info[i].need_avg, pool_info[i].failed_items,