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