From: Vsevolod Stakhov Date: Sat, 2 May 2026 14:26:41 +0000 (+0100) Subject: [Feature] mem_pool: expose per-callsite entries iteration X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=42406d4757fb1e082f5685bff3298cffd81e4132;p=thirdparty%2Frspamd.git [Feature] mem_pool: expose per-callsite entries iteration Add rspamd_mempool_entry_stat_t and rspamd_mempool_entries_foreach() so callers can introspect the per-location mempool registry (suggestion, preallocated counts, average fragmentation/leftover) without reaching into mem_pool_internal.h. Used by the upcoming memstat control command. --- diff --git a/src/libutil/mem_pool.c b/src/libutil/mem_pool.c index d6362a06a1..fe11d4911c 100644 --- a/src/libutil/mem_pool.c +++ b/src/libutil/mem_pool.c @@ -1026,6 +1026,46 @@ void rspamd_mempool_stat_reset(void) } } +void rspamd_mempool_entries_foreach(rspamd_mempool_entry_cb cb, void *ud) +{ + khiter_t k; + + if (cb == NULL || mempool_entries == NULL) { + return; + } + + for (k = kh_begin(mempool_entries); k != kh_end(mempool_entries); ++k) { + if (!kh_exist(mempool_entries, k)) { + continue; + } + + struct rspamd_mempool_entry_point *elt = kh_value(mempool_entries, k); + rspamd_mempool_entry_stat_t st; + uint64_t sum_frag = 0; + uint64_t sum_left = 0; + unsigned int valid = 0; + + for (unsigned int i = 0; i < G_N_ELEMENTS(elt->elts); i++) { + if (elt->elts[i].fragmentation != 0 || elt->elts[i].leftover != 0) { + sum_frag += elt->elts[i].fragmentation; + sum_left += elt->elts[i].leftover; + valid++; + } + } + + st.src = elt->src; + st.cur_suggestion = elt->cur_suggestion; + st.cur_elts = elt->cur_elts; + st.cur_vars = elt->cur_vars; + st.cur_dtors = elt->cur_dtors; + st.samples = valid; + st.avg_fragmentation = valid ? (uint32_t) (sum_frag / valid) : 0; + st.avg_leftover = valid ? (uint32_t) (sum_left / valid) : 0; + + cb(&st, ud); + } +} + gsize rspamd_mempool_suggest_size_(const char *loc) { return 0; diff --git a/src/libutil/mem_pool.h b/src/libutil/mem_pool.h index 16bd6f143c..61a9c74b03 100644 --- a/src/libutil/mem_pool.h +++ b/src/libutil/mem_pool.h @@ -373,6 +373,30 @@ void rspamd_mempool_stat(rspamd_mempool_stat_t *st); */ void rspamd_mempool_stat_reset(void); +/** + * Per-callsite mempool statistics, aggregated from the rolling history + */ +typedef struct rspamd_mempool_entry_stat_s { + const char *src; /**< callsite location string (file:line) */ + uint32_t cur_suggestion; /**< current suggested pool size */ + uint32_t cur_elts; /**< suggested number of preallocated elts */ + uint32_t cur_vars; /**< suggested number of preallocated vars */ + uint32_t cur_dtors; /**< suggested number of preallocated dtors */ + uint32_t avg_fragmentation; /**< average fragmentation across history */ + uint32_t avg_leftover; /**< average leftover across history */ + uint32_t samples; /**< number of valid samples used for averages */ +} rspamd_mempool_entry_stat_t; + +typedef void (*rspamd_mempool_entry_cb)(const rspamd_mempool_entry_stat_t *stat, + void *ud); + +/** + * Iterate over all currently registered mempool callsite entries. + * The callback is invoked synchronously for each entry; the rspamd_mempool_entry_stat_t + * pointer and its src field are valid only for the duration of the callback. + */ +void rspamd_mempool_entries_foreach(rspamd_mempool_entry_cb cb, void *ud); + /** * Get optimal pool size based on page size for this system * @return size of memory page in system