From 7cb1a82826e92462df199ecbf635fb5658b9abfd Mon Sep 17 00:00:00 2001
From: Florian Fischer <florian.fischer@muhq.space>
Date: Fri, 2 Jul 2021 16:58:31 +0200
Subject: [PATCH] [Runtime] use pthread_getaffinity_np to determine default
 worker count

The value reported by std::thread::hardware_concurrency() can be more
than the available CPUs to the current process for example if EMPER runs
in a container or qemu.
GNU nproc(1) does the right thing and we can take inspiration from them.
The solution is to use pthread_getaffinity_np which fills a CPU set with
all CPU a pthread can be scheduled on.
We use this more precise CPU count if possible.
---
 emper/Runtime.cpp | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/emper/Runtime.cpp b/emper/Runtime.cpp
index 5ab9afc2..14a68bf8 100644
--- a/emper/Runtime.cpp
+++ b/emper/Runtime.cpp
@@ -264,6 +264,23 @@ auto Runtime::getDefaultWorkerCount() -> workerid_t {
 		return static_cast<workerid_t>(workerCountInt);
 	}
 
+	// The CPU count reported by sysconf(_SC_NPROCESSORS_ONLN), sysconf(_SC_NPROCESSORS_CONF)
+	// or std::thread::hardware_concurrency() may not match the CPU count available
+	// to the emper process.
+	// This can happen for example if we run EMPER in a container or qemu.o
+	// GNU nproc(1) does report the correct CPU count using pthread_getaffinity_np
+	// which fills a cpu_set with the CPUs the current process can be scheduled on
+	// therefore we use this more precise CPU count if possible.
+	// Code inspiration taken from:
+	// https://github.com/coreutils/gnulib/blob/90e79512d8b385801218d6e9c4d88ff77186560b/lib/nproc.c#L206
+	cpu_set_t set;
+	if (pthread_getaffinity_np(pthread_self(), sizeof(set), &set) == 0) {
+		unsigned long count = CPU_COUNT(&set);
+		if (count > 0) {
+			return count;
+		}
+	}
+
 	return std::thread::hardware_concurrency();
 }
 
-- 
GitLab