]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: global: add option to disable numa detection
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 26 Mar 2021 17:50:33 +0000 (18:50 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 23 Apr 2021 14:06:49 +0000 (16:06 +0200)
Render numa detection optional with a global configuration statement
'no numa-cpu-mapping'. This can be used if the applied affinity of the
algorithm is not optimal. Also complete the documentation with this new
keyword.

doc/configuration.txt
include/haproxy/global-t.h
src/cfgparse-global.c
src/cfgparse.c
src/haproxy.c

index c50700f12495bdddd54c5bcc2f2aeb771aca19be..8827f9bb7f547eb026f4d594781b465d467f8139 100644 (file)
@@ -919,6 +919,7 @@ The following keywords are supported in the "global" section :
    - nbproc
    - nbthread
    - node
+   - numa-cpu-mapping
    - pidfile
    - pp2-never-send-local
    - presetenv
@@ -1540,6 +1541,17 @@ nbthread <number>
   like "taskset" or "cpuset". Otherwise, this value defaults to 1. The default
   value is reported in the output of "haproxy -vv". See also "nbproc".
 
+numa-cpu-mapping
+  By default, if running on Linux, haproxy inspects on startup the CPU topology
+  of the machine. If a multi-socket machine is detected, the affinity is
+  automatically calculated to run on the CPUs of a single node. This is done in
+  order to not suffer from the performance penalties caused by the inter-socket
+  bus latency. However, if the applied binding is non optimal on a particular
+  architecture, it can be disabled with the statement 'no numa-cpu-mapping'.
+  This automatic binding is also not applied if a nbthread statement is present
+  in the configuration, or the affinity of the process is already specified,
+  for example via the 'cpu-map' directive or the taskset utility.
+
 pidfile <pidfile>
   Writes PIDs of all daemons into file <pidfile> when daemon mode or writes PID
   of master process into file <pidfile> when master-worker mode. This option is
index bc734a6d02eefefe74bbbc1abc48b5129b6b4fd9..03a6a5030937cc183b2626649b8b1b7ab02c08ef 100644 (file)
@@ -166,6 +166,7 @@ struct global {
                struct hap_cpuset thread[MAX_THREADS];  /* list of CPU masks for the 32/64 first threads of the 1st process */
        } cpu_map;
 #endif
+       int numa_cpu_mapping;
        /* The info above is config stuff, it doesn't change during the process' life */
        /* A number of the elements below are updated by all threads in real time and
         * suffer high contention, so we need to put them in their own cache lines, if
index 89e3b10b0ad2177a7f3cbeb8dd58dbd0f33036ad..47de32a6b1f3fd951526fb8e3bf49dc86d16ef3f 100644 (file)
@@ -42,7 +42,8 @@ static const char *common_kw_list[] = {
        "log-send-hostname", "server-state-base", "server-state-file",
        "log-tag", "spread-checks", "max-spread-checks", "cpu-map", "setenv",
        "presetenv", "unsetenv", "resetenv", "strict-limits", "localpeer",
-       "defaults", "listen", "frontend", "backend", "peers", "resolvers",
+       "numa-cpu-mapping", "defaults", "listen", "frontend", "backend",
+       "peers", "resolvers",
        NULL /* must be last */
 };
 
@@ -1288,6 +1289,9 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                }
                setenv("HAPROXY_LOCALPEER", localpeer, 1);
        }
+       else if (strcmp(args[0], "numa-cpu-mapping") == 0) {
+               global.numa_cpu_mapping = (kwm == KWM_NO) ? 0 : 1;
+       }
        else {
                struct cfg_kw_list *kwl;
                const char *best;
index 25820bc017e05094d0f8100d325cc0b68b459293..507d072fa3741205dae2a1669dcbb7b1b1b0a38a 100644 (file)
@@ -1846,10 +1846,12 @@ next_line:
                if (kwm != KWM_STD && strcmp(args[0], "option") != 0 &&
                    strcmp(args[0], "log") != 0 && strcmp(args[0], "busy-polling") != 0 &&
                    strcmp(args[0], "set-dumpable") != 0 && strcmp(args[0], "strict-limits") != 0 &&
-                   strcmp(args[0], "insecure-fork-wanted") != 0) {
+                   strcmp(args[0], "insecure-fork-wanted") != 0 &&
+                   strcmp(args[0], "numa-cpu-mapping") != 0) {
                        ha_alert("parsing [%s:%d]: negation/default currently "
                                 "supported only for options, log, busy-polling, "
-                                "set-dumpable, strict-limits, and insecure-fork-wanted.\n", file, linenum);
+                                "set-dumpable, strict-limits, insecure-fork-wanted "
+                                "and numa-cpu-mapping.\n", file, linenum);
                        err_code |= ERR_ALERT | ERR_FATAL;
                        fatal++;
                }
@@ -2189,7 +2191,7 @@ int check_config_validity()
                if (global.nbproc == 1) {
                        int numa_cores = 0;
 #if defined(__linux__) && defined USE_CPU_AFFINITY
-                       if (!thread_cpu_mask_forced())
+                       if (global.numa_cpu_mapping && !thread_cpu_mask_forced())
                                numa_cores = numa_detect_topology();
 #endif
                        global.nbthread = numa_cores ? numa_cores :
index 58e9e62f9e9beb5415d8185ecb4ef5e21a3d6aa3..b89c51779f28fc56a04c2695efdd9a5dc802101b 100644 (file)
@@ -160,6 +160,7 @@ volatile unsigned long stopping_thread_mask = 0; /* Threads acknowledged stoppin
 struct global global = {
        .hard_stop_after = TICK_ETERNITY,
        .nbproc = 1,
+       .numa_cpu_mapping = 1,
        .nbthread = 0,
        .req_count = 0,
        .logsrvs = LIST_HEAD_INIT(global.logsrvs),