1 /* Detect the number of processors.
3 Copyright (C) 2009-2019 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Glen Lenker and Bruno Haible. */
27 #if HAVE_PTHREAD_GETAFFINITY_NP && 0
31 #if HAVE_SCHED_GETAFFINITY_LIKE_GLIBC || HAVE_SCHED_GETAFFINITY_NP
35 #include <sys/types.h>
38 # include <sys/pstat.h>
42 # include <sys/sysmp.h>
46 # include <sys/param.h>
50 # include <sys/sysctl.h>
53 #if defined _WIN32 && ! defined __CYGWIN__
54 # define WIN32_LEAN_AND_MEAN
62 #define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
64 /* Return the number of processors available to the current process, based
65 on a modern system call that returns the "affinity" between the current
66 process and each CPU. Return 0 if unknown or if such a system call does
69 num_processors_via_affinity_mask (void)
71 /* glibc >= 2.3.3 with NPTL and NetBSD 5 have pthread_getaffinity_np,
72 but with different APIs. Also it requires linking with -lpthread.
73 Therefore this code is not enabled.
74 glibc >= 2.3.4 has sched_getaffinity whereas NetBSD 5 has
75 sched_getaffinity_np. */
76 #if HAVE_PTHREAD_GETAFFINITY_NP && defined __GLIBC__ && 0
80 if (pthread_getaffinity_np (pthread_self (), sizeof (set
), &set
) == 0)
85 /* glibc >= 2.6 has the CPU_COUNT macro. */
86 count
= CPU_COUNT (&set
);
91 for (i
= 0; i
< CPU_SETSIZE
; i
++)
92 if (CPU_ISSET (i
, &set
))
99 #elif HAVE_PTHREAD_GETAFFINITY_NP && defined __NetBSD__ && 0
103 set
= cpuset_create ();
106 unsigned long count
= 0;
108 if (pthread_getaffinity_np (pthread_self (), cpuset_size (set
), set
)
115 int ret
= cpuset_isset (i
, set
);
122 cpuset_destroy (set
);
127 #elif HAVE_SCHED_GETAFFINITY_LIKE_GLIBC /* glibc >= 2.3.4 */
131 if (sched_getaffinity (0, sizeof (set
), &set
) == 0)
136 /* glibc >= 2.6 has the CPU_COUNT macro. */
137 count
= CPU_COUNT (&set
);
142 for (i
= 0; i
< CPU_SETSIZE
; i
++)
143 if (CPU_ISSET (i
, &set
))
150 #elif HAVE_SCHED_GETAFFINITY_NP /* NetBSD >= 5 */
154 set
= cpuset_create ();
157 unsigned long count
= 0;
159 if (sched_getaffinity_np (getpid (), cpuset_size (set
), set
) == 0)
165 int ret
= cpuset_isset (i
, set
);
172 cpuset_destroy (set
);
179 #if defined _WIN32 && ! defined __CYGWIN__
180 { /* This works on native Windows platforms. */
181 DWORD_PTR process_mask
;
182 DWORD_PTR system_mask
;
184 if (GetProcessAffinityMask (GetCurrentProcess (),
185 &process_mask
, &system_mask
))
187 DWORD_PTR mask
= process_mask
;
188 unsigned long count
= 0;
190 for (; mask
!= 0; mask
= mask
>> 1)
203 /* Return the total number of processors. Here QUERY must be one of
204 NPROC_ALL, NPROC_CURRENT. The result is guaranteed to be at least 1. */
205 static unsigned long int
206 num_processors_ignoring_omp (enum nproc_query query
)
208 /* On systems with a modern affinity mask system call, we have
209 sysconf (_SC_NPROCESSORS_CONF)
210 >= sysconf (_SC_NPROCESSORS_ONLN)
211 >= num_processors_via_affinity_mask ()
212 The first number is the number of CPUs configured in the system.
213 The second number is the number of CPUs available to the scheduler.
214 The third number is the number of CPUs available to the current process.
216 Note! On Linux systems with glibc, the first and second number come from
217 the /sys and /proc file systems (see
218 glibc/sysdeps/unix/sysv/linux/getsysstats.c).
219 In some situations these file systems are not mounted, and the sysconf
220 call returns 1, which does not reflect the reality. */
222 if (query
== NPROC_CURRENT
)
224 /* Try the modern affinity mask system call. */
226 unsigned long nprocs
= num_processors_via_affinity_mask ();
232 #if defined _SC_NPROCESSORS_ONLN
233 { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
235 long int nprocs
= sysconf (_SC_NPROCESSORS_ONLN
);
241 else /* query == NPROC_ALL */
243 #if defined _SC_NPROCESSORS_CONF
244 { /* This works on glibc, Mac OS X 10.5, FreeBSD, AIX, OSF/1, Solaris,
246 long int nprocs
= sysconf (_SC_NPROCESSORS_CONF
);
248 # if __GLIBC__ >= 2 && defined __linux__
249 /* On Linux systems with glibc, this information comes from the /sys and
250 /proc file systems (see glibc/sysdeps/unix/sysv/linux/getsysstats.c).
251 In some situations these file systems are not mounted, and the
252 sysconf call returns 1. But we wish to guarantee that
253 num_processors (NPROC_ALL) >= num_processors (NPROC_CURRENT). */
256 unsigned long nprocs_current
= num_processors_via_affinity_mask ();
258 if (nprocs_current
> 0)
259 nprocs
= nprocs_current
;
269 #if HAVE_PSTAT_GETDYNAMIC
270 { /* This works on HP-UX. */
271 struct pst_dynamic psd
;
272 if (pstat_getdynamic (&psd
, sizeof psd
, 1, 0) >= 0)
274 /* The field psd_proc_cnt contains the number of active processors.
275 In newer releases of HP-UX 11, the field psd_max_proc_cnt includes
276 deactivated processors. */
277 if (query
== NPROC_CURRENT
)
279 if (psd
.psd_proc_cnt
> 0)
280 return psd
.psd_proc_cnt
;
284 if (psd
.psd_max_proc_cnt
> 0)
285 return psd
.psd_max_proc_cnt
;
291 #if HAVE_SYSMP && defined MP_NAPROCS && defined MP_NPROCS
292 { /* This works on IRIX. */
293 /* MP_NPROCS yields the number of installed processors.
294 MP_NAPROCS yields the number of processors available to unprivileged
297 sysmp (query
== NPROC_CURRENT
&& getpid () != 0
305 /* Finally, as fallback, use the APIs that don't distinguish between
306 NPROC_CURRENT and NPROC_ALL. */
308 #if HAVE_SYSCTL && defined HW_NCPU
309 { /* This works on Mac OS X, FreeBSD, NetBSD, OpenBSD. */
311 size_t len
= sizeof (nprocs
);
312 static int mib
[2] = { CTL_HW
, HW_NCPU
};
314 if (sysctl (mib
, ARRAY_SIZE (mib
), &nprocs
, &len
, NULL
, 0) == 0
315 && len
== sizeof (nprocs
)
321 #if defined _WIN32 && ! defined __CYGWIN__
322 { /* This works on native Windows platforms. */
323 SYSTEM_INFO system_info
;
324 GetSystemInfo (&system_info
);
325 if (0 < system_info
.dwNumberOfProcessors
)
326 return system_info
.dwNumberOfProcessors
;
333 /* Parse OMP environment variables without dependence on OMP.
334 Return 0 for invalid values. */
335 static unsigned long int
336 parse_omp_threads (char const* threads
)
338 unsigned long int ret
= 0;
343 /* The OpenMP spec says that the value assigned to the environment variables
344 "may have leading and trailing white space". */
345 while (*threads
!= '\0' && c_isspace (*threads
))
348 /* Convert it from positive decimal to 'unsigned long'. */
349 if (c_isdigit (*threads
))
352 unsigned long int value
= strtoul (threads
, &endptr
, 10);
356 while (*endptr
!= '\0' && c_isspace (*endptr
))
360 /* Also accept the first value in a nesting level,
361 since we can't determine the nesting level from env vars. */
362 else if (*endptr
== ',')
371 num_processors (enum nproc_query query
)
373 unsigned long int omp_env_limit
= ULONG_MAX
;
375 if (query
== NPROC_CURRENT_OVERRIDABLE
)
377 unsigned long int omp_env_threads
;
378 /* Honor the OpenMP environment variables, recognized also by all
379 programs that are based on OpenMP. */
380 omp_env_threads
= parse_omp_threads (getenv ("OMP_NUM_THREADS"));
381 omp_env_limit
= parse_omp_threads (getenv ("OMP_THREAD_LIMIT"));
383 omp_env_limit
= ULONG_MAX
;
386 return MIN (omp_env_threads
, omp_env_limit
);
388 query
= NPROC_CURRENT
;
390 /* Here query is one of NPROC_ALL, NPROC_CURRENT. */
392 unsigned long nprocs
= num_processors_ignoring_omp (query
);
393 return MIN (nprocs
, omp_env_limit
);