From: Olivier Houchard Date: Thu, 27 Nov 2025 22:33:48 +0000 (+0100) Subject: MEDIUM: cpu-topo: Add a "threads-per-core" keyword to cpu-policy X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3671652bc95a2329f83aff7171ea571064460e9b;p=thirdparty%2Fhaproxy.git MEDIUM: cpu-topo: Add a "threads-per-core" keyword to cpu-policy Add a new, optional key-word to "cpu-policy", "threads-per-core". It takes one argument, "1" or "auto". If "1" is used, then only one thread per core will be created, no matter how many hardware thread each core has. If "auto" is used, then one thread will be created per hardware thread, as is the case by default. for example: cpu-policy performance threads-per-core 1 --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 3cc3499f0..62b4776bf 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2223,7 +2223,7 @@ cpu-map [auto:][/] [,...] [...] cpu-map 4/1-40 40-79,120-159 -cpu-policy +cpu-policy [threads-per-core 1 | auto] Selects the CPU allocation policy to be used. On multi-CPU systems, there can be plenty of reasons for not using all @@ -2375,6 +2375,11 @@ cpu-policy easily. Note that if a single cluster is present, it will still be fully used. + An optional keyword can be added, "threads-per-core". It can accept two + values, "1" and "auto". If set to 1, then only one thread per core will be + created, unrespective of how many hardware threads the core has. If set + to auto, then one thread per hardware thread will be created. + See also: "cpu-map", "cpu-set", "nbthread" cpu-set ... diff --git a/src/cpu_topo.c b/src/cpu_topo.c index ba35b45ab..774e18147 100644 --- a/src/cpu_topo.c +++ b/src/cpu_topo.c @@ -17,6 +17,9 @@ #define CPU_SET_FL_NONE 0x0000 #define CPU_SET_FL_DO_RESET 0x0001 +/* cpu_policy_conf flags */ +#define CPU_POLICY_ONE_THREAD_PER_CORE (1 << 0) + /* 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_lastcpu = -1; // last supposed online CPU (no need to look beyond) @@ -50,8 +53,10 @@ struct cpu_set_cfg { /* CPU policy choice */ struct { int cpu_policy; + int flags; } cpu_policy_conf = { - 1, /* "first-usable-node" */ + 1, /* "performance" policy */ + 0, /* Default flags */ }; /* list of CPU policies for "cpu-policy". The default one is the first one. */ @@ -1030,11 +1035,13 @@ void cpu_refine_cpusets(void) static int cpu_policy_first_usable_node(int policy, int tmin, int tmax, int gmin, int gmax, char **err) { struct hap_cpuset node_cpu_set; + struct hap_cpuset visited_tsid; int first_node_id = -1; int second_node_id = -1; int cpu; int cpu_count; int grp, thr; + int thr_count = 0; if (!global.numa_cpu_mapping) return 0; @@ -1069,12 +1076,19 @@ static int cpu_policy_first_usable_node(int policy, int tmin, int tmax, int gmin * and make a CPU set of them. */ ha_cpuset_zero(&node_cpu_set); + ha_cpuset_zero(&visited_tsid); for (cpu = cpu_count = 0; cpu <= cpu_topo_lastcpu; cpu++) { if (ha_cpu_topo[cpu].no_id != first_node_id) ha_cpu_topo[cpu].st |= HA_CPU_F_IGNORED; else if (!(ha_cpu_topo[cpu].st & HA_CPU_F_EXCL_MASK)) { ha_cpuset_set(&node_cpu_set, ha_cpu_topo[cpu].idx); cpu_count++; + + if (!(cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE) || !ha_cpuset_isset(&visited_tsid, ha_cpu_topo[cpu].ts_id)) { + ha_cpuset_set(&visited_tsid, ha_cpu_topo[cpu].ts_id); + thr_count++; + last_id = ha_cpu_topo[cpu].ts_id; + } } } @@ -1083,8 +1097,8 @@ static int cpu_policy_first_usable_node(int policy, int tmin, int tmax, int gmin for (thr = 0; thr < MAX_THREADS_PER_GROUP; thr++) ha_cpuset_assign(&cpu_map[grp].thread[thr], &node_cpu_set); - if (tmin <= cpu_count && cpu_count < tmax) - tmax = cpu_count; + if (tmin <= thr_count && thr_count < tmax) + tmax = thr_count; ha_diag_warning("Multi-socket cpu detected, automatically binding on active CPUs of '%d' (%u active cpu(s))\n", first_node_id, cpu_count); @@ -1106,6 +1120,7 @@ static int cpu_policy_group_by_cluster(int policy, int tmin, int tmax, int gmin, { struct hap_cpuset visited_cl_set; struct hap_cpuset node_cpu_set; + struct hap_cpuset visited_tsid; int cpu, cpu_start; int cpu_count; int cid; @@ -1149,7 +1164,13 @@ static int cpu_policy_group_by_cluster(int policy, int tmin, int tmax, int gmin, /* make a mask of all of this cluster's CPUs */ ha_cpuset_set(&node_cpu_set, ha_cpu_topo[cpu].idx); - cpu_count++; + if (cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE) { + if (!ha_cpuset_isset(&visited_tsid, ha_cpu_topo[cpu].ts_id)) { + ha_cpuset_set(&visited_tsid, ha_cpu_topo[cpu].ts_id); + cpu_count++; + } + } else + cpu_count++; } /* now cid = next cluster_id or -1 if none; cpu_count is the @@ -1222,6 +1243,7 @@ static int cpu_policy_group_by_ccx(int policy, int tmin, int tmax, int gmin, int { struct hap_cpuset visited_ccx_set; struct hap_cpuset node_cpu_set; + struct hap_cpuset visited_tsid; int cpu, cpu_start; int cpu_count; int l3id; @@ -1246,6 +1268,7 @@ static int cpu_policy_group_by_ccx(int policy, int tmin, int tmax, int gmin, int while (global.nbtgroups < MAX_TGROUPS && global.nbthread < MAX_THREADS) { ha_cpuset_zero(&node_cpu_set); + ha_cpuset_zero(&visited_tsid); l3id = -1; cpu_count = 0; for (cpu = cpu_start; cpu <= cpu_topo_lastcpu; cpu++) { @@ -1265,7 +1288,13 @@ static int cpu_policy_group_by_ccx(int policy, int tmin, int tmax, int gmin, int /* make a mask of all of this cluster's CPUs */ ha_cpuset_set(&node_cpu_set, ha_cpu_topo[cpu].idx); - cpu_count++; + if (cpu_policy_conf.flags & CPU_POLICY_ONE_THREAD_PER_CORE) { + if (!ha_cpuset_isset(&visited_tsid, ha_cpu_topo[cpu].ts_id)) { + ha_cpuset_set(&visited_tsid, ha_cpu_topo[cpu].ts_id); + cpu_count++; + } + } else + cpu_count++; } /* now l3id = next L3 ID or -1 if none; cpu_count is the @@ -1941,9 +1970,23 @@ static int cfg_parse_cpu_policy(char **args, int section_type, struct proxy *cur { int i; - if (too_many_args(1, args, err, NULL)) + if (too_many_args(3, args, err, NULL)) return -1; + if (*args[2] != 0) { + if (!strcmp(args[2], "threads-per-core")) { + if (!strcmp(args[3], "1")) + cpu_policy_conf.flags |= CPU_POLICY_ONE_THREAD_PER_CORE; + else if (strcmp(args[3], "auto")) { + memprintf(err, "'%s' passed an unknown value '%s' to keyword '%s', known values are 1 or auto", args[0], args[3], args[2]); + return -1; + } + } else { + memprintf(err, "'%s' passed an unknown keyword '%s', the only known values are threads-per-core", args[0], args[2]); + return -1; + } + + } for (i = 0; ha_cpu_policy[i].name; i++) { if (strcmp(args[1], ha_cpu_policy[i].name) == 0) { cpu_policy_conf.cpu_policy = i;