]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: config: use platform independent type hap_cpuset for cpu-map
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 21 Apr 2021 16:39:58 +0000 (18:39 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 23 Apr 2021 14:06:49 +0000 (16:06 +0200)
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
include/haproxy/global-t.h
src/cfgparse-global.c
src/haproxy.c

index de910043983f14801532566c2c7cd191ad11413d..c50700f12495bdddd54c5bcc2f2aeb771aca19be 100644 (file)
@@ -1063,14 +1063,16 @@ cpu-map [auto:]<process-set>[/<thread-set>] <cpu-set>...
   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
index c98a0fabaea1faee97d3b8c4047f3ebe60cc6e8e..bc734a6d02eefefe74bbbc1abc48b5129b6b4fd9 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <haproxy/api-t.h>
 #include <haproxy/buf-t.h>
+#include <haproxy/cpuset-t.h>
 #include <haproxy/freq_ctr-t.h>
 #include <haproxy/vars-t.h>
 
@@ -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 */
index 40f3018b3e21c1fa880f9d1d77f0f3d353097b72..694cd70776c8443e248d4cd7ba0e2a33170ed600 100644 (file)
@@ -1,4 +1,3 @@
-#define _GNU_SOURCE  /* for CPU_* from cpuset.h */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -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);
                                        }
                                }
                        }
index ecc5f2135ca2291b94fc86c958b0cf26053f158f..58e9e62f9e9beb5415d8185ecb4ef5e21a3d6aa3 100644 (file)
@@ -92,6 +92,7 @@
 #include <haproxy/chunk.h>
 #include <haproxy/cli.h>
 #include <haproxy/connection.h>
+#include <haproxy/cpuset.h>
 #include <haproxy/dns.h>
 #include <haproxy/dynbuf.h>
 #include <haproxy/errors.h>
@@ -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
                        }
                }