Fix affinity mask handling in nproc for large CPU counts

Kudos to Florian Weimer for fixing this issue in Fedora!

Resolves: RHEL-54139
This commit is contained in:
Lukáš Zaoral 2024-11-26 10:19:20 +01:00
parent afd6388b5a
commit e02e49c0ff
No known key found for this signature in database
GPG Key ID: 39157506DD67752D
3 changed files with 129 additions and 2 deletions

View File

@ -0,0 +1,55 @@
commit 45c2456a56337ebcafe0dd9faa2bd995ccbc3357
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Nov 11 14:05:53 2024 +0100
nproc: Use affinity mask even on systems with more than 1024 CPUs.
* lib/nproc.c (num_processors_via_affinity_mask): Retry
with larger affinity masks if CPU_ALLOC_SIZE is available.
diff --git a/lib/nproc.c b/lib/nproc.c
index 92a07e8289..48bc3d06fa 100644
--- a/lib/nproc.c
+++ b/lib/nproc.c
@@ -20,6 +20,7 @@
#include <config.h>
#include "nproc.h"
+#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
@@ -124,6 +125,33 @@ num_processors_via_affinity_mask (void)
return count;
}
}
+#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC \
+ && defined CPU_ALLOC_SIZE /* glibc >= 2.6 */
+ {
+ unsigned int alloc_count = 1024;
+ while (1)
+ {
+ cpu_set_t *set = CPU_ALLOC (alloc_count);
+ if (set == NULL)
+ return 0;
+ unsigned int size = CPU_ALLOC_SIZE (alloc_count);
+ if (sched_getaffinity (0, size, set) == 0)
+ {
+ unsigned int count = CPU_COUNT_S (size, set);
+ CPU_FREE (set);
+ return count;
+ }
+ if (errno != EINVAL)
+ {
+ CPU_FREE (set);
+ return 0;
+ }
+ CPU_FREE (set);
+ alloc_count *= 2;
+ if (alloc_count == 0)
+ return 0;
+ }
+ }
#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
{
cpu_set_t set;

View File

@ -0,0 +1,64 @@
commit ee0bc695303775da5026091a65e8ec2b764f4a26
Author: Bruno Haible <bruno@clisp.org>
Date: Mon Nov 11 15:40:52 2024 +0100
nproc: Use affinity mask even in out-of-memory situations.
* lib/nproc.c (num_processors_via_affinity_mask): Use a stack-allocated
cpu_set_t as fallback. Add comments.
diff --git a/lib/nproc.c b/lib/nproc.c
index 48bc3d06fa..0b5898d88f 100644
--- a/lib/nproc.c
+++ b/lib/nproc.c
@@ -125,15 +125,25 @@ num_processors_via_affinity_mask (void)
return count;
}
}
-#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC \
- && defined CPU_ALLOC_SIZE /* glibc >= 2.6 */
+#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
+ /* There are two ways to use the sched_getaffinity() function:
+ - With a statically-sized cpu_set_t.
+ - With a dynamically-sized cpu_set_t.
+ Documentation:
+ <https://www.kernel.org/doc/man-pages/online/pages/man2/sched_getaffinity.2.html>
+ <https://www.kernel.org/doc/man-pages/online/pages/man3/CPU_SET.3.html>
+ The second way has the advantage that it works on systems with more than
+ 1024 CPUs. The first way has the advantage that it works also when memory
+ is tight. */
+# if defined CPU_ALLOC_SIZE /* glibc >= 2.6 */
{
unsigned int alloc_count = 1024;
- while (1)
+ for (;;)
{
cpu_set_t *set = CPU_ALLOC (alloc_count);
if (set == NULL)
- return 0;
+ /* Out of memory. */
+ break;
unsigned int size = CPU_ALLOC_SIZE (alloc_count);
if (sched_getaffinity (0, size, set) == 0)
{
@@ -143,16 +153,19 @@ num_processors_via_affinity_mask (void)
}
if (errno != EINVAL)
{
+ /* Some other error. */
CPU_FREE (set);
return 0;
}
CPU_FREE (set);
+ /* Retry with some larger cpu_set_t. */
alloc_count *= 2;
if (alloc_count == 0)
+ /* Integer overflow. Avoid an endless loop. */
return 0;
}
}
-#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
+# endif
{
cpu_set_t set;

View File

@ -1,7 +1,7 @@
Summary: A set of basic GNU tools commonly used in shell scripts Summary: A set of basic GNU tools commonly used in shell scripts
Name: coreutils Name: coreutils
Version: 8.32 Version: 8.32
Release: 37%{?dist} Release: 38%{?dist}
License: GPLv3+ License: GPLv3+
Url: https://www.gnu.org/software/coreutils/ Url: https://www.gnu.org/software/coreutils/
Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz
@ -76,6 +76,11 @@ Patch20: coreutils-8.32-tail-64kpages.patch
# fix extended upstream test suite failures (RHEL-60290) # fix extended upstream test suite failures (RHEL-60290)
Patch21: coreutils-8.32-fix-extended-testsuite.patch Patch21: coreutils-8.32-fix-extended-testsuite.patch
# Fix affinity mask handling in nproc for large CPU counts (RHEL-54139)
# https://bugzilla.redhat.com/show_bug.cgi?id=2325167
Patch22: coreutils-nproc-affinity-1.patch
Patch23: coreutils-nproc-affinity-2.patch
# disable the test-lock gnulib test prone to deadlock # disable the test-lock gnulib test prone to deadlock
Patch100: coreutils-8.26-test-lock.patch Patch100: coreutils-8.26-test-lock.patch
@ -325,7 +330,10 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir
%license COPYING %license COPYING
%changelog %changelog
* Tue Oct 22 2024 Lukáš Zaoral <lzaoral@redhat.com> * Tue Nov 26 2024 Lukáš Zaoral <lzaoral@redhat.com> - 8.32-38
- fix affinity mask handling in nproc for large CPU counts (RHEL-54139)
* Tue Oct 22 2024 Lukáš Zaoral <lzaoral@redhat.com> - 8.32-37
- fix extended upstream test suite failures (RHEL-60290) - fix extended upstream test suite failures (RHEL-60290)
* Fri Aug 16 2024 Lukáš Zaoral <lzaoral@redhat.com> - 8.32-36 * Fri Aug 16 2024 Lukáš Zaoral <lzaoral@redhat.com> - 8.32-36