diff options
Diffstat (limited to 'lib/nproc.c')
-rw-r--r-- | lib/nproc.c | 133 |
1 files changed, 86 insertions, 47 deletions
diff --git a/lib/nproc.c b/lib/nproc.c index 78e13e3bf..fef1f8b20 100644 --- a/lib/nproc.c +++ b/lib/nproc.c @@ -1,6 +1,6 @@ /* Detect the number of processors. - Copyright (C) 2009-2017 Free Software Foundation, Inc. + Copyright (C) 2009-2021 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -13,13 +13,14 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. */ + along with this program; if not, see <https://www.gnu.org/licenses/>. */ /* Written by Glen Lenker and Bruno Haible. */ #include <config.h> #include "nproc.h" +#include <limits.h> #include <stdlib.h> #include <unistd.h> @@ -45,17 +46,19 @@ # include <sys/param.h> #endif -#if HAVE_SYS_SYSCTL_H +#if HAVE_SYS_SYSCTL_H && ! defined __GLIBC__ # include <sys/sysctl.h> #endif -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if defined _WIN32 && ! defined __CYGWIN__ # define WIN32_LEAN_AND_MEAN # include <windows.h> #endif #include "c-ctype.h" +#include "minmax.h" + #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /* Return the number of processors available to the current process, based @@ -173,7 +176,7 @@ num_processors_via_affinity_mask (void) } #endif -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if defined _WIN32 && ! defined __CYGWIN__ { /* This works on native Windows platforms. */ DWORD_PTR process_mask; DWORD_PTR system_mask; @@ -196,41 +199,12 @@ num_processors_via_affinity_mask (void) return 0; } -unsigned long int -num_processors (enum nproc_query query) -{ - if (query == NPROC_CURRENT_OVERRIDABLE) - { - /* Test the environment variable OMP_NUM_THREADS, recognized also by all - programs that are based on OpenMP. The OpenMP spec says that the - value assigned to the environment variable "may have leading and - trailing white space". */ - const char *envvalue = getenv ("OMP_NUM_THREADS"); - - if (envvalue != NULL) - { - while (*envvalue != '\0' && c_isspace (*envvalue)) - envvalue++; - /* Convert it from decimal to 'unsigned long'. */ - if (c_isdigit (*envvalue)) - { - char *endptr = NULL; - unsigned long int value = strtoul (envvalue, &endptr, 10); - - if (endptr != NULL) - { - while (*endptr != '\0' && c_isspace (*endptr)) - endptr++; - if (*endptr == '\0') - return (value > 0 ? value : 1); - } - } - } - - query = NPROC_CURRENT; - } - /* Here query is one of NPROC_ALL, NPROC_CURRENT. */ +/* Return the total number of processors. Here QUERY must be one of + NPROC_ALL, NPROC_CURRENT. The result is guaranteed to be at least 1. */ +static unsigned long int +num_processors_ignoring_omp (enum nproc_query query) +{ /* On systems with a modern affinity mask system call, we have sysconf (_SC_NPROCESSORS_CONF) >= sysconf (_SC_NPROCESSORS_ONLN) @@ -242,8 +216,9 @@ num_processors (enum nproc_query query) Note! On Linux systems with glibc, the first and second number come from the /sys and /proc file systems (see glibc/sysdeps/unix/sysv/linux/getsysstats.c). - In some situations these file systems are not mounted, and the sysconf - call returns 1, which does not reflect the reality. */ + In some situations these file systems are not mounted, and the sysconf call + returns 1 or 2 (<https://sourceware.org/bugzilla/show_bug.cgi?id=21542>), + which does not reflect the reality. */ if (query == NPROC_CURRENT) { @@ -275,13 +250,13 @@ num_processors (enum nproc_query query) /* On Linux systems with glibc, this information comes from the /sys and /proc file systems (see glibc/sysdeps/unix/sysv/linux/getsysstats.c). In some situations these file systems are not mounted, and the - sysconf call returns 1. But we wish to guarantee that + sysconf call returns 1 or 2. But we wish to guarantee that num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT). */ - if (nprocs == 1) + if (nprocs == 1 || nprocs == 2) { unsigned long nprocs_current = num_processors_via_affinity_mask (); - if (nprocs_current > 0) + if (/* nprocs_current > 0 && */ nprocs_current > nprocs) nprocs = nprocs_current; } # endif @@ -320,7 +295,7 @@ num_processors (enum nproc_query query) MP_NAPROCS yields the number of processors available to unprivileged processes. */ int nprocs = - sysmp (query == NPROC_CURRENT && getpid () != 0 + sysmp (query == NPROC_CURRENT && getuid () != 0 ? MP_NAPROCS : MP_NPROCS); if (nprocs > 0) @@ -331,7 +306,7 @@ num_processors (enum nproc_query query) /* Finally, as fallback, use the APIs that don't distinguish between NPROC_CURRENT and NPROC_ALL. */ -#if HAVE_SYSCTL && defined HW_NCPU +#if HAVE_SYSCTL && ! defined __GLIBC__ && defined HW_NCPU { /* This works on Mac OS X, FreeBSD, NetBSD, OpenBSD. */ int nprocs; size_t len = sizeof (nprocs); @@ -344,7 +319,7 @@ num_processors (enum nproc_query query) } #endif -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +#if defined _WIN32 && ! defined __CYGWIN__ { /* This works on native Windows platforms. */ SYSTEM_INFO system_info; GetSystemInfo (&system_info); @@ -355,3 +330,67 @@ num_processors (enum nproc_query query) return 1; } + +/* Parse OMP environment variables without dependence on OMP. + Return 0 for invalid values. */ +static unsigned long int +parse_omp_threads (char const* threads) +{ + unsigned long int ret = 0; + + if (threads == NULL) + return ret; + + /* The OpenMP spec says that the value assigned to the environment variables + "may have leading and trailing white space". */ + while (*threads != '\0' && c_isspace (*threads)) + threads++; + + /* Convert it from positive decimal to 'unsigned long'. */ + if (c_isdigit (*threads)) + { + char *endptr = NULL; + unsigned long int value = strtoul (threads, &endptr, 10); + + if (endptr != NULL) + { + while (*endptr != '\0' && c_isspace (*endptr)) + endptr++; + if (*endptr == '\0') + return value; + /* Also accept the first value in a nesting level, + since we can't determine the nesting level from env vars. */ + else if (*endptr == ',') + return value; + } + } + + return ret; +} + +unsigned long int +num_processors (enum nproc_query query) +{ + unsigned long int omp_env_limit = ULONG_MAX; + + if (query == NPROC_CURRENT_OVERRIDABLE) + { + unsigned long int omp_env_threads; + /* Honor the OpenMP environment variables, recognized also by all + programs that are based on OpenMP. */ + omp_env_threads = parse_omp_threads (getenv ("OMP_NUM_THREADS")); + omp_env_limit = parse_omp_threads (getenv ("OMP_THREAD_LIMIT")); + if (! omp_env_limit) + omp_env_limit = ULONG_MAX; + + if (omp_env_threads) + return MIN (omp_env_threads, omp_env_limit); + + query = NPROC_CURRENT; + } + /* Here query is one of NPROC_ALL, NPROC_CURRENT. */ + { + unsigned long nprocs = num_processors_ignoring_omp (query); + return MIN (nprocs, omp_env_limit); + } +} |