From a60e1fcf7f1d937a429485eae2995f75ff56288e Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 25 Feb 2026 16:06:21 +0100 Subject: [PATCH] MEDIUM: counters: store the number of thread groups accessing extra_counters In order to be able to properly allocate all storage and retrieve data from there, we'll need to know how many thread groups are supposed to access it. Let's store the number of thread groups at init time. If the tgrp_step is zero, there's always only one tg though. Now EXTRA_COUNTERS_ALLOC() takes this number of thread groups in argument and stores it in the structure. It also allocates as many areas as needed, incrementing the datap pointer by the step for each of them. EXTRA_COUNTERS_FREE() uses this info to free all allocated areas. EXTRA_COUNTERS_INIT() initializes all allocated areas, this is used elsewhere to clear/preset counters, e.g. in proxy_stats_clear_counters(). It involves a memcpy() call for each array, which is normally preset to something empty but might also be used to preset certain non-scalar fields such as an instance name. --- include/haproxy/counters-t.h | 1 + include/haproxy/counters.h | 47 ++++++++++++++++++++++++------------ src/resolvers.c | 2 +- src/stats.c | 2 +- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/include/haproxy/counters-t.h b/include/haproxy/counters-t.h index 0dba60e43..301490d29 100644 --- a/include/haproxy/counters-t.h +++ b/include/haproxy/counters-t.h @@ -200,6 +200,7 @@ struct extra_counters { char **datap; /* points to pointer to heap containing counters allocated in a linear fashion */ size_t size; /* size of allocated data */ size_t tgrp_step; /* distance in words between two datap for consecutive tgroups, 0 for single */ + uint nbtgrp; /* number of thread groups accessing these counters */ enum counters_type type; /* type of object containing the counters */ }; diff --git a/include/haproxy/counters.h b/include/haproxy/counters.h index 1f97d9dfc..5fbe94d6f 100644 --- a/include/haproxy/counters.h +++ b/include/haproxy/counters.h @@ -128,27 +128,44 @@ void counters_be_shared_drop(struct be_counters_shared *counters); _ctr->size += (csize); \ } while (0) -#define EXTRA_COUNTERS_ALLOC(counters, alloc_failed_label) \ - do { \ - typeof(counters) _ctr = (counters); \ - *_ctr->datap = malloc((_ctr)->size); \ - if (!*_ctr->datap) \ - goto alloc_failed_label; \ +#define EXTRA_COUNTERS_ALLOC(counters, alloc_failed_label, nbtg) \ + do { \ + typeof(counters) _ctr = (counters); \ + char **datap = _ctr->datap; \ + uint tgrp; \ + _ctr->nbtgrp = _ctr->tgrp_step ? (nbtg) : 1; \ + for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \ + *datap = malloc((_ctr)->size); \ + if (!*_ctr->datap) \ + goto alloc_failed_label; \ + datap += _ctr->tgrp_step; \ + } \ } while (0) #define EXTRA_COUNTERS_INIT(counters, mod, init_counters, init_counters_size) \ do { \ - typeof(counters) _ctr = (counters); \ - memcpy(*_ctr->datap + mod->counters_off[_ctr->type], \ - (init_counters), (init_counters_size)); \ + typeof(counters) _ctr = (counters); \ + char **datap = _ctr->datap; \ + uint tgrp; \ + for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \ + memcpy(*datap + mod->counters_off[_ctr->type], \ + (init_counters), (init_counters_size)); \ + datap += _ctr->tgrp_step; \ + } \ } while (0) -#define EXTRA_COUNTERS_FREE(counters) \ - do { \ - if (counters) { \ - ha_free((counters)->datap);\ - free(counters); \ - } \ +#define EXTRA_COUNTERS_FREE(counters) \ + do { \ + typeof(counters) _ctr = (counters); \ + if (_ctr) { \ + char **datap = _ctr->datap; \ + uint tgrp; \ + for (tgrp = 0; tgrp < _ctr->nbtgrp; tgrp++) { \ + ha_free(datap); \ + datap += _ctr->tgrp_step; \ + } \ + free(_ctr); \ + } \ } while (0) #endif /* _HAPROXY_COUNTERS_H */ diff --git a/src/resolvers.c b/src/resolvers.c index abbe54aca..c717b013a 100644 --- a/src/resolvers.c +++ b/src/resolvers.c @@ -2915,7 +2915,7 @@ int resolv_allocate_counters(struct list *stat_modules) mod->counters_size); } - EXTRA_COUNTERS_ALLOC(ns->extra_counters, alloc_failed); + EXTRA_COUNTERS_ALLOC(ns->extra_counters, alloc_failed, 1); list_for_each_entry(mod, stat_modules, list) { memcpy(*ns->extra_counters->datap + mod->counters_off[ns->extra_counters->type], diff --git a/src/stats.c b/src/stats.c index 08e8c6fdf..b4f29696e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1108,7 +1108,7 @@ int stats_allocate_proxy_counters_internal(struct extra_counters **counters, EXTRA_COUNTERS_ADD(mod, *counters, mod->counters, mod->counters_size); } - EXTRA_COUNTERS_ALLOC(*counters, alloc_failed); + EXTRA_COUNTERS_ALLOC(*counters, alloc_failed, global.nbtgroups); list_for_each_entry(mod, &stats_module_list[STATS_DOMAIN_PROXY], list) { if (!(stats_px_get_cap(mod->domain_flags) & px_cap))