]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/config/linux/affinity.c
Update copyright years.
[thirdparty/gcc.git] / libgomp / config / linux / affinity.c
CommitLineData
99dee823 1/* Copyright (C) 2006-2021 Free Software Foundation, Inc.
a0884cf0
JJ
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
3
f1f3453e
TS
4 This file is part of the GNU Offloading and Multi Processing Library
5 (libgomp).
a0884cf0
JJ
6
7 Libgomp is free software; you can redistribute it and/or modify it
748086b7
JJ
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.
a0884cf0
JJ
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
748086b7 14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
a0884cf0
JJ
15 more details.
16
748086b7
JJ
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/>. */
a0884cf0
JJ
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"
e0b23d9f 32#include "proc.h"
acf0174b 33#include <errno.h>
a0884cf0 34#include <stdlib.h>
acf0174b
JJ
35#include <stdio.h>
36#include <string.h>
a0884cf0
JJ
37#include <unistd.h>
38
39#ifdef HAVE_PTHREAD_AFFINITY_NP
40
acf0174b
JJ
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
a0884cf0
JJ
47
48void
49gomp_init_affinity (void)
50{
acf0174b
JJ
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
65void
66gomp_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
72void **
73gomp_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 }
a0884cf0 85
acf0174b
JJ
86 ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
87 if (ret == NULL)
a0884cf0 88 {
acf0174b
JJ
89 if (!quiet)
90 gomp_error ("Out of memory trying to allocate places list");
91 return NULL;
a0884cf0
JJ
92 }
93
acf0174b
JJ
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
100void
101gomp_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
107bool
108gomp_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 (;;)
20906c66 114 {
acf0174b
JJ
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))
20906c66 126 {
acf0174b
JJ
127 if (!quiet)
128 gomp_error ("Logical CPU number %lu+%ld out of range",
129 num, stride);
130 return false;
20906c66 131 }
acf0174b
JJ
132 num += stride;
133 }
134}
135
136bool
137gomp_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
154bool
155gomp_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
176bool
177gomp_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
186bool
187gomp_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
01275e1e
JJ
225static void
226gomp_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
acf0174b
JJ
300bool
301gomp_affinity_init_level (int level, unsigned long count, bool quiet)
302{
01275e1e
JJ
303 char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
304 "thread_siblings_list") + 3 * sizeof (unsigned long)];
305 cpu_set_t *copy;
acf0174b
JJ
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;
01275e1e
JJ
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)
acf0174b 324 {
01275e1e
JJ
325 if (!quiet)
326 gomp_error ("Error reading core/socket topology");
327 free (gomp_places_list);
328 gomp_places_list = NULL;
329 return false;
a0884cf0 330 }
01275e1e 331 return true;
a0884cf0
JJ
332}
333
334void
acf0174b 335gomp_affinity_print_place (void *p)
a0884cf0 336{
acf0174b
JJ
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);
a0884cf0
JJ
361}
362
d9a6bd32
JJ
363int
364omp_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
373void
374omp_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
386void
387gomp_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
28567c40
JJ
399void
400gomp_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
d9a6bd32
JJ
449ialias(omp_get_place_num_procs)
450ialias(omp_get_place_proc_ids)
451
a0884cf0
JJ
452#else
453
c7ac071f 454#include "../../affinity.c"
a0884cf0
JJ
455
456#endif