vect: Optimize order of lane-reducing operations in loop def-use cycles
[official-gcc.git] / libgomp / config / linux / affinity.c
blob5764fcdd1170469f9472d14b3d0aaf8f4c0ca973
1 /* Copyright (C) 2006-2024 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU Offloading and Multi Processing Library
5 (libgomp).
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.
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.
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.
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/>. */
26 /* This is a Linux specific implementation of a CPU affinity setting. */
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 #include <limits.h>
40 #ifdef HAVE_PTHREAD_AFFINITY_NP
42 #ifndef CPU_ALLOC_SIZE
43 #define CPU_ISSET_S(idx, size, set) CPU_ISSET(idx, set)
44 #define CPU_ZERO_S(size, set) CPU_ZERO(set)
45 #define CPU_SET_S(idx, size, set) CPU_SET(idx, set)
46 #define CPU_CLR_S(idx, size, set) CPU_CLR(idx, set)
47 #endif
49 void
50 gomp_init_affinity (void)
52 if (gomp_places_list == NULL)
54 if (!gomp_affinity_init_level (1, ULONG_MAX, true))
55 return;
58 struct gomp_thread *thr = gomp_thread ();
59 pthread_setaffinity_np (pthread_self (), gomp_cpuset_size,
60 (cpu_set_t *) gomp_places_list[0]);
61 thr->place = 1;
62 thr->ts.place_partition_off = 0;
63 thr->ts.place_partition_len = gomp_places_list_len;
66 void
67 gomp_init_thread_affinity (pthread_attr_t *attr, unsigned int place)
69 pthread_attr_setaffinity_np (attr, gomp_cpuset_size,
70 (cpu_set_t *) gomp_places_list[place]);
73 void **
74 gomp_affinity_alloc (unsigned long count, bool quiet)
76 unsigned long i;
77 void **ret;
78 char *p;
80 if (gomp_cpusetp == NULL)
82 if (!quiet)
83 gomp_error ("Could not get CPU affinity set");
84 return NULL;
87 ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
88 if (ret == NULL)
90 if (!quiet)
91 gomp_error ("Out of memory trying to allocate places list");
92 return NULL;
95 p = (char *) (ret + count);
96 for (i = 0; i < count; i++, p += gomp_cpuset_size)
97 ret[i] = p;
98 return ret;
101 void
102 gomp_affinity_init_place (void *p)
104 cpu_set_t *cpusetp = (cpu_set_t *) p;
105 CPU_ZERO_S (gomp_cpuset_size, cpusetp);
108 bool
109 gomp_affinity_add_cpus (void *p, unsigned long num,
110 unsigned long len, long stride, bool quiet)
112 cpu_set_t *cpusetp = (cpu_set_t *) p;
113 unsigned long max = 8 * gomp_cpuset_size;
114 for (;;)
116 if (num >= max)
118 if (!quiet)
119 gomp_error ("Logical CPU number %lu out of range", num);
120 return false;
122 CPU_SET_S (num, gomp_cpuset_size, cpusetp);
123 if (--len == 0)
124 return true;
125 if ((stride < 0 && num + stride > num)
126 || (stride > 0 && num + stride < num))
128 if (!quiet)
129 gomp_error ("Logical CPU number %lu+%ld out of range",
130 num, stride);
131 return false;
133 num += stride;
137 bool
138 gomp_affinity_remove_cpu (void *p, unsigned long num)
140 cpu_set_t *cpusetp = (cpu_set_t *) p;
141 if (num >= 8 * gomp_cpuset_size)
143 gomp_error ("Logical CPU number %lu out of range", num);
144 return false;
146 if (!CPU_ISSET_S (num, gomp_cpuset_size, cpusetp))
148 gomp_error ("Logical CPU %lu to be removed is not in the set", num);
149 return false;
151 CPU_CLR_S (num, gomp_cpuset_size, cpusetp);
152 return true;
155 bool
156 gomp_affinity_copy_place (void *p, void *q, long stride)
158 unsigned long i, max = 8 * gomp_cpuset_size;
159 cpu_set_t *destp = (cpu_set_t *) p;
160 cpu_set_t *srcp = (cpu_set_t *) q;
162 CPU_ZERO_S (gomp_cpuset_size, destp);
163 for (i = 0; i < max; i++)
164 if (CPU_ISSET_S (i, gomp_cpuset_size, srcp))
166 if ((stride < 0 && i + stride > i)
167 || (stride > 0 && (i + stride < i || i + stride >= max)))
169 gomp_error ("Logical CPU number %lu+%ld out of range", i, stride);
170 return false;
172 CPU_SET_S (i + stride, gomp_cpuset_size, destp);
174 return true;
177 bool
178 gomp_affinity_same_place (void *p, void *q)
180 #ifdef CPU_EQUAL_S
181 return CPU_EQUAL_S (gomp_cpuset_size, (cpu_set_t *) p, (cpu_set_t *) q);
182 #else
183 return memcmp (p, q, gomp_cpuset_size) == 0;
184 #endif
187 bool
188 gomp_affinity_finalize_place_list (bool quiet)
190 unsigned long i, j;
192 for (i = 0, j = 0; i < gomp_places_list_len; i++)
194 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[i];
195 bool nonempty = false;
196 #ifdef CPU_AND_S
197 CPU_AND_S (gomp_cpuset_size, cpusetp, cpusetp, gomp_cpusetp);
198 nonempty = gomp_cpuset_popcount (gomp_cpuset_size, cpusetp) != 0;
199 #else
200 unsigned long k, max = gomp_cpuset_size / sizeof (cpusetp->__bits[0]);
201 for (k = 0; k < max; k++)
202 if ((cpusetp->__bits[k] &= gomp_cpusetp->__bits[k]) != 0)
203 nonempty = true;
204 #endif
205 if (nonempty)
206 gomp_places_list[j++] = gomp_places_list[i];
209 if (j == 0)
211 if (!quiet)
212 gomp_error ("None of the places contain usable logical CPUs");
213 return false;
215 else if (j < gomp_places_list_len)
217 if (!quiet)
218 gomp_error ("Number of places reduced from %ld to %ld because some "
219 "places didn't contain any usable logical CPUs",
220 gomp_places_list_len, j);
221 gomp_places_list_len = j;
223 return true;
226 /* Find the index of the last level cache. We assume the index
227 of the last level cache is the same for all logical CPUs.
228 Also, if there are multiple caches with the same highest level,
229 assume they have the same shared_cpu_list and pick the last one
230 from them (highest index number). */
232 static int
233 gomp_affinity_find_last_cache_level (char *name, size_t prefix_len,
234 unsigned long cpu)
236 int ret = -1;
237 unsigned long maxval = 0;
238 char *line = NULL;
239 size_t linelen = 0;
240 FILE *f;
242 for (int l = 0; l < 128; l++)
244 sprintf (name + prefix_len, "%lu/cache/index%u/level", cpu, l);
245 f = fopen (name, "r");
246 if (f == NULL)
247 break;
248 if (getline (&line, &linelen, f) > 0)
250 unsigned long val;
251 char *p;
252 errno = 0;
253 val = strtoul (line, &p, 10);
254 if (!errno && p > line && val >= maxval)
256 ret = l;
257 maxval = val;
260 fclose (f);
262 free (line);
263 return ret;
266 static void
267 gomp_affinity_init_level_1 (int level, int this_level, unsigned long count,
268 cpu_set_t *copy, char *name, bool quiet)
270 size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1;
271 FILE *f;
272 char *line = NULL;
273 size_t linelen = 0;
274 unsigned long i, max = 8 * gomp_cpuset_size;
275 int init = -1;
277 for (i = 0; i < max && gomp_places_list_len < count; i++)
278 if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
280 if (level == 4)
282 if (init == -1)
284 init = gomp_affinity_find_last_cache_level (name, prefix_len,
286 if (init == -1)
288 CPU_CLR_S (i, gomp_cpuset_size, copy);
289 continue;
291 sprintf (name + prefix_len,
292 "%lu/cache/index%u/shared_cpu_list", i, init);
295 else
296 sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
297 i, this_level == 3 ? "core" : "thread");
298 f = fopen (name, "r");
299 if (f == NULL)
301 CPU_CLR_S (i, gomp_cpuset_size, copy);
302 continue;
304 if (getline (&line, &linelen, f) > 0)
306 char *p = line, *end;
307 void *pl = gomp_places_list[gomp_places_list_len];
308 if (level == this_level)
309 gomp_affinity_init_place (pl);
310 while (*p && *p != '\n')
312 unsigned long first, last;
313 errno = 0;
314 first = strtoul (p, &end, 10);
315 if (errno || end == p)
316 break;
317 p = end;
318 last = first;
319 if (*p == '-')
321 errno = 0;
322 last = strtoul (p + 1, &end, 10);
323 if (errno || end == p + 1 || last < first)
324 break;
325 p = end;
327 for (; first <= last; first++)
328 if (!CPU_ISSET_S (first, gomp_cpuset_size, copy))
329 continue;
330 else if (this_level == 3 && level < this_level)
331 gomp_affinity_init_level_1 (level, 2, count, copy,
332 name, quiet);
333 else
335 if (level == 1)
337 pl = gomp_places_list[gomp_places_list_len];
338 gomp_affinity_init_place (pl);
340 if (gomp_affinity_add_cpus (pl, first, 1, 0, true))
342 CPU_CLR_S (first, gomp_cpuset_size, copy);
343 if (level == 1
344 && ++gomp_places_list_len >= count)
346 fclose (f);
347 free (line);
348 return;
352 if (*p == ',')
353 ++p;
355 if (level == this_level
356 && !CPU_ISSET_S (i, gomp_cpuset_size, copy))
357 gomp_places_list_len++;
358 CPU_CLR_S (i, gomp_cpuset_size, copy);
360 fclose (f);
362 free (line);
365 static void
366 gomp_affinity_init_numa_domains (unsigned long count, cpu_set_t *copy,
367 char *name)
369 FILE *f;
370 char *nline = NULL, *line = NULL;
371 size_t nlinelen = 0, linelen = 0;
372 char *q;
373 size_t prefix_len = sizeof ("/sys/devices/system/node/") - 1;
375 strcpy (name, "/sys/devices/system/node/online");
376 f = fopen (name, "r");
377 if (f == NULL || getline (&nline, &nlinelen, f) <= 0)
379 if (f)
380 fclose (f);
381 return;
383 fclose (f);
384 q = nline;
385 while (*q && *q != '\n' && gomp_places_list_len < count)
387 unsigned long nfirst, nlast;
388 char *end;
390 errno = 0;
391 nfirst = strtoul (q, &end, 10);
392 if (errno || end == q)
393 break;
394 q = end;
395 nlast = nfirst;
396 if (*q == '-')
398 errno = 0;
399 nlast = strtoul (q + 1, &end, 10);
400 if (errno || end == q + 1 || nlast < nfirst)
401 break;
402 q = end;
404 for (; nfirst <= nlast && gomp_places_list_len < count; nfirst++)
406 sprintf (name + prefix_len, "node%lu/cpulist", nfirst);
407 f = fopen (name, "r");
408 if (f == NULL)
409 continue;
410 if (getline (&line, &linelen, f) > 0)
412 char *p = line;
413 void *pl = NULL;
414 bool seen = false;
416 while (*p && *p != '\n')
418 unsigned long first, last;
420 errno = 0;
421 first = strtoul (p, &end, 10);
422 if (errno || end == p)
423 break;
424 p = end;
425 last = first;
426 if (*p == '-')
428 errno = 0;
429 last = strtoul (p + 1, &end, 10);
430 if (errno || end == p + 1 || last < first)
431 break;
432 p = end;
434 for (; first <= last; first++)
436 if (!CPU_ISSET_S (first, gomp_cpuset_size, copy))
437 continue;
438 if (pl == NULL)
440 pl = gomp_places_list[gomp_places_list_len];
441 gomp_affinity_init_place (pl);
443 if (gomp_affinity_add_cpus (pl, first, 1, 0, true))
445 CPU_CLR_S (first, gomp_cpuset_size, copy);
446 if (!seen)
448 gomp_places_list_len++;
449 seen = true;
453 if (*p == ',')
454 ++p;
457 fclose (f);
459 if (*q == ',')
460 ++q;
462 free (line);
463 free (nline);
466 bool
467 gomp_affinity_init_level (int level, unsigned long count, bool quiet)
469 char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
470 "thread_siblings_list") + 6 * sizeof (unsigned long)];
471 cpu_set_t *copy;
473 if (gomp_cpusetp)
475 unsigned long maxcount
476 = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
477 if (count > maxcount)
478 count = maxcount;
480 gomp_places_list = gomp_affinity_alloc (count, quiet);
481 gomp_places_list_len = 0;
482 if (gomp_places_list == NULL)
483 return false;
485 copy = gomp_alloca (gomp_cpuset_size);
486 strcpy (name, "/sys/devices/system/cpu/cpu");
487 memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
488 if (level == 5)
489 gomp_affinity_init_numa_domains (count, copy, name);
490 else
491 gomp_affinity_init_level_1 (level, level > 3 ? level : 3, count, copy,
492 name, quiet);
493 if (gomp_places_list_len == 0)
495 if (!quiet)
496 gomp_error ("Error reading core/socket topology");
497 free (gomp_places_list);
498 gomp_places_list = NULL;
499 return false;
501 return true;
504 void
505 gomp_affinity_print_place (void *p)
507 unsigned long i, max = 8 * gomp_cpuset_size, len;
508 cpu_set_t *cpusetp = (cpu_set_t *) p;
509 bool notfirst = false;
511 for (i = 0, len = 0; i < max; i++)
512 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
514 if (len == 0)
516 if (notfirst)
517 fputc (',', stderr);
518 notfirst = true;
519 fprintf (stderr, "%lu", i);
521 ++len;
523 else
525 if (len > 1)
526 fprintf (stderr, ":%lu", len);
527 len = 0;
529 if (len > 1)
530 fprintf (stderr, ":%lu", len);
534 omp_get_place_num_procs (int place_num)
536 if (place_num < 0 || place_num >= gomp_places_list_len)
537 return 0;
539 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
540 return gomp_cpuset_popcount (gomp_cpuset_size, cpusetp);
543 void
544 omp_get_place_proc_ids (int place_num, int *ids)
546 if (place_num < 0 || place_num >= gomp_places_list_len)
547 return;
549 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
550 unsigned long i, max = 8 * gomp_cpuset_size;
551 for (i = 0; i < max; i++)
552 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
553 *ids++ = i;
556 void
557 gomp_get_place_proc_ids_8 (int place_num, int64_t *ids)
559 if (place_num < 0 || place_num >= gomp_places_list_len)
560 return;
562 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
563 unsigned long i, max = 8 * gomp_cpuset_size;
564 for (i = 0; i < max; i++)
565 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
566 *ids++ = i;
569 void
570 gomp_display_affinity_place (char *buffer, size_t size, size_t *ret,
571 int place)
573 cpu_set_t *cpusetp;
574 char buf[sizeof (long) * 3 + 4];
575 if (place >= 0 && place < gomp_places_list_len)
576 cpusetp = (cpu_set_t *) gomp_places_list[place];
577 else if (gomp_cpusetp)
578 cpusetp = gomp_cpusetp;
579 else
581 if (gomp_available_cpus > 1)
582 sprintf (buf, "0-%lu", gomp_available_cpus - 1);
583 else
584 strcpy (buf, "0");
585 gomp_display_string (buffer, size, ret, buf, strlen (buf));
586 return;
589 unsigned long i, max = 8 * gomp_cpuset_size, start;
590 bool prev_set = false;
591 start = max;
592 for (i = 0; i <= max; i++)
594 bool this_set;
595 if (i == max)
596 this_set = false;
597 else
598 this_set = CPU_ISSET_S (i, gomp_cpuset_size, cpusetp);
599 if (this_set != prev_set)
601 prev_set = this_set;
602 if (this_set)
604 char *p = buf;
605 if (start != max)
606 *p++ = ',';
607 sprintf (p, "%lu", i);
608 start = i;
610 else if (i == start + 1)
611 continue;
612 else
613 sprintf (buf, "-%lu", i - 1);
614 gomp_display_string (buffer, size, ret, buf, strlen (buf));
619 ialias(omp_get_place_num_procs)
620 ialias(omp_get_place_proc_ids)
622 #else
624 #include "../../affinity.c"
626 #endif