From 0faa777e172c0c6439201b13c9da16a939989e06 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 11 May 2026 09:27:29 -0400 Subject: [PATCH] MT#55283 add bufferpool stats output Change-Id: I1bae3b0d933948a8a22c41860d9c7508484ef17e --- daemon/statistics.c | 38 +++++++++++++ lib/bufferpool.c | 20 +++++++ lib/bufferpool.h | 13 +++++ t/test-stats.c | 133 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+) diff --git a/daemon/statistics.c b/daemon/statistics.c index 2867c8c01..bce75d511 100644 --- a/daemon/statistics.c +++ b/daemon/statistics.c @@ -313,6 +313,36 @@ static void add_header(stats_metric_q *ret, const char *fmt1, const char *fmt2, #define HEADERl(fmt2, ...) add_header(ret, NULL, fmt2, ##__VA_ARGS__) +static void bpool_stats(stats_metric_q *ret, const char *name, struct bufferpool *bpool) { + if (!bpool) // relevant for unit tests only + return; + + HEADER(name, NULL); + HEADER("{", NULL); + { + g_auto(bpool_stats_t) stats; + bufferpool_stats(bpool, &stats); + + METRICs("num_shards", "%u", stats.num_shards); + + HEADER("shards", NULL); + HEADER("[", NULL); + + for (unsigned int i = 0; i < stats.num_shards; i++) { + HEADER("{", NULL); + + METRICs("references", "%u", stats.shards[i].refs); + METRICs("size", "%zu", stats.shards[i].size); + METRICs("used", "%zu", stats.shards[i].used); + + HEADER("}", NULL); + } + + HEADER("]", NULL); + } + HEADER("}", NULL); +} + stats_metric_q *statistics_gather_metrics(struct interface_sampled_rate_stats *interface_rate_stats) { stats_metric_q *ret = stats_metric_q_new(); @@ -928,6 +958,14 @@ stats_metric_q *statistics_gather_metrics(struct interface_sampled_rate_stats *i } HEADER("]", NULL); + HEADER("bufferpools", NULL); + HEADER("{", NULL); + + bpool_stats(ret, "main", rtpe_bufferpool); + bpool_stats(ret, "shared", shm_bufferpool); + + HEADER("}", NULL); + HEADER("}", NULL); return ret; diff --git a/lib/bufferpool.c b/lib/bufferpool.c index 9005c039c..2d99af1e6 100644 --- a/lib/bufferpool.c +++ b/lib/bufferpool.c @@ -359,3 +359,23 @@ void *bufferpool_aligned_alloc(void) { void bufferpool_aligned_free(void *p) { free(p); } + +void bufferpool_stats(struct bufferpool *bp, bpool_stats_t *stats) { + rwlock_lock_r(&bp->shards_lock); + + stats->num_shards = bp->num_shards; + + stats->shards = g_new(__typeof(*stats->shards), bp->num_shards); + + for (unsigned int i = 0; i < bp->num_shards; i++) { + stats->shards[i].refs = bp->shards[i]->refs; + stats->shards[i].size = bp->shards[i]->end - bp->shards[i]->empty; + stats->shards[i].used = bp->shards[i]->head - bp->shards[i]->empty; + } + + rwlock_unlock_r(&bp->shards_lock); +} + +void bufferpool_stats_clear(bpool_stats_t *stats) { + g_free(stats->shards); +} diff --git a/lib/bufferpool.h b/lib/bufferpool.h index a842e5fbc..bdeeed94b 100644 --- a/lib/bufferpool.h +++ b/lib/bufferpool.h @@ -15,6 +15,15 @@ struct bufferpool; struct bpool_shard; +typedef struct { + unsigned int num_shards; + struct { + unsigned int refs; + size_t size; + size_t used; + } *shards; +} bpool_stats_t; + void bufferpool_init(void); void bufferpool_cleanup(void); @@ -38,6 +47,10 @@ INLINE void *bufferpool_alloc0(struct bufferpool *bp, size_t len) { void *bufferpool_aligned_alloc(void); void bufferpool_aligned_free(void *); +void bufferpool_stats(struct bufferpool *bp, bpool_stats_t *stats); +void bufferpool_stats_clear(bpool_stats_t *stats); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(bpool_stats_t, bufferpool_stats_clear); + typedef char bp_char; G_DEFINE_AUTOPTR_CLEANUP_FUNC(bp_char, bufferpool_unref); typedef char bp_void; diff --git a/t/test-stats.c b/t/test-stats.c index 6499c49d9..252d4913f 100644 --- a/t/test-stats.c +++ b/t/test-stats.c @@ -1393,6 +1393,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n"); RTPE_STATS_INC(ng_commands[OP_OFFER]); @@ -2705,6 +2724,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n"); RTPE_STATS_INC(ng_commands[OP_ANSWER]); @@ -4014,6 +4052,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n"); // test cmd_ps_min/max/avg @@ -5342,6 +5399,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n"); // test average call duration @@ -6659,6 +6735,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n"); @@ -7970,6 +8065,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n"); @@ -9284,6 +9398,25 @@ int main(void) { "poller_threads\n" "[\n" "]\n" + "bufferpools\n" + "{\n" + "shared\n" + "{\n" + "num_shards\n" + "1\n" + "shards\n" + "[\n" + "{\n" + "references\n" + "1\n" + "size\n" + "16777208\n" + "used\n" + "480\n" + "}\n" + "]\n" + "}\n" + "}\n" "}\n");