1 /* Copyright (C) 2006-2023 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
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)
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
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. */
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)
50 gomp_init_affinity (void)
52 if (gomp_places_list
== NULL
)
54 if (!gomp_affinity_init_level (1, ULONG_MAX
, true))
58 struct gomp_thread
*thr
= gomp_thread ();
59 pthread_setaffinity_np (pthread_self (), gomp_cpuset_size
,
60 (cpu_set_t
*) gomp_places_list
[0]);
62 thr
->ts
.place_partition_off
= 0;
63 thr
->ts
.place_partition_len
= gomp_places_list_len
;
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
]);
74 gomp_affinity_alloc (unsigned long count
, bool quiet
)
80 if (gomp_cpusetp
== NULL
)
83 gomp_error ("Could not get CPU affinity set");
87 ret
= malloc (count
* sizeof (void *) + count
* gomp_cpuset_size
);
91 gomp_error ("Out of memory trying to allocate places list");
95 p
= (char *) (ret
+ count
);
96 for (i
= 0; i
< count
; i
++, p
+= gomp_cpuset_size
)
102 gomp_affinity_init_place (void *p
)
104 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
105 CPU_ZERO_S (gomp_cpuset_size
, cpusetp
);
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
;
119 gomp_error ("Logical CPU number %lu out of range", num
);
122 CPU_SET_S (num
, gomp_cpuset_size
, cpusetp
);
125 if ((stride
< 0 && num
+ stride
> num
)
126 || (stride
> 0 && num
+ stride
< num
))
129 gomp_error ("Logical CPU number %lu+%ld out of range",
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
);
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
);
151 CPU_CLR_S (num
, gomp_cpuset_size
, cpusetp
);
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
);
172 CPU_SET_S (i
+ stride
, gomp_cpuset_size
, destp
);
178 gomp_affinity_same_place (void *p
, void *q
)
181 return CPU_EQUAL_S (gomp_cpuset_size
, (cpu_set_t
*) p
, (cpu_set_t
*) q
);
183 return memcmp (p
, q
, gomp_cpuset_size
) == 0;
188 gomp_affinity_finalize_place_list (bool quiet
)
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;
197 CPU_AND_S (gomp_cpuset_size
, cpusetp
, cpusetp
, gomp_cpusetp
);
198 nonempty
= gomp_cpuset_popcount (gomp_cpuset_size
, cpusetp
) != 0;
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)
206 gomp_places_list
[j
++] = gomp_places_list
[i
];
212 gomp_error ("None of the places contain usable logical CPUs");
215 else if (j
< gomp_places_list_len
)
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
;
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). */
233 gomp_affinity_find_last_cache_level (char *name
, size_t prefix_len
,
237 unsigned long maxval
= 0;
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");
248 if (getline (&line
, &linelen
, f
) > 0)
253 val
= strtoul (line
, &p
, 10);
254 if (!errno
&& p
> line
&& val
>= maxval
)
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;
274 unsigned long i
, max
= 8 * gomp_cpuset_size
;
277 for (i
= 0; i
< max
&& gomp_places_list_len
< count
; i
++)
278 if (CPU_ISSET_S (i
, gomp_cpuset_size
, copy
))
284 init
= gomp_affinity_find_last_cache_level (name
, prefix_len
,
288 CPU_CLR_S (i
, gomp_cpuset_size
, copy
);
291 sprintf (name
+ prefix_len
,
292 "%lu/cache/index%u/shared_cpu_list", i
, init
);
296 sprintf (name
+ prefix_len
, "%lu/topology/%s_siblings_list",
297 i
, this_level
== 3 ? "core" : "thread");
298 f
= fopen (name
, "r");
301 CPU_CLR_S (i
, gomp_cpuset_size
, copy
);
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
;
314 first
= strtoul (p
, &end
, 10);
315 if (errno
|| end
== p
)
322 last
= strtoul (p
+ 1, &end
, 10);
323 if (errno
|| end
== p
+ 1 || last
< first
)
327 for (; first
<= last
; first
++)
328 if (!CPU_ISSET_S (first
, gomp_cpuset_size
, copy
))
330 else if (this_level
== 3 && level
< this_level
)
331 gomp_affinity_init_level_1 (level
, 2, count
, copy
,
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
);
344 && ++gomp_places_list_len
>= count
)
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
);
366 gomp_affinity_init_numa_domains (unsigned long count
, cpu_set_t
*copy
,
370 char *nline
= NULL
, *line
= NULL
;
371 size_t nlinelen
= 0, linelen
= 0;
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)
385 while (*q
&& *q
!= '\n' && gomp_places_list_len
< count
)
387 unsigned long nfirst
, nlast
;
391 nfirst
= strtoul (q
, &end
, 10);
392 if (errno
|| end
== q
)
399 nlast
= strtoul (q
+ 1, &end
, 10);
400 if (errno
|| end
== q
+ 1 || nlast
< nfirst
)
404 for (; nfirst
<= nlast
&& gomp_places_list_len
< count
; nfirst
++)
406 sprintf (name
+ prefix_len
, "node%lu/cpulist", nfirst
);
407 f
= fopen (name
, "r");
410 if (getline (&line
, &linelen
, f
) > 0)
416 while (*p
&& *p
!= '\n')
418 unsigned long first
, last
;
421 first
= strtoul (p
, &end
, 10);
422 if (errno
|| end
== p
)
429 last
= strtoul (p
+ 1, &end
, 10);
430 if (errno
|| end
== p
+ 1 || last
< first
)
434 for (; first
<= last
; first
++)
436 if (!CPU_ISSET_S (first
, gomp_cpuset_size
, copy
))
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
);
448 gomp_places_list_len
++;
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)];
475 unsigned long maxcount
476 = gomp_cpuset_popcount (gomp_cpuset_size
, gomp_cpusetp
);
477 if (count
> maxcount
)
480 gomp_places_list
= gomp_affinity_alloc (count
, quiet
);
481 gomp_places_list_len
= 0;
482 if (gomp_places_list
== NULL
)
485 copy
= gomp_alloca (gomp_cpuset_size
);
486 strcpy (name
, "/sys/devices/system/cpu/cpu");
487 memcpy (copy
, gomp_cpusetp
, gomp_cpuset_size
);
489 gomp_affinity_init_numa_domains (count
, copy
, name
);
491 gomp_affinity_init_level_1 (level
, level
> 3 ? level
: 3, count
, copy
,
493 if (gomp_places_list_len
== 0)
496 gomp_error ("Error reading core/socket topology");
497 free (gomp_places_list
);
498 gomp_places_list
= NULL
;
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
))
519 fprintf (stderr
, "%lu", i
);
526 fprintf (stderr
, ":%lu", len
);
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
)
539 cpu_set_t
*cpusetp
= (cpu_set_t
*) gomp_places_list
[place_num
];
540 return gomp_cpuset_popcount (gomp_cpuset_size
, cpusetp
);
544 omp_get_place_proc_ids (int place_num
, int *ids
)
546 if (place_num
< 0 || place_num
>= gomp_places_list_len
)
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
))
557 gomp_get_place_proc_ids_8 (int place_num
, int64_t *ids
)
559 if (place_num
< 0 || place_num
>= gomp_places_list_len
)
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
))
570 gomp_display_affinity_place (char *buffer
, size_t size
, size_t *ret
,
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
;
581 if (gomp_available_cpus
> 1)
582 sprintf (buf
, "0-%lu", gomp_available_cpus
- 1);
585 gomp_display_string (buffer
, size
, ret
, buf
, strlen (buf
));
589 unsigned long i
, max
= 8 * gomp_cpuset_size
, start
;
590 bool prev_set
= false;
592 for (i
= 0; i
<= max
; i
++)
598 this_set
= CPU_ISSET_S (i
, gomp_cpuset_size
, cpusetp
);
599 if (this_set
!= prev_set
)
607 sprintf (p
, "%lu", i
);
610 else if (i
== start
+ 1)
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
)
624 #include "../../affinity.c"