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.
This commit is contained in:
Willy Tarreau 2026-02-25 16:06:21 +01:00
parent 7ac47910a2
commit a60e1fcf7f
4 changed files with 35 additions and 17 deletions

View file

@ -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 */
};

View file

@ -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 */

View file

@ -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],

View file

@ -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))