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.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index de91004..c50700f 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1063,14 +1063,16 @@
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 c98a0fa..bc734a6 100644
--- a/include/haproxy/global-t.h
+++ b/include/haproxy/global-t.h
@@ -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 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 40f3018..694cd70 100644
--- a/src/cfgparse-global.c
+++ b/src/cfgparse-global.c
@@ -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 @@
/* 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 @@
}
}
- 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 @@
*/
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 @@
* 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 ecc5f21..58e9e62 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -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 @@
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 @@
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 @@
#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 @@
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 @@
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
}
}