On 28/11/16 06:34, Oliver Heimlich wrote:
> Follow-Up: Savannah bugs #48534 #48535.
> 
> Hi,
> I have two problems with the function num_processors in libgnu's nproc.c.
> 
> 
> FIRST PROBLEM
> 
> num_processors (NPROC_CURRENT_OVERRIDABLE) returns the value of
> OMP_NUM_THREADS. However, if a thread limit is defined, it should return
> the minimum of OMP_NUM_THREADS and OMP_THREAD_LIMIT.
> 
> 
> OMP_THREAD_LIMIT=1 OMP_NUM_THREADS=2 ./run-my-program
> - What I get: 2
> - What I expect: 1
> - Reason: The effective number of threads cannot exceed the thread limit.
> 
> 
> SECOND PROBLEM
> 
> num_processors (NPROC_CURRENT_OVERRIDABLE) parses the environment
> variable OMP_NUM_THREADS for an integer. However, according to OpenMP
> documentation it may be a list of integers. In that case, the function
> ignores the value of OMP_NUM_THREADS. See
> https://gcc.gnu.org/onlinedocs/libgomp/OMP_005fNUM_005fTHREADS.html
> 
> 
> OMP_NUM_THREADS=2,2,1 ./run-my-program
> - What I get: 4
> - What I expect: 2 or 1 depending on the current OpenMP nesting level

There is no way to determine the current nesting level,
without actually using OpenMP, so I added support
for calling omp_get_num_threads() if _OPENMP is defined.
I'm not 100% sure it's valid to do that without depending on
the openmp module (which I think it's best not for nproc to do),
so I'm open to removing that portion.

Also I added support for deferring to the first nesting level
in OMP_NUM_THREADS, and for OMP_THREADS_LIMIT like you suggest.

Tesing coreutils' nproc (without _OPENMP) with this change gives:

$ src/nproc
4
$ OMP_THREADS_LIMIT=1 src/nproc
4
$ OMP_NUM_THREADS=2,2,1 src/nproc
2
$ OMP_NUM_THREADS=2bad src/nproc
4
$ OMP_THREADS_LIMIT=1 OMP_NUM_THREADS=2,2,1 src/nproc
1
$ OMP_THREADS_LIMIT=0 OMP_NUM_THREADS=2,2,1 src/nproc
2
$ OMP_THREADS_LIMIT=1bad OMP_NUM_THREADS=2,2,1 src/nproc
2
$ OMP_THREADS_LIMIT=1b OMP_NUM_THREADS=12,2,1 src/nproc
12
$ OMP_THREADS_LIMIT=1 OMP_NUM_THREADS=12 src/nproc
1
$ OMP_THREADS_LIMIT=111 OMP_NUM_THREADS=12 src/nproc
12
$ OMP_NUM_THREADS=12 nproc
12

cheers,
Pádraig
From 41137bbc339ede60f39eaf9db3d61188e0ab1e8c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Mon, 20 Feb 2017 20:26:35 -0800
Subject: [PATCH] nproc: support nested OMP_NUM_THREADS, and OMP_THREAD_LIMIT

* lib/nproc.c (parse_omp_threads): A new function refactored
from num_processors() to support parsing both of the
above environment variables.
(num_processors): Prefer using omp_get_num_threads() with [_OPENMP]
to accurately reflect the current OpenMP nesting level.
Also support the OMP_THREAD_LIMIT environment variable
to limit the max value determined from OMP_NUM_THREADS.
* modules/nproc: Depend on minmax header.
Suggested by Oliver Heimlich.
---
 lib/nproc.c   | 82 +++++++++++++++++++++++++++++++++++++++++++----------------
 modules/nproc |  1 +
 2 files changed, 61 insertions(+), 22 deletions(-)

diff --git a/lib/nproc.c b/lib/nproc.c
index 9053d75..3d9007b 100644
--- a/lib/nproc.c
+++ b/lib/nproc.c
@@ -54,8 +54,14 @@
 # include <windows.h>
 #endif
 
+#if defined(_OPENMP)
+# include <omp.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
@@ -196,35 +202,67 @@ num_processors_via_affinity_mask (void)
   return 0;
 }
 
+/* Parse OMP environment variables without dependence on OMP.
+   Return > 0 for valid 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 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 > 0 ? value : 1);
+          /* 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 > 0 ? value : 1);
+        }
+    }
+
+  return ret;
+}
+
 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");
+      unsigned long int omp_env_threads;
+      unsigned long int omp_env_limit;
+
+/* If OPENMP is enabled with AC_OPENMP, then use OPENMP to
+   get the number of threads for the current nesting level.  */
+#if defined(_OPENMP)
+      return omp_get_num_threads ();
+#endif
 
-      if (envvalue != NULL)
+      /* 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"));
+      if (omp_env_threads)
         {
-          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);
-                }
-            }
+          omp_env_limit = parse_omp_threads (getenv ("OMP_THREADS_LIMIT"));
+          if (omp_env_limit > 1)
+            omp_env_threads = MIN (omp_env_threads, omp_env_limit);
+
+          return omp_env_threads;
         }
 
       query = NPROC_CURRENT;
diff --git a/modules/nproc b/modules/nproc
index 2cbf04d..5259579 100644
--- a/modules/nproc
+++ b/modules/nproc
@@ -9,6 +9,7 @@ m4/nproc.m4
 Depends-on:
 c-ctype
 extensions
+minmax
 unistd
 
 configure.ac:
-- 
2.5.5

Reply via email to