1/* -*- buffer-read-only: t -*- vi: set ro: */ 2/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ 3#line 1 4/* Detect the number of processors. 5 6 Copyright (C) 2009-2010 Free Software Foundation, Inc. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software Foundation, 20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 21 22/* Written by Glen Lenker and Bruno Haible. */ 23 24#include <config.h> 25#include "nproc.h" 26 27#include <stdlib.h> 28#include <unistd.h> 29 30#if HAVE_PTHREAD_AFFINITY_NP && 0 31# include <pthread.h> 32# include <sched.h> 33#endif 34#if HAVE_SCHED_GETAFFINITY_LIKE_GLIBC || HAVE_SCHED_GETAFFINITY_NP 35# include <sched.h> 36#endif 37 38#include <sys/types.h> 39 40#if HAVE_SYS_PSTAT_H 41# include <sys/pstat.h> 42#endif 43 44#if HAVE_SYS_SYSMP_H 45# include <sys/sysmp.h> 46#endif 47 48#if HAVE_SYS_PARAM_H 49# include <sys/param.h> 50#endif 51 52#if HAVE_SYS_SYSCTL_H 53# include <sys/sysctl.h> 54#endif 55 56#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 57# define WIN32_LEAN_AND_MEAN 58# include <windows.h> 59#endif 60 61#include "c-ctype.h" 62 63#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) 64 65/* Return the number of processors available to the current process, based 66 on a modern system call that returns the "affinity" between the current 67 process and each CPU. Return 0 if unknown or if such a system call does 68 not exist. */ 69static unsigned long 70num_processors_via_affinity_mask (void) 71{ 72 /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np, 73 but with different APIs. Also it requires linking with -lpthread. 74 Therefore this code is not enabled. 75 glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has 76 sched_getaffinity_np. */ 77#if HAVE_PTHREAD_AFFINITY_NP && defined __GLIBC__ && 0 78 { 79 cpu_set_t set; 80 81 if (pthread_getaffinity_np (pthread_self (), sizeof (set), &set) == 0) 82 { 83 unsigned long count; 84 85# ifdef CPU_COUNT 86 /* glibc >= 2.6 has the CPU_COUNT macro. */ 87 count = CPU_COUNT (&set); 88# else 89 size_t i; 90 91 count = 0; 92 for (i = 0; i < CPU_SETSIZE; i++) 93 if (CPU_ISSET (i, &set)) 94 count++; 95# endif 96 if (count > 0) 97 return count; 98 } 99 } 100#elif HAVE_PTHREAD_AFFINITY_NP && defined __NetBSD__ && 0 101 { 102 cpuset_t *set; 103 104 set = cpuset_create (); 105 if (set != NULL) 106 { 107 unsigned long count = 0; 108 109 if (pthread_getaffinity_np (pthread_self (), cpuset_size (set), set) 110 == 0) 111 { 112 cpuid_t i; 113 114 for (i = 0;; i++) 115 { 116 int ret = cpuset_isset (i, set); 117 if (ret < 0) 118 break; 119 if (ret > 0) 120 count++; 121 } 122 } 123 cpuset_destroy (set); 124 if (count > 0) 125 return count; 126 } 127 } 128#elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */ 129 { 130 cpu_set_t set; 131 132 if (sched_getaffinity (0, sizeof (set), &set) == 0) 133 { 134 unsigned long count; 135 136# ifdef CPU_COUNT 137 /* glibc >= 2.6 has the CPU_COUNT macro. */ 138 count = CPU_COUNT (&set); 139# else 140 size_t i; 141 142 count = 0; 143 for (i = 0; i < CPU_SETSIZE; i++) 144 if (CPU_ISSET (i, &set)) 145 count++; 146# endif 147 if (count > 0) 148 return count; 149 } 150 } 151#elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */ 152 { 153 cpuset_t *set; 154 155 set = cpuset_create (); 156 if (set != NULL) 157 { 158 unsigned long count = 0; 159 160 if (sched_getaffinity_np (getpid (), cpuset_size (set), set) == 0) 161 { 162 cpuid_t i; 163 164 for (i = 0;; i++) 165 { 166 int ret = cpuset_isset (i, set); 167 if (ret < 0) 168 break; 169 if (ret > 0) 170 count++; 171 } 172 } 173 cpuset_destroy (set); 174 if (count > 0) 175 return count; 176 } 177 } 178#endif 179 180#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 181 { /* This works on native Windows platforms. */ 182 DWORD_PTR process_mask; 183 DWORD_PTR system_mask; 184 185 if (GetProcessAffinityMask (GetCurrentProcess (), 186 &process_mask, &system_mask)) 187 { 188 DWORD_PTR mask = process_mask; 189 unsigned long count = 0; 190 191 for (; mask != 0; mask = mask >> 1) 192 if (mask & 1) 193 count++; 194 if (count > 0) 195 return count; 196 } 197 } 198#endif 199 200 return 0; 201} 202 203unsigned long int 204num_processors (enum nproc_query query) 205{ 206 if (query == NPROC_CURRENT_OVERRIDABLE) 207 { 208 /* Test the environment variable OMP_NUM_THREADS, recognized also by all 209 programs that are based on OpenMP. The OpenMP spec says that the 210 value assigned to the environment variable "may have leading and 211 trailing white space". */ 212 const char *envvalue = getenv ("OMP_NUM_THREADS"); 213 214 if (envvalue != NULL) 215 { 216 while (*envvalue != '\0' && c_isspace (*envvalue)) 217 envvalue++; 218 /* Convert it from decimal to 'unsigned long'. */ 219 if (c_isdigit (*envvalue)) 220 { 221 char *endptr = NULL; 222 unsigned long int value = strtoul (envvalue, &endptr, 10); 223 224 if (endptr != NULL) 225 { 226 while (*endptr != '\0' && c_isspace (*endptr)) 227 endptr++; 228 if (*endptr == '\0') 229 return (value > 0 ? value : 1); 230 } 231 } 232 } 233 234 query = NPROC_CURRENT; 235 } 236 /* Here query is one of NPROC_ALL, NPROC_CURRENT. */ 237 238 /* On systems with a modern affinity mask system call, we have 239 sysconf (_SC_NPROCESSORS_CONF) 240 >= sysconf (_SC_NPROCESSORS_ONLN) 241 >= num_processors_via_affinity_mask () 242 The first number is the number of CPUs configured in the system. 243 The second number is the number of CPUs available to the scheduler. 244 The third number is the number of CPUs available to the current process. 245 246 Note! On Linux systems with glibc, the first and second number come from 247 the /sys and /proc file systems (see 248 glibc/sysdeps/unix/sysv/linux/getsysstats.c). 249 In some situations these file systems are not mounted, and the sysconf 250 call returns 1, which does not reflect the reality. */ 251 252 if (query == NPROC_CURRENT) 253 { 254 /* Try the modern affinity mask system call. */ 255 { 256 unsigned long nprocs = num_processors_via_affinity_mask (); 257 258 if (nprocs > 0) 259 return nprocs; 260 } 261 262#if defined _SC_NPROCESSORS_ONLN 263 { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris, 264 Cygwin, Haiku. */ 265 long int nprocs = sysconf (_SC_NPROCESSORS_ONLN); 266 if (nprocs > 0) 267 return nprocs; 268 } 269#endif 270 } 271 else /* query == NPROC_ALL */ 272 { 273#if defined _SC_NPROCESSORS_CONF 274 { /* This works on glibc, MacOS X 10.5, FreeBSD, AIX, OSF/1, Solaris, 275 Cygwin, Haiku. */ 276 long int nprocs = sysconf (_SC_NPROCESSORS_CONF); 277 278# if __GLIBC__ >= 2 && defined __linux__ 279 /* On Linux systems with glibc, this information comes from the /sys and 280 /proc file systems (see glibc/sysdeps/unix/sysv/linux/getsysstats.c). 281 In some situations these file systems are not mounted, and the 282 sysconf call returns 1. But we wish to guarantee that 283 num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT). */ 284 if (nprocs == 1) 285 { 286 unsigned long nprocs_current = num_processors_via_affinity_mask (); 287 288 if (nprocs_current > 0) 289 nprocs = nprocs_current; 290 } 291# endif 292 293 if (nprocs > 0) 294 return nprocs; 295 } 296#endif 297 } 298 299#if HAVE_PSTAT_GETDYNAMIC 300 { /* This works on HP-UX. */ 301 struct pst_dynamic psd; 302 if (pstat_getdynamic (&psd, sizeof psd, 1, 0) >= 0) 303 { 304 /* The field psd_proc_cnt contains the number of active processors. 305 In newer releases of HP-UX 11, the field psd_max_proc_cnt includes 306 deactivated processors. */ 307 if (query == NPROC_CURRENT) 308 { 309 if (psd.psd_proc_cnt > 0) 310 return psd.psd_proc_cnt; 311 } 312 else 313 { 314 if (psd.psd_max_proc_cnt > 0) 315 return psd.psd_max_proc_cnt; 316 } 317 } 318 } 319#endif 320 321#if HAVE_SYSMP && defined MP_NAPROCS && defined MP_NPROCS 322 { /* This works on IRIX. */ 323 /* MP_NPROCS yields the number of installed processors. 324 MP_NAPROCS yields the number of processors available to unprivileged 325 processes. */ 326 int nprocs = 327 sysmp (query == NPROC_CURRENT && getpid () != 0 328 ? MP_NAPROCS 329 : MP_NPROCS); 330 if (nprocs > 0) 331 return nprocs; 332 } 333#endif 334 335 /* Finally, as fallback, use the APIs that don't distinguish between 336 NPROC_CURRENT and NPROC_ALL. */ 337 338#if HAVE_SYSCTL && defined HW_NCPU 339 { /* This works on MacOS X, FreeBSD, NetBSD, OpenBSD. */ 340 int nprocs; 341 size_t len = sizeof (nprocs); 342 static int mib[2] = { CTL_HW, HW_NCPU }; 343 344 if (sysctl (mib, ARRAY_SIZE (mib), &nprocs, &len, NULL, 0) == 0 345 && len == sizeof (nprocs) 346 && 0 < nprocs) 347 return nprocs; 348 } 349#endif 350 351#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 352 { /* This works on native Windows platforms. */ 353 SYSTEM_INFO system_info; 354 GetSystemInfo (&system_info); 355 if (0 < system_info.dwNumberOfProcessors) 356 return system_info.dwNumberOfProcessors; 357 } 358#endif 359 360 return 1; 361} 362