nproc: Refactor.
authorBruno Haible <bruno@clisp.org>
Mon, 11 Jan 2010 01:14:00 +0000 (02:14 +0100)
committerBruno Haible <bruno@clisp.org>
Mon, 11 Jan 2010 19:19:30 +0000 (20:19 +0100)
ChangeLog
lib/nproc.c

index d075b31c55b6aa7e590d1df285aedda4c008186f..f07170a623ea0105af55ed1a5aafe2aae3b4a1df 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2010-01-10  Bruno Haible  <bruno@clisp.org>
+
+       nproc: Refactor.
+       * lib/nproc.c (num_processors_via_affinity_mask): New function,
+       extracted from num_processors.
+       (num_processors): Call it.
+
 2010-01-11  Jim Meyering  <meyering@redhat.com>
 
        utimecmp: avoid new warning from upcoming gcc-4.5.0
index af4da75d188f775c6852ae62de7e2eedf2b00097..b72d7215779b1586f467efba35164e5102bc1d13 100644 (file)
@@ -1,6 +1,6 @@
 /* Detect the number of processors.
 
-   Copyright (C) 20092010 Free Software Foundation, Inc.
+   Copyright (C) 2009-2010 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
 
-unsigned long int
-num_processors (enum nproc_query query)
+/* Return the number of processors available to the current process, based
+   on a modern system call that returns the "affinity" between the current
+   process and each CPU.  Return 0 if unknown or if such a system call does
+   not exist.  */
+static unsigned long
+num_processors_via_affinity_mask (void)
 {
-  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.  */
-
-  if (query == NPROC_CURRENT)
-    {
-      /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np,
-         but with different APIs.  Also it requires linking with -lpthread.
-         Therefore this code is not enabled.
-         glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has
-         sched_getaffinity_np.  */
+  /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np,
+     but with different APIs.  Also it requires linking with -lpthread.
+     Therefore this code is not enabled.
+     glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has
+     sched_getaffinity_np.  */
 #if HAVE_PTHREAD_AFFINITY_NP && defined __GLIBC__ && 0
-      {
-        cpu_set_t set;
+  {
+    cpu_set_t set;
 
-        if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0)
-          {
-            unsigned long count;
+    if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0)
+      {
+        unsigned long count;
 
 # ifdef CPU_COUNT
-            /* glibc >= 2.6 has the CPU_COUNT macro.  */
-            count = CPU_COUNT (&set);
+        /* glibc >= 2.6 has the CPU_COUNT macro.  */
+        count = CPU_COUNT (&set);
 # else
-            size_t i;
+        size_t i;
 
-            count = 0;
-            for (i = 0; i < CPU_SETSIZE; i++)
-              if (CPU_ISSET (i, &set))
-                count++;
+        count = 0;
+        for (i = 0; i < CPU_SETSIZE; i++)
+          if (CPU_ISSET (i, &set))
+            count++;
 # endif
-            if (count > 0)
-              return count;
-          }
+        if (count > 0)
+          return count;
       }
+  }
 #elif HAVE_PTHREAD_AFFINITY_NP && defined __NetBSD__ && 0
+  {
+    cpuset_t *set;
+
+    set = cpuset_create ();
+    if (set != NULL)
       {
-        cpuset_t *set;
+        unsigned long count = 0;
 
-        set = cpuset_create ();
-        if (set != NULL)
+        if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set)
+            == 0)
           {
-            unsigned long count = 0;
+            cpuid_t i;
 
-            if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set)
-                == 0)
+            for (i = 0;; i++)
               {
-                cpuid_t i;
-
-                for (i = 0;; i++)
-                  {
-                    int ret = cpuset_isset (i, set);
-                    if (ret < 0)
-                      break;
-                    if (ret > 0)
-                      count++;
-                  }
+                int ret = cpuset_isset (i, set);
+                if (ret < 0)
+                  break;
+                if (ret > 0)
+                  count++;
               }
-            cpuset_destroy (set);
-            if (count > 0)
-              return count;
           }
+        cpuset_destroy (set);
+        if (count > 0)
+          return count;
       }
+  }
 #elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
-      {
-        cpu_set_t set;
+  {
+    cpu_set_t set;
 
-        if (sched_getaffinity (0, sizeof (set), &set) == 0)
-          {
-            unsigned long count;
+    if (sched_getaffinity (0, sizeof (set), &set) == 0)
+      {
+        unsigned long count;
 
 # ifdef CPU_COUNT
-            /* glibc >= 2.6 has the CPU_COUNT macro.  */
-            count = CPU_COUNT (&set);
+        /* glibc >= 2.6 has the CPU_COUNT macro.  */
+        count = CPU_COUNT (&set);
 # else
-            size_t i;
+        size_t i;
 
-            count = 0;
-            for (i = 0; i < CPU_SETSIZE; i++)
-              if (CPU_ISSET (i, &set))
-                count++;
+        count = 0;
+        for (i = 0; i < CPU_SETSIZE; i++)
+          if (CPU_ISSET (i, &set))
+            count++;
 # endif
-            if (count > 0)
-              return count;
-          }
+        if (count > 0)
+          return count;
       }
+  }
 #elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */
+  {
+    cpuset_t *set;
+
+    set = cpuset_create ();
+    if (set != NULL)
       {
-        cpuset_t *set;
+        unsigned long count = 0;
 
-        set = cpuset_create ();
-        if (set != NULL)
+        if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0)
           {
-            unsigned long count = 0;
+            cpuid_t i;
 
-            if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0)
+            for (i = 0;; i++)
               {
-                cpuid_t i;
-
-                for (i = 0;; i++)
-                  {
-                    int ret = cpuset_isset (i, set);
-                    if (ret < 0)
-                      break;
-                    if (ret > 0)
-                      count++;
-                  }
+                int ret = cpuset_isset (i, set);
+                if (ret < 0)
+                  break;
+                if (ret > 0)
+                  count++;
               }
-            cpuset_destroy (set);
-            if (count > 0)
-              return count;
           }
+        cpuset_destroy (set);
+        if (count > 0)
+          return count;
       }
+  }
 #endif
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
-      { /* This works on native Windows platforms.  */
-        DWORD_PTR process_mask;
-        DWORD_PTR system_mask;
+  { /* This works on native Windows platforms.  */
+    DWORD_PTR process_mask;
+    DWORD_PTR system_mask;
 
-        if (GetProcessAffinityMask (GetCurrentProcess (),
-                                    &process_mask, &system_mask))
-          {
-            DWORD_PTR mask = process_mask;
-            unsigned long count = 0;
-
-            for (; mask != 0; mask = mask >> 1)
-              if (mask & 1)
-                count++;
-            if (count > 0)
-              return count;
-          }
+    if (GetProcessAffinityMask (GetCurrentProcess (),
+                                &process_mask, &system_mask))
+      {
+        DWORD_PTR mask = process_mask;
+        unsigned long count = 0;
+
+        for (; mask != 0; mask = mask >> 1)
+          if (mask & 1)
+            count++;
+        if (count > 0)
+          return count;
       }
+  }
 #endif
 
+  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.  */
+
+  /* On systems with a modern affinity mask system call, we have
+         sysconf (_SC_NPROCESSORS_CONF)
+            >= sysconf (_SC_NPROCESSORS_ONLN)
+               >= num_processors_via_affinity_mask ()
+     The first number is the number of CPUs configured in the system.
+     The second number is the number of CPUs available to the scheduler.
+     The third number is the number of CPUs available to the current process.
+   */
+
+  if (query == NPROC_CURRENT)
+    {
+      /* Try the modern affinity mask system call.  */
+      {
+        unsigned long nprocs = num_processors_via_affinity_mask ();
+
+        if (nprocs > 0)
+          return nprocs;
+      }
+
 #if defined _SC_NPROCESSORS_ONLN
       { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
            Cygwin, Haiku.  */