From 40b17bd9335ecba66a549922ac11199b7ede0cfb Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 8 Sep 2026 09:20:58 -0400 Subject: [PATCH] MT#55283 exponential increase of arena allocations Rel: #2165 Change-Id: I3da5a0bdd95cb4a73e39d159d19310f2b9bd7ef9 --- lib/arena.c | 27 ++++++++++++++++++++------- lib/arena.h | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/arena.c b/lib/arena.c index cb6928a29..fcf2e9e5d 100644 --- a/lib/arena.c +++ b/lib/arena.c @@ -2,7 +2,7 @@ #include "helpers.h" -#define ARENA_MIN_PIECE_LEN 4096 +#define ARENA_INITIAL_PIECE_ORDER 12 // 4096 // enable to perform each allocation separately, to make debugging (valgrind...) easier //#define ARENA_ALLOC_DEBUG @@ -15,19 +15,31 @@ struct arena_piece { }; -static struct arena_piece *arena_piece_new(size_t size, void *(*alloc_fn)(size_t)) { +static struct arena_piece *arena_piece_new(arena_t *arena, size_t size, void *(*alloc_fn)(size_t)) { struct arena_piece *ret; - size_t alloc_size = size + sizeof(*ret) + ARENA_ALLOC_ALIGN; + static const unsigned long overhead = sizeof(*ret) + ARENA_ALLOC_ALIGN; + unsigned long needed_size = size + overhead; + #ifndef ARENA_ALLOC_DEBUG - alloc_size = MAX(alloc_size, ARENA_MIN_PIECE_LEN); + unsigned long alloc_size = 1L << arena->piece_order; + + if (needed_size > alloc_size) { + arena->piece_order = LONG_BIT - __builtin_clzl(needed_size); + alloc_size = 1L << arena->piece_order; + } + + arena->piece_order++; // next needed piece will be larger +#else + unsigned long alloc_size = needed_size; #endif + ret = alloc_fn(alloc_size); if (!ret) return NULL; ret->tail = ret->buf; - ret->left = alloc_size - sizeof(*ret) - ARENA_ALLOC_ALIGN; + ret->left = alloc_size - overhead; ret->next = NULL; return ret; @@ -36,7 +48,8 @@ static struct arena_piece *arena_piece_new(size_t size, void *(*alloc_fn)(size_t bool arena_init(arena_t *arena, void *(*alloc_fn)(size_t), void (*free_fn)(void *)) { arena->alloc = alloc_fn; arena->free = free_fn; - arena->pieces = arena_piece_new(0, alloc_fn); + arena->piece_order = ARENA_INITIAL_PIECE_ORDER; + arena->pieces = arena_piece_new(arena, 0, alloc_fn); if (!arena->pieces) return false; return true; @@ -55,7 +68,7 @@ void *arena_alloc(arena_t *arena, size_t size) { if (size <= piece->left) goto alloc; - piece = arena_piece_new(size, arena->alloc); + piece = arena_piece_new(arena, size, arena->alloc); if (!piece) return NULL; piece->next = arena->pieces; diff --git a/lib/arena.h b/lib/arena.h index 951f7db38..aca4e9b63 100644 --- a/lib/arena.h +++ b/lib/arena.h @@ -17,6 +17,7 @@ struct arena { struct arena_piece *pieces; void *(*alloc)(size_t); void (*free)(void *); + unsigned int piece_order; }; typedef struct arena arena_t;