2014-09-11 Segher Boessenkool <segher@kernel.crashing.org>
[official-gcc.git] / libgomp / config / linux / affinity.c
blob2f8a300295471b50031333d43f86826ddc554618
1 /* Copyright (C) 2006-2014 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 is a Linux specific implementation of a CPU affinity setting. */
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE 1
29 #endif
30 #include "libgomp.h"
31 #include "proc.h"
32 #include <errno.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
38 #ifdef HAVE_PTHREAD_AFFINITY_NP
40 #ifndef CPU_ALLOC_SIZE
41 #define CPU_ISSET_S(idx, size, set) CPU_ISSET(idx, set)
42 #define CPU_ZERO_S(size, set) CPU_ZERO(set)
43 #define CPU_SET_S(idx, size, set) CPU_SET(idx, set)
44 #define CPU_CLR_S(idx, size, set) CPU_CLR(idx, set)
45 #endif
47 void
48 gomp_init_affinity (void)
50 if (gomp_places_list == NULL)
52 if (!gomp_affinity_init_level (1, ULONG_MAX, true))
53 return;
56 struct gomp_thread *thr = gomp_thread ();
57 pthread_setaffinity_np (pthread_self (), gomp_cpuset_size,
58 (cpu_set_t *) gomp_places_list[0]);
59 thr->place = 1;
60 thr->ts.place_partition_off = 0;
61 thr->ts.place_partition_len = gomp_places_list_len;
64 void
65 gomp_init_thread_affinity (pthread_attr_t *attr, unsigned int place)
67 pthread_attr_setaffinity_np (attr, gomp_cpuset_size,
68 (cpu_set_t *) gomp_places_list[place]);
71 void **
72 gomp_affinity_alloc (unsigned long count, bool quiet)
74 unsigned long i;
75 void **ret;
76 char *p;
78 if (gomp_cpusetp == NULL)
80 if (!quiet)
81 gomp_error ("Could not get CPU affinity set");
82 return NULL;
85 ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
86 if (ret == NULL)
88 if (!quiet)
89 gomp_error ("Out of memory trying to allocate places list");
90 return NULL;
93 p = (char *) (ret + count);
94 for (i = 0; i < count; i++, p += gomp_cpuset_size)
95 ret[i] = p;
96 return ret;
99 void
100 gomp_affinity_init_place (void *p)
102 cpu_set_t *cpusetp = (cpu_set_t *) p;
103 CPU_ZERO_S (gomp_cpuset_size, cpusetp);
106 bool
107 gomp_affinity_add_cpus (void *p, unsigned long num,
108 unsigned long len, long stride, bool quiet)
110 cpu_set_t *cpusetp = (cpu_set_t *) p;
111 unsigned long max = 8 * gomp_cpuset_size;
112 for (;;)
114 if (num >= max)
116 if (!quiet)
117 gomp_error ("Logical CPU number %lu out of range", num);
118 return false;
120 CPU_SET_S (num, gomp_cpuset_size, cpusetp);
121 if (--len == 0)
122 return true;
123 if ((stride < 0 && num + stride > num)
124 || (stride > 0 && num + stride < num))
126 if (!quiet)
127 gomp_error ("Logical CPU number %lu+%ld out of range",
128 num, stride);
129 return false;
131 num += stride;
135 bool
136 gomp_affinity_remove_cpu (void *p, unsigned long num)
138 cpu_set_t *cpusetp = (cpu_set_t *) p;
139 if (num >= 8 * gomp_cpuset_size)
141 gomp_error ("Logical CPU number %lu out of range", num);
142 return false;
144 if (!CPU_ISSET_S (num, gomp_cpuset_size, cpusetp))
146 gomp_error ("Logical CPU %lu to be removed is not in the set", num);
147 return false;
149 CPU_CLR_S (num, gomp_cpuset_size, cpusetp);
150 return true;
153 bool
154 gomp_affinity_copy_place (void *p, void *q, long stride)
156 unsigned long i, max = 8 * gomp_cpuset_size;
157 cpu_set_t *destp = (cpu_set_t *) p;
158 cpu_set_t *srcp = (cpu_set_t *) q;
160 CPU_ZERO_S (gomp_cpuset_size, destp);
161 for (i = 0; i < max; i++)
162 if (CPU_ISSET_S (i, gomp_cpuset_size, srcp))
164 if ((stride < 0 && i + stride > i)
165 || (stride > 0 && (i + stride < i || i + stride >= max)))
167 gomp_error ("Logical CPU number %lu+%ld out of range", i, stride);
168 return false;
170 CPU_SET_S (i + stride, gomp_cpuset_size, destp);
172 return true;
175 bool
176 gomp_affinity_same_place (void *p, void *q)
178 #ifdef CPU_EQUAL_S
179 return CPU_EQUAL_S (gomp_cpuset_size, (cpu_set_t *) p, (cpu_set_t *) q);
180 #else
181 return memcmp (p, q, gomp_cpuset_size) == 0;
182 #endif
185 bool
186 gomp_affinity_finalize_place_list (bool quiet)
188 unsigned long i, j;
190 for (i = 0, j = 0; i < gomp_places_list_len; i++)
192 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[i];
193 bool nonempty = false;
194 #ifdef CPU_AND_S
195 CPU_AND_S (gomp_cpuset_size, cpusetp, cpusetp, gomp_cpusetp);
196 nonempty = gomp_cpuset_popcount (gomp_cpuset_size, cpusetp) != 0;
197 #else
198 unsigned long k, max = gomp_cpuset_size / sizeof (cpusetp->__bits[0]);
199 for (k = 0; k < max; k++)
200 if ((cpusetp->__bits[k] &= gomp_cpusetp->__bits[k]) != 0)
201 nonempty = true;
202 #endif
203 if (nonempty)
204 gomp_places_list[j++] = gomp_places_list[i];
207 if (j == 0)
209 if (!quiet)
210 gomp_error ("None of the places contain usable logical CPUs");
211 return false;
213 else if (j < gomp_places_list_len)
215 if (!quiet)
216 gomp_error ("Number of places reduced from %ld to %ld because some "
217 "places didn't contain any usable logical CPUs",
218 gomp_places_list_len, j);
219 gomp_places_list_len = j;
221 return true;
224 bool
225 gomp_affinity_init_level (int level, unsigned long count, bool quiet)
227 unsigned long i, max = 8 * gomp_cpuset_size;
229 if (gomp_cpusetp)
231 unsigned long maxcount
232 = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
233 if (count > maxcount)
234 count = maxcount;
236 gomp_places_list = gomp_affinity_alloc (count, quiet);
237 gomp_places_list_len = 0;
238 if (gomp_places_list == NULL)
239 return false;
240 /* SMT (threads). */
241 if (level == 1)
243 for (i = 0; i < max && gomp_places_list_len < count; i++)
244 if (CPU_ISSET_S (i, gomp_cpuset_size, gomp_cpusetp))
246 gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
247 gomp_affinity_add_cpus (gomp_places_list[gomp_places_list_len],
248 i, 1, 0, true);
249 ++gomp_places_list_len;
251 return true;
253 else
255 char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
256 "thread_siblings_list") + 3 * sizeof (unsigned long)];
257 size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1;
258 cpu_set_t *copy = gomp_alloca (gomp_cpuset_size);
259 FILE *f;
260 char *line = NULL;
261 size_t linelen = 0;
263 memcpy (name, "/sys/devices/system/cpu/cpu", prefix_len);
264 memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
265 for (i = 0; i < max && gomp_places_list_len < count; i++)
266 if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
268 sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
269 i, level == 2 ? "thread" : "core");
270 f = fopen (name, "r");
271 if (f != NULL)
273 if (getline (&line, &linelen, f) > 0)
275 char *p = line;
276 bool seen_i = false;
277 void *pl = gomp_places_list[gomp_places_list_len];
278 gomp_affinity_init_place (pl);
279 while (*p && *p != '\n')
281 unsigned long first, last;
282 errno = 0;
283 first = strtoul (p, &p, 10);
284 if (errno)
285 break;
286 last = first;
287 if (*p == '-')
289 errno = 0;
290 last = strtoul (p + 1, &p, 10);
291 if (errno || last < first)
292 break;
294 for (; first <= last; first++)
295 if (CPU_ISSET_S (first, gomp_cpuset_size, copy)
296 && gomp_affinity_add_cpus (pl, first, 1, 0,
297 true))
299 CPU_CLR_S (first, gomp_cpuset_size, copy);
300 if (first == i)
301 seen_i = true;
303 if (*p == ',')
304 ++p;
306 if (seen_i)
307 gomp_places_list_len++;
309 fclose (f);
312 if (gomp_places_list_len == 0)
314 if (!quiet)
315 gomp_error ("Error reading %s topology",
316 level == 2 ? "core" : "socket");
317 free (gomp_places_list);
318 gomp_places_list = NULL;
319 return false;
321 return true;
323 return false;
326 void
327 gomp_affinity_print_place (void *p)
329 unsigned long i, max = 8 * gomp_cpuset_size, len;
330 cpu_set_t *cpusetp = (cpu_set_t *) p;
331 bool notfirst = false;
333 for (i = 0, len = 0; i < max; i++)
334 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
336 if (len == 0)
338 if (notfirst)
339 fputc (',', stderr);
340 notfirst = true;
341 fprintf (stderr, "%lu", i);
343 ++len;
345 else
347 if (len > 1)
348 fprintf (stderr, ":%lu", len);
349 len = 0;
351 if (len > 1)
352 fprintf (stderr, ":%lu", len);
355 #else
357 #include "../posix/affinity.c"
359 #endif