]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgomp/config/linux/affinity.c
Update copyright years.
[thirdparty/gcc.git] / libgomp / config / linux / affinity.c
1 /* Copyright (C) 2006-2019 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
3
4 This file is part of the GNU Offloading and Multi Processing Library
5 (libgomp).
6
7 Libgomp is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
25
26 /* This is a Linux specific implementation of a CPU affinity setting. */
27
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 <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #ifdef HAVE_PTHREAD_AFFINITY_NP
40
41 #ifndef CPU_ALLOC_SIZE
42 #define CPU_ISSET_S(idx, size, set) CPU_ISSET(idx, set)
43 #define CPU_ZERO_S(size, set) CPU_ZERO(set)
44 #define CPU_SET_S(idx, size, set) CPU_SET(idx, set)
45 #define CPU_CLR_S(idx, size, set) CPU_CLR(idx, set)
46 #endif
47
48 void
49 gomp_init_affinity (void)
50 {
51 if (gomp_places_list == NULL)
52 {
53 if (!gomp_affinity_init_level (1, ULONG_MAX, true))
54 return;
55 }
56
57 struct gomp_thread *thr = gomp_thread ();
58 pthread_setaffinity_np (pthread_self (), gomp_cpuset_size,
59 (cpu_set_t *) gomp_places_list[0]);
60 thr->place = 1;
61 thr->ts.place_partition_off = 0;
62 thr->ts.place_partition_len = gomp_places_list_len;
63 }
64
65 void
66 gomp_init_thread_affinity (pthread_attr_t *attr, unsigned int place)
67 {
68 pthread_attr_setaffinity_np (attr, gomp_cpuset_size,
69 (cpu_set_t *) gomp_places_list[place]);
70 }
71
72 void **
73 gomp_affinity_alloc (unsigned long count, bool quiet)
74 {
75 unsigned long i;
76 void **ret;
77 char *p;
78
79 if (gomp_cpusetp == NULL)
80 {
81 if (!quiet)
82 gomp_error ("Could not get CPU affinity set");
83 return NULL;
84 }
85
86 ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
87 if (ret == NULL)
88 {
89 if (!quiet)
90 gomp_error ("Out of memory trying to allocate places list");
91 return NULL;
92 }
93
94 p = (char *) (ret + count);
95 for (i = 0; i < count; i++, p += gomp_cpuset_size)
96 ret[i] = p;
97 return ret;
98 }
99
100 void
101 gomp_affinity_init_place (void *p)
102 {
103 cpu_set_t *cpusetp = (cpu_set_t *) p;
104 CPU_ZERO_S (gomp_cpuset_size, cpusetp);
105 }
106
107 bool
108 gomp_affinity_add_cpus (void *p, unsigned long num,
109 unsigned long len, long stride, bool quiet)
110 {
111 cpu_set_t *cpusetp = (cpu_set_t *) p;
112 unsigned long max = 8 * gomp_cpuset_size;
113 for (;;)
114 {
115 if (num >= max)
116 {
117 if (!quiet)
118 gomp_error ("Logical CPU number %lu out of range", num);
119 return false;
120 }
121 CPU_SET_S (num, gomp_cpuset_size, cpusetp);
122 if (--len == 0)
123 return true;
124 if ((stride < 0 && num + stride > num)
125 || (stride > 0 && num + stride < num))
126 {
127 if (!quiet)
128 gomp_error ("Logical CPU number %lu+%ld out of range",
129 num, stride);
130 return false;
131 }
132 num += stride;
133 }
134 }
135
136 bool
137 gomp_affinity_remove_cpu (void *p, unsigned long num)
138 {
139 cpu_set_t *cpusetp = (cpu_set_t *) p;
140 if (num >= 8 * gomp_cpuset_size)
141 {
142 gomp_error ("Logical CPU number %lu out of range", num);
143 return false;
144 }
145 if (!CPU_ISSET_S (num, gomp_cpuset_size, cpusetp))
146 {
147 gomp_error ("Logical CPU %lu to be removed is not in the set", num);
148 return false;
149 }
150 CPU_CLR_S (num, gomp_cpuset_size, cpusetp);
151 return true;
152 }
153
154 bool
155 gomp_affinity_copy_place (void *p, void *q, long stride)
156 {
157 unsigned long i, max = 8 * gomp_cpuset_size;
158 cpu_set_t *destp = (cpu_set_t *) p;
159 cpu_set_t *srcp = (cpu_set_t *) q;
160
161 CPU_ZERO_S (gomp_cpuset_size, destp);
162 for (i = 0; i < max; i++)
163 if (CPU_ISSET_S (i, gomp_cpuset_size, srcp))
164 {
165 if ((stride < 0 && i + stride > i)
166 || (stride > 0 && (i + stride < i || i + stride >= max)))
167 {
168 gomp_error ("Logical CPU number %lu+%ld out of range", i, stride);
169 return false;
170 }
171 CPU_SET_S (i + stride, gomp_cpuset_size, destp);
172 }
173 return true;
174 }
175
176 bool
177 gomp_affinity_same_place (void *p, void *q)
178 {
179 #ifdef CPU_EQUAL_S
180 return CPU_EQUAL_S (gomp_cpuset_size, (cpu_set_t *) p, (cpu_set_t *) q);
181 #else
182 return memcmp (p, q, gomp_cpuset_size) == 0;
183 #endif
184 }
185
186 bool
187 gomp_affinity_finalize_place_list (bool quiet)
188 {
189 unsigned long i, j;
190
191 for (i = 0, j = 0; i < gomp_places_list_len; i++)
192 {
193 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[i];
194 bool nonempty = false;
195 #ifdef CPU_AND_S
196 CPU_AND_S (gomp_cpuset_size, cpusetp, cpusetp, gomp_cpusetp);
197 nonempty = gomp_cpuset_popcount (gomp_cpuset_size, cpusetp) != 0;
198 #else
199 unsigned long k, max = gomp_cpuset_size / sizeof (cpusetp->__bits[0]);
200 for (k = 0; k < max; k++)
201 if ((cpusetp->__bits[k] &= gomp_cpusetp->__bits[k]) != 0)
202 nonempty = true;
203 #endif
204 if (nonempty)
205 gomp_places_list[j++] = gomp_places_list[i];
206 }
207
208 if (j == 0)
209 {
210 if (!quiet)
211 gomp_error ("None of the places contain usable logical CPUs");
212 return false;
213 }
214 else if (j < gomp_places_list_len)
215 {
216 if (!quiet)
217 gomp_error ("Number of places reduced from %ld to %ld because some "
218 "places didn't contain any usable logical CPUs",
219 gomp_places_list_len, j);
220 gomp_places_list_len = j;
221 }
222 return true;
223 }
224
225 static void
226 gomp_affinity_init_level_1 (int level, int this_level, unsigned long count,
227 cpu_set_t *copy, char *name, bool quiet)
228 {
229 size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1;
230 FILE *f;
231 char *line = NULL;
232 size_t linelen = 0;
233 unsigned long i, max = 8 * gomp_cpuset_size;
234
235 for (i = 0; i < max && gomp_places_list_len < count; i++)
236 if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
237 {
238 sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
239 i, this_level == 3 ? "core" : "thread");
240 f = fopen (name, "r");
241 if (f == NULL)
242 {
243 CPU_CLR_S (i, gomp_cpuset_size, copy);
244 continue;
245 }
246 if (getline (&line, &linelen, f) > 0)
247 {
248 char *p = line;
249 void *pl = gomp_places_list[gomp_places_list_len];
250 if (level == this_level)
251 gomp_affinity_init_place (pl);
252 while (*p && *p != '\n')
253 {
254 unsigned long first, last;
255 errno = 0;
256 first = strtoul (p, &p, 10);
257 if (errno)
258 break;
259 last = first;
260 if (*p == '-')
261 {
262 errno = 0;
263 last = strtoul (p + 1, &p, 10);
264 if (errno || last < first)
265 break;
266 }
267 for (; first <= last; first++)
268 if (!CPU_ISSET_S (first, gomp_cpuset_size, copy))
269 continue;
270 else if (this_level == 3 && level < this_level)
271 gomp_affinity_init_level_1 (level, 2, count, copy,
272 name, quiet);
273 else
274 {
275 if (level == 1)
276 {
277 pl = gomp_places_list[gomp_places_list_len];
278 gomp_affinity_init_place (pl);
279 }
280 if (gomp_affinity_add_cpus (pl, first, 1, 0, true))
281 {
282 CPU_CLR_S (first, gomp_cpuset_size, copy);
283 if (level == 1)
284 gomp_places_list_len++;
285 }
286 }
287 if (*p == ',')
288 ++p;
289 }
290 if (level == this_level
291 && !CPU_ISSET_S (i, gomp_cpuset_size, copy))
292 gomp_places_list_len++;
293 CPU_CLR_S (i, gomp_cpuset_size, copy);
294 }
295 fclose (f);
296 }
297 free (line);
298 }
299
300 bool
301 gomp_affinity_init_level (int level, unsigned long count, bool quiet)
302 {
303 char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
304 "thread_siblings_list") + 3 * sizeof (unsigned long)];
305 cpu_set_t *copy;
306
307 if (gomp_cpusetp)
308 {
309 unsigned long maxcount
310 = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
311 if (count > maxcount)
312 count = maxcount;
313 }
314 gomp_places_list = gomp_affinity_alloc (count, quiet);
315 gomp_places_list_len = 0;
316 if (gomp_places_list == NULL)
317 return false;
318
319 copy = gomp_alloca (gomp_cpuset_size);
320 strcpy (name, "/sys/devices/system/cpu/cpu");
321 memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
322 gomp_affinity_init_level_1 (level, 3, count, copy, name, quiet);
323 if (gomp_places_list_len == 0)
324 {
325 if (!quiet)
326 gomp_error ("Error reading core/socket topology");
327 free (gomp_places_list);
328 gomp_places_list = NULL;
329 return false;
330 }
331 return true;
332 }
333
334 void
335 gomp_affinity_print_place (void *p)
336 {
337 unsigned long i, max = 8 * gomp_cpuset_size, len;
338 cpu_set_t *cpusetp = (cpu_set_t *) p;
339 bool notfirst = false;
340
341 for (i = 0, len = 0; i < max; i++)
342 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
343 {
344 if (len == 0)
345 {
346 if (notfirst)
347 fputc (',', stderr);
348 notfirst = true;
349 fprintf (stderr, "%lu", i);
350 }
351 ++len;
352 }
353 else
354 {
355 if (len > 1)
356 fprintf (stderr, ":%lu", len);
357 len = 0;
358 }
359 if (len > 1)
360 fprintf (stderr, ":%lu", len);
361 }
362
363 int
364 omp_get_place_num_procs (int place_num)
365 {
366 if (place_num < 0 || place_num >= gomp_places_list_len)
367 return 0;
368
369 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
370 return gomp_cpuset_popcount (gomp_cpuset_size, cpusetp);
371 }
372
373 void
374 omp_get_place_proc_ids (int place_num, int *ids)
375 {
376 if (place_num < 0 || place_num >= gomp_places_list_len)
377 return;
378
379 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
380 unsigned long i, max = 8 * gomp_cpuset_size;
381 for (i = 0; i < max; i++)
382 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
383 *ids++ = i;
384 }
385
386 void
387 gomp_get_place_proc_ids_8 (int place_num, int64_t *ids)
388 {
389 if (place_num < 0 || place_num >= gomp_places_list_len)
390 return;
391
392 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
393 unsigned long i, max = 8 * gomp_cpuset_size;
394 for (i = 0; i < max; i++)
395 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
396 *ids++ = i;
397 }
398
399 void
400 gomp_display_affinity_place (char *buffer, size_t size, size_t *ret,
401 int place)
402 {
403 cpu_set_t *cpusetp;
404 char buf[sizeof (long) * 3 + 4];
405 if (place >= 0 && place < gomp_places_list_len)
406 cpusetp = (cpu_set_t *) gomp_places_list[place];
407 else if (gomp_cpusetp)
408 cpusetp = gomp_cpusetp;
409 else
410 {
411 if (gomp_available_cpus > 1)
412 sprintf (buf, "0-%lu", gomp_available_cpus - 1);
413 else
414 strcpy (buf, "0");
415 gomp_display_string (buffer, size, ret, buf, strlen (buf));
416 return;
417 }
418
419 unsigned long i, max = 8 * gomp_cpuset_size, start;
420 bool prev_set = false;
421 start = max;
422 for (i = 0; i <= max; i++)
423 {
424 bool this_set;
425 if (i == max)
426 this_set = false;
427 else
428 this_set = CPU_ISSET_S (i, gomp_cpuset_size, cpusetp);
429 if (this_set != prev_set)
430 {
431 prev_set = this_set;
432 if (this_set)
433 {
434 char *p = buf;
435 if (start != max)
436 *p++ = ',';
437 sprintf (p, "%lu", i);
438 start = i;
439 }
440 else if (i == start + 1)
441 continue;
442 else
443 sprintf (buf, "-%lu", i - 1);
444 gomp_display_string (buffer, size, ret, buf, strlen (buf));
445 }
446 }
447 }
448
449 ialias(omp_get_place_num_procs)
450 ialias(omp_get_place_proc_ids)
451
452 #else
453
454 #include "../../affinity.c"
455
456 #endif