/* Detect the number of processors.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 2009-2013 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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
/* Written by Glen Lenker and Bruno Haible. */
#include <stdlib.h>
#include <unistd.h>
-#if HAVE_PTHREAD_AFFINITY_NP && 0
+#if HAVE_PTHREAD_GETAFFINITY_NP && 0
# include <pthread.h>
# include <sched.h>
#endif
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+/* 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)
+{
+ /* 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_GETAFFINITY_NP && defined __GLIBC__ && 0
+ {
+ cpu_set_t set;
+
+ 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);
+# else
+ size_t i;
+
+ count = 0;
+ for (i = 0; i < CPU_SETSIZE; i++)
+ if (CPU_ISSET (i, &set))
+ count++;
+# endif
+ if (count > 0)
+ return count;
+ }
+ }
+#elif HAVE_PTHREAD_GETAFFINITY_NP && defined __NetBSD__ && 0
+ {
+ cpuset_t *set;
+
+ set = cpuset_create ();
+ if (set != NULL)
+ {
+ unsigned long count = 0;
+
+ if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set)
+ == 0)
+ {
+ cpuid_t i;
+
+ for (i = 0;; i++)
+ {
+ int ret = cpuset_isset (i, set);
+ if (ret < 0)
+ break;
+ if (ret > 0)
+ count++;
+ }
+ }
+ cpuset_destroy (set);
+ if (count > 0)
+ return count;
+ }
+ }
+#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
+ {
+ cpu_set_t set;
+
+ 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);
+# else
+ size_t i;
+
+ count = 0;
+ for (i = 0; i < CPU_SETSIZE; i++)
+ if (CPU_ISSET (i, &set))
+ count++;
+# endif
+ if (count > 0)
+ return count;
+ }
+ }
+#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */
+ {
+ cpuset_t *set;
+
+ set = cpuset_create ();
+ if (set != NULL)
+ {
+ unsigned long count = 0;
+
+ if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0)
+ {
+ cpuid_t i;
+
+ for (i = 0;; i++)
+ {
+ int ret = cpuset_isset (i, set);
+ if (ret < 0)
+ break;
+ if (ret > 0)
+ 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;
+
+ 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)
{
}
/* 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. */
-#if HAVE_PTHREAD_AFFINITY_NP && defined __GLIBC__ && 0
- {
- cpu_set_t set;
-
- 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);
-# else
- size_t i;
-
- count = 0;
- for (i = 0; i < CPU_SETSIZE; i++)
- if (CPU_ISSET (i, &set))
- count++;
-# endif
- if (count > 0)
- return count;
- }
- }
-#elif HAVE_PTHREAD_AFFINITY_NP && defined __NetBSD__ && 0
- {
- cpuset_t *set;
-
- set = cpuset_create ();
- if (set != NULL)
- {
- unsigned long count = 0;
+ /* 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 (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set)
- == 0)
- {
- cpuid_t i;
-
- for (i = 0;; i++)
- {
- int ret = cpuset_isset (i, set);
- if (ret < 0)
- break;
- if (ret > 0)
- count++;
- }
- }
- cpuset_destroy (set);
- if (count > 0)
- return count;
- }
- }
-#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
- {
- cpu_set_t set;
+ 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. */
- 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);
-# else
- size_t i;
-
- count = 0;
- for (i = 0; i < CPU_SETSIZE; i++)
- if (CPU_ISSET (i, &set))
- count++;
-# endif
- if (count > 0)
- return count;
- }
- }
-#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */
+ if (query == NPROC_CURRENT)
+ {
+ /* Try the modern affinity mask system call. */
{
- cpuset_t *set;
-
- set = cpuset_create ();
- if (set != NULL)
- {
- unsigned long count = 0;
-
- if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0)
- {
- cpuid_t i;
-
- for (i = 0;; i++)
- {
- int ret = cpuset_isset (i, set);
- if (ret < 0)
- break;
- if (ret > 0)
- count++;
- }
- }
- cpuset_destroy (set);
- if (count > 0)
- return count;
- }
- }
-#endif
+ unsigned long nprocs = num_processors_via_affinity_mask ();
-#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
- { /* 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 (nprocs > 0)
+ return nprocs;
}
-#endif
#if defined _SC_NPROCESSORS_ONLN
- { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
+ { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
Cygwin, Haiku. */
long int nprocs = sysconf (_SC_NPROCESSORS_ONLN);
if (nprocs > 0)
else /* query == NPROC_ALL */
{
#if defined _SC_NPROCESSORS_CONF
- { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
+ { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
Cygwin, Haiku. */
long int nprocs = sysconf (_SC_NPROCESSORS_CONF);
+
+# if __GLIBC__ >= 2 && defined __linux__
+ /* 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
+ num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT). */
+ if (nprocs == 1)
+ {
+ unsigned long nprocs_current = num_processors_via_affinity_mask ();
+
+ if (nprocs_current > 0)
+ nprocs = nprocs_current;
+ }
+# endif
+
if (nprocs > 0)
return nprocs;
}
NPROC_CURRENT and NPROC_ALL. */
#if HAVE_SYSCTL && defined HW_NCPU
- { /* This works on MacOS X, FreeBSD, NetBSD, OpenBSD. */
+ { /* This works on Mac OS X, FreeBSD, NetBSD, OpenBSD. */
int nprocs;
size_t len = sizeof (nprocs);
static int mib[2] = { CTL_HW, HW_NCPU };