From 982fb53390ae58de4de44ad0632b3393339bace4 Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Wed, 21 Apr 2021 18:39:58 +0200 Subject: [PATCH] MEDIUM: config: use platform independent type hap_cpuset for cpu-map Use the platform independent type hap_cpuset for the cpu-map statement parsing. This allow to address CPU index greater than LONGBITS. Update the documentation to reflect the removal of this limit except for platforms without cpu_set_t type or equivalent. --- doc/configuration.txt | 18 +++++----- include/haproxy/global-t.h | 7 ++-- src/cfgparse-global.c | 71 ++++++++++++++++++-------------------- src/haproxy.c | 53 +++++++++++----------------- 4 files changed, 67 insertions(+), 82 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index de91004398..c50700f124 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -1063,14 +1063,16 @@ cpu-map [auto:][/] ... a dash ('-'). It also is possible to specify all processes at once using "all", only odd numbers using "odd" or even numbers using "even", just like with the "bind-process" directive. The second and forthcoming arguments are - CPU sets. Each CPU set is either a unique number between 0 and 31 or 63 or a - range with two such numbers delimited by a dash ('-'). Multiple CPU numbers - or ranges may be specified, and the processes or threads will be allowed to - bind to all of them. Obviously, multiple "cpu-map" directives may be - specified. Each "cpu-map" directive will replace the previous ones when they - overlap. A thread will be bound on the intersection of its mapping and the - one of the process on which it is attached. If the intersection is null, no - specific binding will be set for the thread. + CPU sets. Each CPU set is either a unique number starting at 0 for the first + CPU or a range with two such numbers delimited by a dash ('-'). Outside of + Linux and BSDs, there may be a limitation on the maximum CPU index to either + 31 or 63. Multiple CPU numbers or ranges may be specified, and the processes + or threads will be allowed to bind to all of them. Obviously, multiple + "cpu-map" directives may be specified. Each "cpu-map" directive will replace + the previous ones when they overlap. A thread will be bound on the + intersection of its mapping and the one of the process on which it is + attached. If the intersection is null, no specific binding will be set for + the thread. Ranges can be partially defined. The higher bound can be omitted. In such case, it is replaced by the corresponding maximum value, 32 or 64 depending diff --git a/include/haproxy/global-t.h b/include/haproxy/global-t.h index c98a0fabae..bc734a6d02 100644 --- a/include/haproxy/global-t.h +++ b/include/haproxy/global-t.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -160,9 +161,9 @@ struct global { struct proxy *cli_fe; /* the frontend holding the stats settings */ #ifdef USE_CPU_AFFINITY struct { - unsigned long proc[MAX_PROCS]; /* list of CPU masks for the 32/64 first processes */ - unsigned long proc_t1[MAX_PROCS]; /* list of CPU masks for the 1st thread of each process */ - unsigned long thread[MAX_THREADS]; /* list of CPU masks for the 32/64 first threads of the 1st process */ + struct hap_cpuset proc[MAX_PROCS]; /* list of CPU masks for the 32/64 first processes */ + struct hap_cpuset proc_t1[MAX_PROCS]; /* list of CPU masks for the 1st thread of each process */ + struct hap_cpuset thread[MAX_THREADS]; /* list of CPU masks for the 32/64 first threads of the 1st process */ } cpu_map; #endif /* The info above is config stuff, it doesn't change during the process' life */ diff --git a/src/cfgparse-global.c b/src/cfgparse-global.c index 40f3018b3e..694cd70776 100644 --- a/src/cfgparse-global.c +++ b/src/cfgparse-global.c @@ -1,4 +1,3 @@ -#define _GNU_SOURCE /* for CPU_* from cpuset.h */ #include #include #include @@ -1028,9 +1027,9 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) /* map a process list to a CPU set */ #ifdef USE_CPU_AFFINITY char *slash; - unsigned long proc = 0, thread = 0, cpus; - int i, j, n, k, autoinc; - struct hap_cpuset cpuset; + unsigned long proc = 0, thread = 0; + int i, j, n, autoinc; + struct hap_cpuset cpus, cpus_copy; if (!*args[1] || !*args[2]) { ha_alert("parsing [%s:%d] : %s expects a process number " @@ -1071,26 +1070,15 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } } - if (parse_cpu_set((const char **)args+2, &cpuset, &errmsg)) { + if (parse_cpu_set((const char **)args+2, &cpus, &errmsg)) { ha_alert("parsing [%s:%d] : %s : %s\n", file, linenum, args[0], errmsg); err_code |= ERR_ALERT | ERR_FATAL; goto out; } -#if defined(CPUSET_USE_CPUSET) - k = 0; - while (CPU_COUNT(&cpuset.cpuset)) { - while (!CPU_ISSET(k, &cpuset.cpuset)) - ++k; - cpus |= 1 << k; - CPU_CLR(k, &cpuset.cpuset); - ++k; - } -#elif defined(CPUSET_USE_ULONG) - cpus = cpuset.cpuset; -#endif + if (autoinc && - my_popcountl(proc) != my_popcountl(cpus) && - my_popcountl(thread) != my_popcountl(cpus)) { + my_popcountl(proc) != ha_cpuset_count(&cpus) && + my_popcountl(thread) != ha_cpuset_count(&cpus)) { ha_alert("parsing [%s:%d] : %s : PROC/THREAD range and CPU sets " "must have the same size to be automatically bound\n", file, linenum, args[0]); @@ -1111,16 +1099,19 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) */ if (!thread) { /* mapping for whole processes. E.g. cpu-map 1-4 0-3 */ + ha_cpuset_assign(&cpus_copy, &cpus); for (i = n = 0; i < MAX_PROCS; i++) { /* No mapping for this process */ if (!(proc & (1UL << i))) continue; if (!autoinc) - global.cpu_map.proc[i] = cpus; + ha_cpuset_assign(&global.cpu_map.proc[i], &cpus); else { - n += my_ffsl(cpus >> n); - global.cpu_map.proc[i] = (1UL << (n-1)); + ha_cpuset_zero(&global.cpu_map.proc[i]); + n = ha_cpuset_ffs(&cpus_copy) - 1; + ha_cpuset_clr(&cpus_copy, n); + ha_cpuset_set(&global.cpu_map.proc[i], n); } } } else { @@ -1129,44 +1120,48 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) * other combinations are silently ignored. */ if (thread == 0x1) { - int val; - /* first thread, iterate on processes. E.g. cpu-map 1-4/1 0-3 */ + struct hap_cpuset *dst; + + ha_cpuset_assign(&cpus_copy, &cpus); for (i = n = 0; i < MAX_PROCS; i++) { /* No mapping for this process */ if (!(proc & (1UL << i))) continue; + /* For first process, thread[0] is used. + * Use proc_t1[N] for all others + */ + dst = i ? &global.cpu_map.proc_t1[i] : + &global.cpu_map.thread[0]; + if (!autoinc) { - val = cpus; + ha_cpuset_assign(dst, &cpus); } else { - n += my_ffsl(cpus >> n); - val = 1UL << (n - 1); + ha_cpuset_zero(dst); + n = ha_cpuset_ffs(&cpus_copy) - 1; + ha_cpuset_clr(&cpus_copy, n); + ha_cpuset_set(dst, n); } - - /* For first process, thread[0] is used. - * Use proc_t1[N] for all others - */ - if (!i) - global.cpu_map.thread[0] = val; - else - global.cpu_map.proc_t1[i] = val; } } if (proc == 0x1) { /* first process, iterate on threads. E.g. cpu-map 1/1-4 0-3 */ + ha_cpuset_assign(&cpus_copy, &cpus); for (j = n = 0; j < MAX_THREADS; j++) { /* No mapping for this thread */ if (!(thread & (1UL << j))) continue; if (!autoinc) - global.cpu_map.thread[j] = cpus; + ha_cpuset_assign(&global.cpu_map.thread[j], &cpus); else { - n += my_ffsl(cpus >> n); - global.cpu_map.thread[j] = (1UL << (n-1)); + ha_cpuset_zero(&global.cpu_map.thread[j]); + n = ha_cpuset_ffs(&cpus_copy) - 1; + ha_cpuset_clr(&cpus_copy, n); + ha_cpuset_set(&global.cpu_map.thread[j], n); } } } diff --git a/src/haproxy.c b/src/haproxy.c index ecc5f2135c..58e9e62f9e 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include @@ -1268,6 +1269,7 @@ static void init(int argc, char **argv) struct proxy *px; struct post_check_fct *pcf; int ideal_maxconn; + int i; global.mode = MODE_STARTING; old_argv = copy_argv(argc, argv); @@ -1576,6 +1578,12 @@ static void init(int argc, char **argv) global.maxsock = 10; /* reserve 10 fds ; will be incremented by socket eaters */ + for (i = 0; i < MAX_PROCS; ++i) { + ha_cpuset_zero(&global.cpu_map.proc[i]); + ha_cpuset_zero(&global.cpu_map.proc_t1[i]); + ha_cpuset_zero(&global.cpu_map.thread[i]); + } + /* in wait mode, we don't try to read the configuration files */ if (!(global.mode & MODE_MWORKER_WAIT)) { char *env_cfgfiles = NULL; @@ -2925,23 +2933,15 @@ int main(int argc, char **argv) #ifdef USE_CPU_AFFINITY if (proc < global.nbproc && /* child */ proc < MAX_PROCS && /* only the first 32/64 processes may be pinned */ - global.cpu_map.proc[proc]) /* only do this if the process has a CPU map */ -#ifdef __FreeBSD__ - { - cpuset_t cpuset; - int i; - unsigned long cpu_map = global.cpu_map.proc[proc]; + ha_cpuset_count(&global.cpu_map.proc[proc])) { /* only do this if the process has a CPU map */ - CPU_ZERO(&cpuset); - while ((i = ffsl(cpu_map)) > 0) { - CPU_SET(i - 1, &cpuset); - cpu_map &= ~(1UL << (i - 1)); - } - ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(cpuset), &cpuset); - } + struct hap_cpuset *set = &global.cpu_map.proc[proc]; +#ifdef __FreeBSD__ + ret = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, sizeof(set->cpuset), &set->cpuset); #elif defined(__linux__) || defined(__DragonFly__) - sched_setaffinity(0, sizeof(unsigned long), (void *)&global.cpu_map.proc[proc]); + sched_setaffinity(0, sizeof(set->cpuset), &set->cpuset); #endif + } #endif /* close the pidfile both in children and father */ if (pidfd >= 0) { @@ -3179,14 +3179,14 @@ int main(int argc, char **argv) global.cpu_map.thread[0] = global.cpu_map.proc_t1[relative_pid-1]; for (i = 0; i < global.nbthread; i++) { - if (global.cpu_map.proc[relative_pid-1]) - global.cpu_map.thread[i] &= global.cpu_map.proc[relative_pid-1]; + if (ha_cpuset_count(&global.cpu_map.proc[relative_pid-1])) + ha_cpuset_and(&global.cpu_map.thread[i], &global.cpu_map.proc[relative_pid-1]); if (i < MAX_THREADS && /* only the first 32/64 threads may be pinned */ - global.cpu_map.thread[i]) {/* only do this if the thread has a THREAD map */ + ha_cpuset_count(&global.cpu_map.thread[i])) {/* only do this if the thread has a THREAD map */ #if defined(__APPLE__) int j; - unsigned long cpu_map = global.cpu_map.thread[i]; + unsigned long cpu_map = global.cpu_map.thread[i].cpuset; while ((j = ffsl(cpu_map)) > 0) { thread_affinity_policy_data_t cpu_set = { j - 1 }; @@ -3195,22 +3195,9 @@ int main(int argc, char **argv) cpu_map &= ~(1UL << (j - 1)); } #else -#if defined(__FreeBSD__) || defined(__NetBSD__) - cpuset_t cpuset; -#else - cpu_set_t cpuset; -#endif - int j; - unsigned long cpu_map = global.cpu_map.thread[i]; - - CPU_ZERO(&cpuset); - - while ((j = ffsl(cpu_map)) > 0) { - CPU_SET(j - 1, &cpuset); - cpu_map &= ~(1UL << (j - 1)); - } + struct hap_cpuset *set = &global.cpu_map.thread[i]; pthread_setaffinity_np(ha_thread_info[i].pthread, - sizeof(cpuset), &cpuset); + sizeof(set->cpuset), &set->cpuset); #endif } } -- 2.39.5