]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cpu-set-util: introduce cpus_online().
authorLennart Poettering <lennart@amutable.com>
Wed, 13 May 2026 12:59:35 +0000 (14:59 +0200)
committerLennart Poettering <lennart@amutable.com>
Thu, 14 May 2026 06:12:28 +0000 (08:12 +0200)
Add a helper that tries to determine the number of installed CPUs. This
borrows heavily from physical_memory(), i.e. uses the physical number,
but caps by per-container cpuset.

src/modules-load/modules-load.c
src/shared/cpu-set-util.c
src/shared/cpu-set-util.h
src/test/test-cpu-set-util.c

index 0917f800a1a84cf9a1554b84795868916b5c705d..eb58b70c7b06cad9b0141770c81ebee862b3ed5e 100644 (file)
@@ -11,6 +11,7 @@
 #include "build.h"
 #include "conf-files.h"
 #include "constants.h"
+#include "cpu-set-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -314,13 +315,13 @@ static unsigned determine_num_worker_threads(unsigned n_modules) {
         if (n_threads == UINT_MAX) {
                 /* By default, use a number of worker threads equal the number of online CPUs,
                  * but clamp it to avoid a probing storm on machines with many CPUs. */
-                long ncpus = sysconf(_SC_NPROCESSORS_ONLN);
-                if (ncpus < 0) {
-                        log_warning_errno(errno, "Failed to get number of online CPUs, ignoring: %m");
-                        ncpus = 1;
-                }
-
-                n_threads = CLAMP((unsigned)ncpus, 1U, 16U);
+                unsigned n_cpus;
+                r = cpus_online(&n_cpus);
+                if (r < 0) {
+                        log_warning_errno(r, "Failed to get number of online CPUs, ignoring: %m");
+                        n_threads = 1;
+                } else
+                        n_threads = CLAMP(n_cpus, 1U, 16U);
         }
 
         /* There's no reason to spawn more threads than the modules that need to be loaded */
index 9211dbe47e54a46e8b03a26ab3ec4cb4a85db3b3..85d0e114023860fdf5aed7effa962181eea57d88 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "alloc-util.h"
 #include "bitfield.h"
+#include "cgroup-util.h"
 #include "cpu-set-util.h"
 #include "extract-word.h"
 #include "log.h"
@@ -400,3 +401,50 @@ int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *ret) {
         *ret = TAKE_STRUCT(c);
         return 0;
 }
+
+static int cgroup_cpus_effective(unsigned *ret) {
+        int r;
+
+        assert(ret);
+
+        _cleanup_free_ char *root = NULL;
+        r = cg_get_root_path(&root);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to determine root cgroup: %m");
+
+        _cleanup_free_ char *value = NULL;
+        r = cg_get_attribute(root, "cpuset.cpus.effective", &value);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to read cpuset.cpus.effective cgroup attribute: %m");
+
+        _cleanup_(cpu_set_done) CPUSet cpus = {};
+        r = parse_cpu_set(value, &cpus);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to parse cpuset.cpus.effective cgroup attribute: %m");
+
+        *ret = (unsigned) MIN(cpu_set_count(&cpus), UINT_MAX);
+        return 0;
+}
+
+int cpus_online(unsigned *ret) {
+        int r;
+
+        assert(ret);
+
+        /* In order to support containers nicely that have a configured cpuset we'll take the minimum of the
+         * physically reported amount of CPUs and the limit configured for the root cgroup, if there is
+         * any. */
+
+        long sc = sysconf(_SC_NPROCESSORS_ONLN);
+        if (sc < 0)
+                return log_debug_errno(errno, "sysconf(_SC_NPROCESSORS_ONLN) failed: %m");
+
+        unsigned cg, lc = (unsigned) CLAMP((unsigned long) sc, 1U, UINT_MAX);
+        r = cgroup_cpus_effective(&cg);
+        if (r < 0)
+                *ret = lc;
+        else
+                *ret = CLAMP(cg, 1U, lc);
+
+        return 0;
+}
index 751e9add27f09af143fc41ffce6a3e6e1d1e9f6c..1f89ce2020701eae4829669265a96a3c00644157 100644 (file)
@@ -46,3 +46,5 @@ static inline size_t cpu_set_count(const CPUSet *c) {
                 return 0;
         return CPU_COUNT_S(c->allocated, c->set);
 }
+
+int cpus_online(unsigned *ret);
index 672451ff3557636886c98ae49179260c876327bd..027e0ca2d4756fc23e1f5ea962df8e4d99251bbd 100644 (file)
@@ -284,4 +284,11 @@ TEST(cpu_set_add_range) {
         ASSERT_OK(cpu_set_add_range(&c, 0, 8191));
 }
 
+TEST(cpus_online) {
+        unsigned n_cpus = 0;
+        ASSERT_OK(cpus_online(&n_cpus));
+        ASSERT_GE(n_cpus, 1U);
+        log_info("Number of CPUs currently online: %u", n_cpus);
+}
+
 DEFINE_TEST_MAIN(LOG_DEBUG);