From 90e8ccd9c2a09d8b64a4a1a5fadb435768d96b2a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 14 Apr 2026 17:42:36 +0200 Subject: [PATCH] MINOR: sample: add new sample fetch functions reporting current CPU usage Some features can automatically turn on or off depending on CPU usage, but it's not easy to measure it. Let's provide 3 new sample fetch functions reporting the CPU usage as measured inside haproxy during the previous polling loop, and reported in "idle" stats header / "show info", or used by tune.glitches.kill.cpu-usage, or maxcompcpuusage: - cpu_usage_thr: CPU usage between 0 and 100 of the current thread, used by functions above - cpu_usage_grp: CPU usage between 0 and 100, averaged over all threads of the same group as the current one. - cpu_usage_proc: CPU usage between 0 and 100, averaged over all threads of the current process Note that the value will fluctuate since it only covers a few tens to hundreds of requests of the last polling loop, but it reports what is being used to take decisions. It could also be used to disable some non-essential debugging/processing under too high loads for example. --- doc/configuration.txt | 24 ++++++++++++++++++++++++ src/sample.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/doc/configuration.txt b/doc/configuration.txt index 43b6e6b5f..b62778423 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -23672,6 +23672,30 @@ cpu_ns_tot : integer high cpu_calls count, for example when processing many HTTP chunks, and for this reason it is often preferred to log cpu_ns_avg instead. +cpu_usage_grp : integer + Returns the measured CPU usage over the last polling loop, between 0 and 100, + averaged over all threads of the current thread group. This can be used for + troubleshooting and for logging. The measure is extremely volatile but will + remain accurate for sustained loads as each thread measures it over a few + tens to hundreds of requests. + +cpu_usage_proc : integer + Returns the measured CPU usage over the last polling loop, between 0 and 100, + averaged over all running threads. This can be used for troubleshooting and + for logging. The measure is extremely volatile but will remain accurate for + sustained loads as each thread measures it over a few tens to hundreds of + requests. This is 100 minus the value reported in the idle ratio in the stats + page and in "show info". + +cpu_usage_thr : integer + Returns the measured CPU usage over the last polling loop, between 0 and 100, + for the calling thread. This can be used for troubleshooting and for logging. + The measure is extremely volatile but will remain accurate for sustained + loads as it is measured over a few tens to hundreds of requests. This is the + same value as used to decide to enable connection killing on too high + glitches, or to disable compression. See also "tune.glitches.kill.cpu-usage" + and "maxcomcpuusage". + date([[,]]) : integer Returns the current date as the epoch (number of seconds since 01/01/1970). diff --git a/src/sample.c b/src/sample.c index 370c0156a..a1e1c74ae 100644 --- a/src/sample.c +++ b/src/sample.c @@ -5089,6 +5089,43 @@ smp_fetch_tgroup(const struct arg *args, struct sample *smp, const char *kw, voi return 1; } +/* returns the last known CPU usage of the current thread */ +static int +smp_fetch_cpu_usage_thr(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + smp->data.type = SMP_T_SINT; + smp->data.u.sint = 100 - th_ctx->idle_pct; + return 1; +} + +/* returns the last known CPU usage of the current thread group */ +static int +smp_fetch_cpu_usage_grp(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + uint thr, tot = 0; + + for (thr = 0; thr < ha_tgroup_info[tgid - 1].count; thr++) + tot += 100 - ha_thread_ctx[ha_tgroup_info[tgid - 1].base + thr].idle_pct; + + smp->data.type = SMP_T_SINT; + smp->data.u.sint = (tot + thr / 2) / thr; + return 1; +} + +/* returns the last known CPU usage of the whole process */ +static int +smp_fetch_cpu_usage_proc(const struct arg *args, struct sample *smp, const char *kw, void *private) +{ + int thr, tot = 0; + + for (thr = 0; thr < global.nbthread; thr++) + tot += 100 - ha_thread_ctx[thr].idle_pct; + + smp->data.type = SMP_T_SINT; + smp->data.u.sint = (tot + thr / 2) / thr; + return 1; +} + /* generate a random 32-bit integer for whatever purpose, with an optional * range specified in argument. */ @@ -5677,6 +5714,9 @@ static struct sample_fetch_kw_list smp_kws = {ILH, { { "cpu_calls", smp_fetch_cpu_calls, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, { "cpu_ns_avg", smp_fetch_cpu_ns_avg, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, { "cpu_ns_tot", smp_fetch_cpu_ns_tot, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, + { "cpu_usage_grp", smp_fetch_cpu_usage_grp, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, + { "cpu_usage_proc",smp_fetch_cpu_usage_proc, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, + { "cpu_usage_thr", smp_fetch_cpu_usage_thr, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, { "lat_ns_avg", smp_fetch_lat_ns_avg, 0, NULL, SMP_T_SINT, SMP_USE_INTRN }, { "lat_ns_tot", smp_fetch_lat_ns_tot, 0, NULL, SMP_T_SINT, SMP_USE_INTRN },