Reverting merge from trunk
[official-gcc.git] / libgomp / config / linux / proc.c
blob76616dd37a08634914c72e3db05e477b8face171
1 /* Copyright (C) 2005-2013 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
11 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This file contains system specific routines related to counting
26 online processors and dynamic load balancing. */
28 #ifndef _GNU_SOURCE
29 #define _GNU_SOURCE 1
30 #endif
31 #include "libgomp.h"
32 #include "proc.h"
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #ifdef HAVE_GETLOADAVG
37 # ifdef HAVE_SYS_LOADAVG_H
38 # include <sys/loadavg.h>
39 # endif
40 #endif
42 #ifdef HAVE_PTHREAD_AFFINITY_NP
43 unsigned long gomp_cpuset_size;
44 static unsigned long gomp_get_cpuset_size;
45 cpu_set_t *gomp_cpusetp;
47 unsigned long
48 gomp_cpuset_popcount (unsigned long cpusetsize, cpu_set_t *cpusetp)
50 #ifdef CPU_COUNT_S
51 /* glibc 2.7 and above provide a macro for this. */
52 return CPU_COUNT_S (cpusetsize, cpusetp);
53 #else
54 #ifdef CPU_COUNT
55 if (cpusetsize == sizeof (cpu_set_t))
56 /* glibc 2.6 and above provide a macro for this. */
57 return CPU_COUNT (cpusetp);
58 #endif
59 size_t i;
60 unsigned long ret = 0;
61 extern int check[sizeof (cpusetp->__bits[0]) == sizeof (unsigned long int)
62 ? 1 : -1] __attribute__((unused));
64 for (i = 0; i < cpusetsize / sizeof (cpusetp->__bits[0]); i++)
66 unsigned long int mask = cpusetp->__bits[i];
67 if (mask == 0)
68 continue;
69 ret += __builtin_popcountl (mask);
71 return ret;
72 #endif
74 #endif
76 /* At startup, determine the default number of threads. It would seem
77 this should be related to the number of cpus online. */
79 void
80 gomp_init_num_threads (void)
82 #ifdef HAVE_PTHREAD_AFFINITY_NP
83 #if defined (_SC_NPROCESSORS_CONF) && defined (CPU_ALLOC_SIZE)
84 gomp_cpuset_size = sysconf (_SC_NPROCESSORS_CONF);
85 gomp_cpuset_size = CPU_ALLOC_SIZE (gomp_cpuset_size);
86 #else
87 gomp_cpuset_size = sizeof (cpu_set_t);
88 #endif
90 gomp_cpusetp = (cpu_set_t *) gomp_malloc (gomp_cpuset_size);
93 int ret = pthread_getaffinity_np (pthread_self (), gomp_cpuset_size,
94 gomp_cpusetp);
95 if (ret == 0)
97 /* Count only the CPUs this process can use. */
98 gomp_global_icv.nthreads_var
99 = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
100 if (gomp_global_icv.nthreads_var == 0)
101 break;
102 gomp_get_cpuset_size = gomp_cpuset_size;
103 #ifdef CPU_ALLOC_SIZE
104 unsigned long i;
105 for (i = gomp_cpuset_size * 8; i; i--)
106 if (CPU_ISSET_S (i - 1, gomp_cpuset_size, gomp_cpusetp))
107 break;
108 gomp_cpuset_size = CPU_ALLOC_SIZE (i);
109 #endif
110 return;
112 if (ret != EINVAL)
113 break;
114 #ifdef CPU_ALLOC_SIZE
115 if (gomp_cpuset_size < sizeof (cpu_set_t))
116 gomp_cpuset_size = sizeof (cpu_set_t);
117 else
118 gomp_cpuset_size = gomp_cpuset_size * 2;
119 if (gomp_cpuset_size < 8 * sizeof (cpu_set_t))
120 gomp_cpusetp
121 = (cpu_set_t *) gomp_realloc (gomp_cpusetp, gomp_cpuset_size);
122 else
124 /* Avoid gomp_fatal if too large memory allocation would be
125 requested, e.g. kernel returning EINVAL all the time. */
126 void *p = realloc (gomp_cpusetp, gomp_cpuset_size);
127 if (p == NULL)
128 break;
129 gomp_cpusetp = (cpu_set_t *) p;
131 #else
132 break;
133 #endif
135 while (1);
136 gomp_cpuset_size = 0;
137 gomp_global_icv.nthreads_var = 1;
138 free (gomp_cpusetp);
139 gomp_cpusetp = NULL;
140 #endif
141 #ifdef _SC_NPROCESSORS_ONLN
142 gomp_global_icv.nthreads_var = sysconf (_SC_NPROCESSORS_ONLN);
143 #endif
146 static int
147 get_num_procs (void)
149 #ifdef HAVE_PTHREAD_AFFINITY_NP
150 if (gomp_places_list == NULL)
152 /* Count only the CPUs this process can use. */
153 if (gomp_cpusetp
154 && pthread_getaffinity_np (pthread_self (), gomp_get_cpuset_size,
155 gomp_cpusetp) == 0)
157 int ret = gomp_cpuset_popcount (gomp_get_cpuset_size, gomp_cpusetp);
158 return ret != 0 ? ret : 1;
161 else
163 /* We can't use pthread_getaffinity_np in this case
164 (we have changed it ourselves, it binds to just one CPU).
165 Count instead the number of different CPUs we are
166 using. gomp_init_affinity updated gomp_available_cpus to
167 the number of CPUs in the GOMP_AFFINITY mask that we are
168 allowed to use though. */
169 return gomp_available_cpus;
171 #endif
172 #ifdef _SC_NPROCESSORS_ONLN
173 return sysconf (_SC_NPROCESSORS_ONLN);
174 #else
175 return gomp_icv (false)->nthreads_var;
176 #endif
179 /* When OMP_DYNAMIC is set, at thread launch determine the number of
180 threads we should spawn for this team. */
181 /* ??? I have no idea what best practice for this is. Surely some
182 function of the number of processors that are *still* online and
183 the load average. Here I use the number of processors online
184 minus the 15 minute load average. */
186 unsigned
187 gomp_dynamic_max_threads (void)
189 unsigned n_onln, loadavg, nthreads_var = gomp_icv (false)->nthreads_var;
191 n_onln = get_num_procs ();
192 if (n_onln > nthreads_var)
193 n_onln = nthreads_var;
195 loadavg = 0;
196 #ifdef HAVE_GETLOADAVG
198 double dloadavg[3];
199 if (getloadavg (dloadavg, 3) == 3)
201 /* Add 0.1 to get a kind of biased rounding. */
202 loadavg = dloadavg[2] + 0.1;
205 #endif
207 if (loadavg >= n_onln)
208 return 1;
209 else
210 return n_onln - loadavg;
214 omp_get_num_procs (void)
216 return get_num_procs ();
219 ialias (omp_get_num_procs)