]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Follow the number of CPU set by taskset/cpuset
authorOndřej Surý <ondrej@isc.org>
Thu, 22 Aug 2024 15:23:09 +0000 (17:23 +0200)
committerNicki Křížek <nicki@isc.org>
Tue, 3 Sep 2024 13:52:10 +0000 (13:52 +0000)
Administrators may wish to constrain the set of cores that BIND 9 runs
on via the 'taskset', 'cpuset' or 'numactl' programs (or equivalent on
other O/S), for example to achieve higher (or more stable) performance
by more closely associating threads with individual NIC rx queues. If
the admin has used taskset, it follows that BIND ought to
automatically use the given number of CPUs rather than the system wide
count.

Co-Authored-By: Ray Bellis <ray@isc.org>
(cherry picked from commit 5a2df8caf5c7c2def7266dc10dde60ef92d4ccb7)

bin/tests/system/Makefile.am
bin/tests/system/cpu/clean.sh [new file with mode: 0644]
bin/tests/system/cpu/ns1/named.conf.in [new file with mode: 0644]
bin/tests/system/cpu/prereq.sh [new file with mode: 0644]
bin/tests/system/cpu/setup.sh [new file with mode: 0644]
bin/tests/system/cpu/tests.sh [new file with mode: 0755]
bin/tests/system/cpu/tests_sh_cpu.py [new file with mode: 0644]
configure.ac
lib/isc/os.c

index 842bb5db8b9caf90c9712d2ebeed2ffab8d46c7c..54fd7ed5fa73dd44dbf3d3adc167fed2e01a3da3 100644 (file)
@@ -95,6 +95,7 @@ TESTS =                               \
        checknames              \
        checkzone               \
        cookie                  \
+       cpu                     \
        database                \
        dialup                  \
        digdelv                 \
diff --git a/bin/tests/system/cpu/clean.sh b/bin/tests/system/cpu/clean.sh
new file mode 100644 (file)
index 0000000..cff7c61
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+set -e
+
+rm -f ./named.run.*
diff --git a/bin/tests/system/cpu/ns1/named.conf.in b/bin/tests/system/cpu/ns1/named.conf.in
new file mode 100644 (file)
index 0000000..6c934b2
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+options {
+       query-source address 10.53.0.1;
+       port @PORT@;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+};
diff --git a/bin/tests/system/cpu/prereq.sh b/bin/tests/system/cpu/prereq.sh
new file mode 100644 (file)
index 0000000..7f9f6c0
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+. ../conf.sh
+
+command -v cpuset >/dev/null || command -v numactl >/dev/null || command -v taskset >/dev/null || {
+  echo_i "This test requires cpuset, numactl, or taskset." >&2
+  exit 255
+}
+
+exit 0
diff --git a/bin/tests/system/cpu/setup.sh b/bin/tests/system/cpu/setup.sh
new file mode 100644 (file)
index 0000000..9676770
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../conf.sh
+
+set -e
+
+$SHELL clean.sh
+
+copy_setports ns1/named.conf.in ns1/named.conf
diff --git a/bin/tests/system/cpu/tests.sh b/bin/tests/system/cpu/tests.sh
new file mode 100755 (executable)
index 0000000..a521b4f
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# shellcheck source=conf.sh
+. ../conf.sh
+
+status=0
+n=0
+
+CPUSET=$(command -v cpuset)
+NUMACTL=$(command -v numactl)
+TASKSET=$(command -v taskset)
+
+cpulist() (
+  if [ -n "$CPUSET" ]; then
+    cpuset -g | head -1 | sed -e "s/.*: //" | tr -s ', ' '\n'
+  elif [ -n "$NUMACTL" ]; then
+    numactl --show | sed -ne 's/^physcpubind: //p' | tr -s ' ' '\n'
+  elif [ -n "$TASKSET" ]; then
+    # shellcheck disable=SC2046
+    seq $(taskset -c -p $$ | sed -e 's/.*: //' | tr -s ' -' ' ')
+  else
+    echo 0
+  fi
+)
+
+cpulimit() (
+  set -x
+  min_cpu="${1}"
+  shift
+  max_cpu="${1}"
+  shift
+
+  if [ -n "$CPUSET" ]; then
+    cpuset -l "${min_cpu}-${max_cpu}" "$@" 2>&1
+  elif [ -n "$NUMACTL" ]; then
+    numactl --physcpubind="${min_cpu}-${max_cpu}" "$@" 2>&1
+  elif [ -n "$TASKSET" ]; then
+    taskset -c "${min_cpu}-${max_cpu}" "$@" 2>&1
+  fi
+)
+
+ret=0
+for cpu in $(cpulist); do
+  n=$((n + 1))
+  echo_i "testing that limiting CPU sets to 0-${cpu} works ($n)"
+  cpulimit 0 "$cpu" "$NAMED" -g >named.run.$n 2>&1 || true
+  ncpus=$(sed -ne 's/.*found \([0-9]*\) CPU.*\([0-9]*\) worker thread.*/\1/p' named.run.$n)
+  [ "$ncpus" -eq "$((cpu + 1))" ] || ret=1
+done
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status + ret))
+
+echo_i "exit status: $status"
+[ $status -eq 0 ] || exit 1
diff --git a/bin/tests/system/cpu/tests_sh_cpu.py b/bin/tests/system/cpu/tests_sh_cpu.py
new file mode 100644 (file)
index 0000000..264dc27
--- /dev/null
@@ -0,0 +1,14 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+
+def test_cpu(run_tests_sh):
+    run_tests_sh()
index 6929a5974dba962572ddbfca7cc5927d760b4969..6a85460ea44fd6e621febb5e3ba8ab273a57e3b9 100644 (file)
@@ -342,7 +342,8 @@ AS_CASE([$host],
                  ])
        ])
 
-AC_CHECK_HEADERS([fcntl.h regex.h sys/time.h unistd.h sys/mman.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h sys/socket.h net/route.h linux/netlink.h linux/rtnetlink.h], [], [],
+AC_CHECK_HEADERS([sys/param.h sys/socket.h])
+AC_CHECK_HEADERS([fcntl.h regex.h sys/time.h unistd.h sys/mman.h sys/sockio.h sys/select.h sys/sysctl.h net/if6.h net/route.h linux/netlink.h linux/rtnetlink.h], [], [],
                 [$ac_includes_default
                  #ifdef HAVE_SYS_PARAM_H
                  # include <sys/param.h>
@@ -625,9 +626,16 @@ AM_CONDITIONAL([HAVE_LIBNGHTTP2], [test -n "$LIBNGHTTP2_LIBS"])
 AC_CHECK_FUNCS([flockfile getc_unlocked])
 
 #
-# Look for sysconf to allow detection of the number of processors.
+# Look for sysconf or other ways to allow detection of the number of processors.
 #
 AC_CHECK_FUNCS([sysconf])
+AC_CHECK_FUNCS(sysconf sched_getaffinity cpuset_getaffinity)
+AC_CHECK_HEADERS([sys/cpuset.h], [], [],
+                [$ac_includes_default
+                 #ifdef HAVE_SYS_PARAM_H
+                 # include <sys/param.h>
+                 #endif
+                ])
 
 #
 # Do we want to use pthread rwlock?
index 0ba0fab43cbeb61556251b61d8df238d08192cfc..fced991903109ec32bbb985ca806710baa6781bd 100644 (file)
@@ -59,17 +59,94 @@ sysctl_ncpus(void) {
 }
 #endif /* if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME) */
 
+#if defined(HAVE_SCHED_GETAFFINITY)
+
+#if defined(HAVE_SCHED_H)
+#include <sched.h>
+#endif
+
+/*
+ * Administrators may wish to constrain the set of cores that BIND runs
+ * on via the 'taskset' or 'numactl' programs (or equivalent on other
+ * O/S), for example to achieve higher (or more stable) performance by
+ * more closely associating threads with individual NIC rx queues. If
+ * the admin has used taskset, it follows that BIND ought to
+ * automatically use the given number of CPUs rather than the system
+ * wide count.
+ */
+static int
+sched_affinity_ncpus(void) {
+       cpu_set_t cpus;
+       int result;
+
+       result = sched_getaffinity(0, sizeof(cpus), &cpus);
+       if (result != -1) {
+#ifdef CPU_COUNT
+               return (CPU_COUNT(&cpus));
+#else
+               int i, n = 0;
+
+               for (i = 0; i < CPU_SETSIZE; ++i) {
+                       if (CPU_ISSET(i, &cpus))
+                               ++n;
+               }
+               return (n);
+#endif
+       }
+       return (0);
+}
+#endif
+
+/*
+ * Affinity detecting variant of sched_affinity_cpus() for FreeBSD
+ */
+
+#if defined(HAVE_SYS_CPUSET_H) && defined(HAVE_CPUSET_GETAFFINITY)
+#include <sys/cpuset.h>
+#include <sys/param.h>
+
+static int
+cpuset_affinity_ncpus(void) {
+       cpuset_t cpus;
+       int result;
+
+       result = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1,
+                                   sizeof(cpus), &cpus);
+       if (result != -1) {
+               int i, n = 0;
+               for (i = 0; i < CPU_SETSIZE; ++i) {
+                       if (CPU_ISSET(i, &cpus))
+                               ++n;
+               }
+               return (n);
+       }
+       return (0);
+}
+#endif
+
 static void
 ncpus_initialize(void) {
+#if defined(HAVE_SYS_CPUSET_H) && defined(HAVE_CPUSET_GETAFFINITY)
+       if (isc__os_ncpus <= 0) {
+               isc__os_ncpus = cpuset_affinity_ncpus();
+       }
+#endif
+#if defined(HAVE_SCHED_GETAFFINITY)
+       if (isc__os_ncpus <= 0) {
+               isc__os_ncpus = sched_affinity_ncpus();
+       }
+#endif
 #if defined(HAVE_SYSCONF)
-       isc__os_ncpus = sysconf_ncpus();
+       if (isc__os_ncpus <= 0) {
+               isc__os_ncpus = sysconf_ncpus();
+       }
 #endif /* if defined(HAVE_SYSCONF) */
 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)
        if (isc__os_ncpus <= 0) {
                isc__os_ncpus = sysctl_ncpus();
        }
 #endif /* if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME) */
-       if (isc__os_ncpus == 0) {
+       if (isc__os_ncpus <= 0) {
                isc__os_ncpus = 1;
        }
 }