summaryrefslogtreecommitdiff
path: root/lib/nproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nproc.c')
-rw-r--r--lib/nproc.c133
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);
+ }
+}