From ea2a0e5796718739ded60ecf516a0094d74f5317 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 21 Oct 2025 11:41:50 +0100 Subject: [PATCH] [Feature] Smart destructor preallocation based on pool type and statistics Implement intelligent preallocation strategy for destructor heap: Long-lived pools (LONG_LIVED flag): - Fixed preallocation: 32 destructor slots - No statistical tracking needed (pool lives entire process lifetime) - Covers typical module/configuration destructor counts Short-lived pools (default): - Statistics-based preallocation using entry point data - Track maximum destructors seen per entry point - Cap at 64 slots to prevent excessive preallocation - Simplified max-tracking logic (replaces exponential growth) Benefits: - Long-lived: predictable memory usage, no reallocation overhead - Short-lived: adaptive to actual usage patterns - Reduced heap resizing operations during destructor addition - Memory bounded (32 for long-lived, max 64 for short-lived) Statistics updated on pool deletion to inform future allocations from same entry point. --- src/libutil/mem_pool.c | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/libutil/mem_pool.c b/src/libutil/mem_pool.c index b7441ee4bc..726d66d7d9 100644 --- a/src/libutil/mem_pool.c +++ b/src/libutil/mem_pool.c @@ -674,10 +674,20 @@ void rspamd_mempool_add_destructor_full(rspamd_mempool_t *pool, if (pool->priv->dtors_heap.a == NULL) { rspamd_heap_init(rspamd_mempool_destruct_heap, &pool->priv->dtors_heap); - /* Reserve space based on statistics */ - if (pool->priv->entry && pool->priv->entry->cur_dtors > 0) { + /* Reserve space based on pool type and statistics */ + unsigned int preallocate = 0; + if (pool->priv->flags & RSPAMD_MEMPOOL_LONG_LIVED) { + /* Long-lived pools: fixed preallocation (32 slots) */ + preallocate = 32; + } + else if (pool->priv->entry && pool->priv->entry->cur_dtors > 0) { + /* Short-lived pools: use statistics, cap at 64 */ + preallocate = MIN(pool->priv->entry->cur_dtors, 64); + } + + if (preallocate > 0) { kv_resize_safe(struct _pool_destructors, pool->priv->dtors_heap, - pool->priv->entry->cur_dtors, cleanup); + preallocate, cleanup); } } @@ -939,27 +949,9 @@ void rspamd_mempool_delete(rspamd_mempool_t *pool) if (pool->priv->entry && mempool_entries) { ndtors = rspamd_heap_size(rspamd_mempool_destruct_heap, &pool->priv->dtors_heap); - /* Update suggestion using similar logic to variables */ - if (pool->priv->entry->cur_dtors < ndtors) { - static const unsigned int max_preallocated_dtors = 128; - - unsigned int old_guess = pool->priv->entry->cur_dtors; - unsigned int new_guess; - - if (old_guess == 0) { - new_guess = MIN(ndtors, max_preallocated_dtors); - } - else { - if (old_guess * 2 < ndtors) { - new_guess = MIN(ndtors, max_preallocated_dtors); - } - else { - /* Too large step */ - new_guess = MIN(old_guess * 2, max_preallocated_dtors); - } - } - - pool->priv->entry->cur_dtors = new_guess; + /* Track maximum number of destructors seen, cap at 64 */ + if (ndtors > pool->priv->entry->cur_dtors) { + pool->priv->entry->cur_dtors = MIN(ndtors, 64); } } -- 2.47.3