1 /* Copyright (C) 2006-2018 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. */
39 #ifdef HAVE_PTHREAD_AFFINITY_NP
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)
49 gomp_init_affinity (void)
51 if (gomp_places_list
== NULL
)
53 if (!gomp_affinity_init_level (1, ULONG_MAX
, true))
57 struct gomp_thread
*thr
= gomp_thread ();
58 pthread_setaffinity_np (pthread_self (), gomp_cpuset_size
,
59 (cpu_set_t
*) gomp_places_list
[0]);
61 thr
->ts
.place_partition_off
= 0;
62 thr
->ts
.place_partition_len
= gomp_places_list_len
;
66 gomp_init_thread_affinity (pthread_attr_t
*attr
, unsigned int place
)
68 pthread_attr_setaffinity_np (attr
, gomp_cpuset_size
,
69 (cpu_set_t
*) gomp_places_list
[place
]);
73 gomp_affinity_alloc (unsigned long count
, bool quiet
)
79 if (gomp_cpusetp
== NULL
)
82 gomp_error ("Could not get CPU affinity set");
86 ret
= malloc (count
* sizeof (void *) + count
* gomp_cpuset_size
);
90 gomp_error ("Out of memory trying to allocate places list");
94 p
= (char *) (ret
+ count
);
95 for (i
= 0; i
< count
; i
++, p
+= gomp_cpuset_size
)
101 gomp_affinity_init_place (void *p
)
103 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
104 CPU_ZERO_S (gomp_cpuset_size
, cpusetp
);
108 gomp_affinity_add_cpus (void *p
, unsigned long num
,
109 unsigned long len
, long stride
, bool quiet
)
111 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
112 unsigned long max
= 8 * gomp_cpuset_size
;
118 gomp_error ("Logical CPU number %lu out of range", num
);
121 CPU_SET_S (num
, gomp_cpuset_size
, cpusetp
);
124 if ((stride
< 0 && num
+ stride
> num
)
125 || (stride
> 0 && num
+ stride
< num
))
128 gomp_error ("Logical CPU number %lu+%ld out of range",
137 gomp_affinity_remove_cpu (void *p
, unsigned long num
)
139 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
140 if (num
>= 8 * gomp_cpuset_size
)
142 gomp_error ("Logical CPU number %lu out of range", num
);
145 if (!CPU_ISSET_S (num
, gomp_cpuset_size
, cpusetp
))
147 gomp_error ("Logical CPU %lu to be removed is not in the set", num
);
150 CPU_CLR_S (num
, gomp_cpuset_size
, cpusetp
);
155 gomp_affinity_copy_place (void *p
, void *q
, long stride
)
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
;
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
))
165 if ((stride
< 0 && i
+ stride
> i
)
166 || (stride
> 0 && (i
+ stride
< i
|| i
+ stride
>= max
)))
168 gomp_error ("Logical CPU number %lu+%ld out of range", i
, stride
);
171 CPU_SET_S (i
+ stride
, gomp_cpuset_size
, destp
);
177 gomp_affinity_same_place (void *p
, void *q
)
180 return CPU_EQUAL_S (gomp_cpuset_size
, (cpu_set_t
*) p
, (cpu_set_t
*) q
);
182 return memcmp (p
, q
, gomp_cpuset_size
) == 0;
187 gomp_affinity_finalize_place_list (bool quiet
)
191 for (i
= 0, j
= 0; i
< gomp_places_list_len
; i
++)
193 cpu_set_t
*cpusetp
= (cpu_set_t
*) gomp_places_list
[i
];
194 bool nonempty
= false;
196 CPU_AND_S (gomp_cpuset_size
, cpusetp
, cpusetp
, gomp_cpusetp
);
197 nonempty
= gomp_cpuset_popcount (gomp_cpuset_size
, cpusetp
) != 0;
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)
205 gomp_places_list
[j
++] = gomp_places_list
[i
];
211 gomp_error ("None of the places contain usable logical CPUs");
214 else if (j
< gomp_places_list_len
)
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
;
226 gomp_affinity_init_level_1 (int level
, int this_level
, unsigned long count
,
227 cpu_set_t
*copy
, char *name
, bool quiet
)
229 size_t prefix_len
= sizeof ("/sys/devices/system/cpu/cpu") - 1;
233 unsigned long i
, max
= 8 * gomp_cpuset_size
;
235 for (i
= 0; i
< max
&& gomp_places_list_len
< count
; i
++)
236 if (CPU_ISSET_S (i
, gomp_cpuset_size
, copy
))
238 sprintf (name
+ prefix_len
, "%lu/topology/%s_siblings_list",
239 i
, this_level
== 3 ? "core" : "thread");
240 f
= fopen (name
, "r");
243 CPU_CLR_S (i
, gomp_cpuset_size
, copy
);
246 if (getline (&line
, &linelen
, f
) > 0)
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')
254 unsigned long first
, last
;
256 first
= strtoul (p
, &p
, 10);
263 last
= strtoul (p
+ 1, &p
, 10);
264 if (errno
|| last
< first
)
267 for (; first
<= last
; first
++)
268 if (!CPU_ISSET_S (first
, gomp_cpuset_size
, copy
))
270 else if (this_level
== 3 && level
< this_level
)
271 gomp_affinity_init_level_1 (level
, 2, count
, copy
,
277 pl
= gomp_places_list
[gomp_places_list_len
];
278 gomp_affinity_init_place (pl
);
280 if (gomp_affinity_add_cpus (pl
, first
, 1, 0, true))
282 CPU_CLR_S (first
, gomp_cpuset_size
, copy
);
284 gomp_places_list_len
++;
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
);
301 gomp_affinity_init_level (int level
, unsigned long count
, bool quiet
)
303 char name
[sizeof ("/sys/devices/system/cpu/cpu/topology/"
304 "thread_siblings_list") + 3 * sizeof (unsigned long)];
309 unsigned long maxcount
310 = gomp_cpuset_popcount (gomp_cpuset_size
, gomp_cpusetp
);
311 if (count
> maxcount
)
314 gomp_places_list
= gomp_affinity_alloc (count
, quiet
);
315 gomp_places_list_len
= 0;
316 if (gomp_places_list
== NULL
)
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)
326 gomp_error ("Error reading core/socket topology");
327 free (gomp_places_list
);
328 gomp_places_list
= NULL
;
335 gomp_affinity_print_place (void *p
)
337 unsigned long i
, max
= 8 * gomp_cpuset_size
, len
;
338 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
339 bool notfirst
= false;
341 for (i
= 0, len
= 0; i
< max
; i
++)
342 if (CPU_ISSET_S (i
, gomp_cpuset_size
, cpusetp
))
349 fprintf (stderr
, "%lu", i
);
356 fprintf (stderr
, ":%lu", len
);
360 fprintf (stderr
, ":%lu", len
);
364 omp_get_place_num_procs (int place_num
)
366 if (place_num
< 0 || place_num
>= gomp_places_list_len
)
369 cpu_set_t
*cpusetp
= (cpu_set_t
*) gomp_places_list
[place_num
];
370 return gomp_cpuset_popcount (gomp_cpuset_size
, cpusetp
);
374 omp_get_place_proc_ids (int place_num
, int *ids
)
376 if (place_num
< 0 || place_num
>= gomp_places_list_len
)
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
))
387 gomp_get_place_proc_ids_8 (int place_num
, int64_t *ids
)
389 if (place_num
< 0 || place_num
>= gomp_places_list_len
)
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
))
399 ialias(omp_get_place_num_procs
)
400 ialias(omp_get_place_proc_ids
)
404 #include "../../affinity.c"