]>
Commit | Line | Data |
---|---|---|
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 | |
48 | void | |
49 | gomp_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 | ||
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 | } | |
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 | ||
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 (;;) | |
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 | ||
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 | ||
01275e1e JJ |
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 | ||
acf0174b JJ |
300 | bool |
301 | gomp_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 | ||
334 | void | |
acf0174b | 335 | gomp_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 |
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 | ||
28567c40 JJ |
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 | ||
d9a6bd32 JJ |
449 | ialias(omp_get_place_num_procs) |
450 | ialias(omp_get_place_proc_ids) | |
451 | ||
a0884cf0 JJ |
452 | #else |
453 | ||
c7ac071f | 454 | #include "../../affinity.c" |
a0884cf0 JJ |
455 | |
456 | #endif |