MINOR: cpu-topo: add a new "cpu-set" global directive to choose cpus

For now it's limited, it only supports "reset" to ask that any previous
"taskset" be ignored. The goal will be to later add more actions that
allow to symbolically define sets of cpus to bind to or to drop. This
also clears the cpu_mask_forced variable that is used to detect
that a taskset had been used.
This commit is contained in:
Willy Tarreau 2025-02-26 15:17:41 +01:00
parent f0661e79fe
commit cda4956d9c
2 changed files with 73 additions and 6 deletions

View File

@ -1522,6 +1522,7 @@ The following keywords are supported in the "global" section :
- chroot - chroot
- cluster-secret - cluster-secret
- cpu-map - cpu-map
- cpu-set
- crt-base - crt-base
- daemon - daemon
- default-path - default-path
@ -1946,6 +1947,13 @@ cpu-map [auto:]<thread-group>[/<thread-set>] <cpu-set>[,...] [...]
cpu-map 4/1-40 40-79,120-159 cpu-map 4/1-40 40-79,120-159
cpu-set <directive>...
Allows to symbolically describe what sets of CPUs to run on. The directive
supports the following keyword:
- reset this undoes any previous limitation that could have
been inherited by a service manager or a "taskset"
command for example.
crt-base <dir> crt-base <dir>
Assigns a default directory to fetch SSL certificates from when a relative Assigns a default directory to fetch SSL certificates from when a relative
path is used with "crtfile" or "crt" directives. Absolute locations specified path is used with "crtfile" or "crt" directives. Absolute locations specified

View File

@ -6,11 +6,16 @@
#include <unistd.h> #include <unistd.h>
#include <haproxy/api.h> #include <haproxy/api.h>
#include <haproxy/cfgparse.h>
#include <haproxy/cpuset.h> #include <haproxy/cpuset.h>
#include <haproxy/cpu_topo.h> #include <haproxy/cpu_topo.h>
#include <haproxy/global.h> #include <haproxy/global.h>
#include <haproxy/tools.h> #include <haproxy/tools.h>
/* for cpu_set.flags below */
#define CPU_SET_FL_NONE 0x0000
#define CPU_SET_FL_DO_RESET 0x0001
/* CPU topology information, ha_cpuset_size() entries, allocated at boot */ /* CPU topology information, ha_cpuset_size() entries, allocated at boot */
int cpu_topo_maxcpus = -1; // max number of CPUs supported by OS/haproxy int cpu_topo_maxcpus = -1; // max number of CPUs supported by OS/haproxy
int cpu_topo_lastcpu = -1; // last supposed online CPU (no need to look beyond) int cpu_topo_lastcpu = -1; // last supposed online CPU (no need to look beyond)
@ -20,6 +25,11 @@ struct cpu_map *cpu_map;
/* non-zero if we're certain that taskset or similar was used to force CPUs */ /* non-zero if we're certain that taskset or similar was used to force CPUs */
int cpu_mask_forced = 0; int cpu_mask_forced = 0;
/* "cpu-set" global configuration */
struct cpu_set_cfg {
uint flags; // CPU_SET_FL_XXX above
} cpu_set_cfg;
/* Detects CPUs that are online on the system. It may rely on FS access (e.g. /* Detects CPUs that are online on the system. It may rely on FS access (e.g.
* /sys on Linux). Returns the number of CPUs detected or 0 if the detection * /sys on Linux). Returns the number of CPUs detected or 0 if the detection
* failed. * failed.
@ -83,13 +93,15 @@ int cpu_detect_usable(void)
struct hap_cpuset boot_set = { }; struct hap_cpuset boot_set = { };
int cpu; int cpu;
/* update the list with the CPUs currently bound to the current process */ if (!(cpu_set_cfg.flags & CPU_SET_FL_DO_RESET)) {
ha_cpuset_detect_bound(&boot_set); /* update the list with the CPUs currently bound to the current process */
ha_cpuset_detect_bound(&boot_set);
/* remove the known-excluded CPUs */ /* remove the known-excluded CPUs */
for (cpu = 0; cpu < cpu_topo_maxcpus; cpu++) for (cpu = 0; cpu < cpu_topo_maxcpus; cpu++)
if (!ha_cpuset_isset(&boot_set, cpu)) if (!ha_cpuset_isset(&boot_set, cpu))
ha_cpu_topo[cpu].st |= HA_CPU_F_EXCLUDED; ha_cpu_topo[cpu].st |= HA_CPU_F_EXCLUDED;
}
/* Update the list of currently offline CPUs. Normally it's a subset /* Update the list of currently offline CPUs. Normally it's a subset
* of the unbound ones, but we cannot infer anything if we don't have * of the unbound ones, but we cannot infer anything if we don't have
@ -463,6 +475,45 @@ int cpu_detect_topology(void)
#endif // OS-specific cpu_detect_topology() #endif // OS-specific cpu_detect_topology()
/* Parse the "cpu-set" global directive, which takes action names and
* optional values, and fills the cpu_set structure above.
*/
static int cfg_parse_cpu_set(char **args, int section_type, struct proxy *curpx,
const struct proxy *defpx, const char *file, int line,
char **err)
{
int arg;
for (arg = 1; *args[arg]; arg++) {
if (strcmp(args[arg], "reset") == 0) {
if (too_many_args(0 + arg, args, err, NULL))
return -1;
/* reset the excluded CPUs first (undo "taskset") */
cpu_set_cfg.flags |= CPU_SET_FL_DO_RESET;
cpu_mask_forced = 0;
}
else {
/* fall back with default error message */
memprintf(err, "'%s' passed an unknown directive '%s'", args[0], args[arg]);
goto leave_with_err;
}
}
if (arg == 1) {
memprintf(err, "'%s' requires a directive and an optional value", args[0]);
goto leave_with_err;
}
/* all done */
return 0;
leave_with_err:
/* complete with supported directives */
memprintf(err, "%s (only 'reset' supported).", *err);
return -1;
}
/* Allocates everything needed to store CPU topology at boot. /* Allocates everything needed to store CPU topology at boot.
* Returns non-zero on success, zero on failure. * Returns non-zero on success, zero on failure.
*/ */
@ -502,3 +553,11 @@ static void cpu_topo_deinit(void)
INITCALL0(STG_ALLOC, cpu_topo_alloc); INITCALL0(STG_ALLOC, cpu_topo_alloc);
REGISTER_POST_DEINIT(cpu_topo_deinit); REGISTER_POST_DEINIT(cpu_topo_deinit);
/* config keyword parsers */
static struct cfg_kw_list cfg_kws = {ILH, {
{ CFG_GLOBAL, "cpu-set", cfg_parse_cpu_set, 0 },
{ 0, NULL, NULL }
}};
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);