From 45ab174d5bb73911a43cc3c55bff6405f31b724b Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 11 Jan 2010 02:14:00 +0100 Subject: [PATCH] nproc: Refactor. --- ChangeLog | 7 ++ lib/nproc.c | 275 +++++++++++++++++++++++++++++----------------------- 2 files changed, 158 insertions(+), 124 deletions(-) diff --git a/ChangeLog b/ChangeLog index d075b31c55..f07170a623 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2010-01-10 Bruno Haible + + 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 utimecmp: avoid new warning from upcoming gcc-4.5.0 diff --git a/lib/nproc.c b/lib/nproc.c index af4da75d18..b72d721577 100644 --- a/lib/nproc.c +++ b/lib/nproc.c @@ -1,6 +1,6 @@ /* Detect the number of processors. - Copyright (C) 2009, 2010 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 @@ -59,171 +59,198 @@ #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. */ -- 2.30.2