1 /* Copyright (C) 2006-2014 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
4 This file is part of the GNU OpenMP Library (libgomp).
6 Libgomp is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 Under Section 7 of GPL version 3, you are granted additional
17 permissions described in the GCC Runtime Library Exception, version
18 3.1, as published by the Free Software Foundation.
20 You should have received a copy of the GNU General Public License and
21 a copy of the GCC Runtime Library Exception along with this program;
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 <http://www.gnu.org/licenses/>. */
25 /* This is a Linux specific implementation of a CPU affinity setting. */
38 #ifdef HAVE_PTHREAD_AFFINITY_NP
40 #ifndef CPU_ALLOC_SIZE
41 #define CPU_ISSET_S(idx, size, set) CPU_ISSET(idx, set)
42 #define CPU_ZERO_S(size, set) CPU_ZERO(set)
43 #define CPU_SET_S(idx, size, set) CPU_SET(idx, set)
44 #define CPU_CLR_S(idx, size, set) CPU_CLR(idx, set)
48 gomp_init_affinity (void)
50 if (gomp_places_list
== NULL
)
52 if (!gomp_affinity_init_level (1, ULONG_MAX
, true))
56 struct gomp_thread
*thr
= gomp_thread ();
57 pthread_setaffinity_np (pthread_self (), gomp_cpuset_size
,
58 (cpu_set_t
*) gomp_places_list
[0]);
60 thr
->ts
.place_partition_off
= 0;
61 thr
->ts
.place_partition_len
= gomp_places_list_len
;
65 gomp_init_thread_affinity (pthread_attr_t
*attr
, unsigned int place
)
67 pthread_attr_setaffinity_np (attr
, gomp_cpuset_size
,
68 (cpu_set_t
*) gomp_places_list
[place
]);
72 gomp_affinity_alloc (unsigned long count
, bool quiet
)
78 if (gomp_cpusetp
== NULL
)
81 gomp_error ("Could not get CPU affinity set");
85 ret
= malloc (count
* sizeof (void *) + count
* gomp_cpuset_size
);
89 gomp_error ("Out of memory trying to allocate places list");
93 p
= (char *) (ret
+ count
);
94 for (i
= 0; i
< count
; i
++, p
+= gomp_cpuset_size
)
100 gomp_affinity_init_place (void *p
)
102 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
103 CPU_ZERO_S (gomp_cpuset_size
, cpusetp
);
107 gomp_affinity_add_cpus (void *p
, unsigned long num
,
108 unsigned long len
, long stride
, bool quiet
)
110 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
111 unsigned long max
= 8 * gomp_cpuset_size
;
117 gomp_error ("Logical CPU number %lu out of range", num
);
120 CPU_SET_S (num
, gomp_cpuset_size
, cpusetp
);
123 if ((stride
< 0 && num
+ stride
> num
)
124 || (stride
> 0 && num
+ stride
< num
))
127 gomp_error ("Logical CPU number %lu+%ld out of range",
136 gomp_affinity_remove_cpu (void *p
, unsigned long num
)
138 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
139 if (num
>= 8 * gomp_cpuset_size
)
141 gomp_error ("Logical CPU number %lu out of range", num
);
144 if (!CPU_ISSET_S (num
, gomp_cpuset_size
, cpusetp
))
146 gomp_error ("Logical CPU %lu to be removed is not in the set", num
);
149 CPU_CLR_S (num
, gomp_cpuset_size
, cpusetp
);
154 gomp_affinity_copy_place (void *p
, void *q
, long stride
)
156 unsigned long i
, max
= 8 * gomp_cpuset_size
;
157 cpu_set_t
*destp
= (cpu_set_t
*) p
;
158 cpu_set_t
*srcp
= (cpu_set_t
*) q
;
160 CPU_ZERO_S (gomp_cpuset_size
, destp
);
161 for (i
= 0; i
< max
; i
++)
162 if (CPU_ISSET_S (i
, gomp_cpuset_size
, srcp
))
164 if ((stride
< 0 && i
+ stride
> i
)
165 || (stride
> 0 && (i
+ stride
< i
|| i
+ stride
>= max
)))
167 gomp_error ("Logical CPU number %lu+%ld out of range", i
, stride
);
170 CPU_SET_S (i
+ stride
, gomp_cpuset_size
, destp
);
176 gomp_affinity_same_place (void *p
, void *q
)
179 return CPU_EQUAL_S (gomp_cpuset_size
, (cpu_set_t
*) p
, (cpu_set_t
*) q
);
181 return memcmp (p
, q
, gomp_cpuset_size
) == 0;
186 gomp_affinity_finalize_place_list (bool quiet
)
190 for (i
= 0, j
= 0; i
< gomp_places_list_len
; i
++)
192 cpu_set_t
*cpusetp
= (cpu_set_t
*) gomp_places_list
[i
];
193 bool nonempty
= false;
195 CPU_AND_S (gomp_cpuset_size
, cpusetp
, cpusetp
, gomp_cpusetp
);
196 nonempty
= gomp_cpuset_popcount (gomp_cpuset_size
, cpusetp
) != 0;
198 unsigned long k
, max
= gomp_cpuset_size
/ sizeof (cpusetp
->__bits
[0]);
199 for (k
= 0; k
< max
; k
++)
200 if ((cpusetp
->__bits
[k
] &= gomp_cpusetp
->__bits
[k
]) != 0)
204 gomp_places_list
[j
++] = gomp_places_list
[i
];
210 gomp_error ("None of the places contain usable logical CPUs");
213 else if (j
< gomp_places_list_len
)
216 gomp_error ("Number of places reduced from %ld to %ld because some "
217 "places didn't contain any usable logical CPUs",
218 gomp_places_list_len
, j
);
219 gomp_places_list_len
= j
;
225 gomp_affinity_init_level (int level
, unsigned long count
, bool quiet
)
227 unsigned long i
, max
= 8 * gomp_cpuset_size
;
231 unsigned long maxcount
232 = gomp_cpuset_popcount (gomp_cpuset_size
, gomp_cpusetp
);
233 if (count
> maxcount
)
236 gomp_places_list
= gomp_affinity_alloc (count
, quiet
);
237 gomp_places_list_len
= 0;
238 if (gomp_places_list
== NULL
)
243 for (i
= 0; i
< max
&& gomp_places_list_len
< count
; i
++)
244 if (CPU_ISSET_S (i
, gomp_cpuset_size
, gomp_cpusetp
))
246 gomp_affinity_init_place (gomp_places_list
[gomp_places_list_len
]);
247 gomp_affinity_add_cpus (gomp_places_list
[gomp_places_list_len
],
249 ++gomp_places_list_len
;
255 char name
[sizeof ("/sys/devices/system/cpu/cpu/topology/"
256 "thread_siblings_list") + 3 * sizeof (unsigned long)];
257 size_t prefix_len
= sizeof ("/sys/devices/system/cpu/cpu") - 1;
258 cpu_set_t
*copy
= gomp_alloca (gomp_cpuset_size
);
263 memcpy (name
, "/sys/devices/system/cpu/cpu", prefix_len
);
264 memcpy (copy
, gomp_cpusetp
, gomp_cpuset_size
);
265 for (i
= 0; i
< max
&& gomp_places_list_len
< count
; i
++)
266 if (CPU_ISSET_S (i
, gomp_cpuset_size
, copy
))
268 sprintf (name
+ prefix_len
, "%lu/topology/%s_siblings_list",
269 i
, level
== 2 ? "thread" : "core");
270 f
= fopen (name
, "r");
273 if (getline (&line
, &linelen
, f
) > 0)
277 void *pl
= gomp_places_list
[gomp_places_list_len
];
278 gomp_affinity_init_place (pl
);
279 while (*p
&& *p
!= '\n')
281 unsigned long first
, last
;
283 first
= strtoul (p
, &p
, 10);
290 last
= strtoul (p
+ 1, &p
, 10);
291 if (errno
|| last
< first
)
294 for (; first
<= last
; first
++)
295 if (CPU_ISSET_S (first
, gomp_cpuset_size
, copy
)
296 && gomp_affinity_add_cpus (pl
, first
, 1, 0,
299 CPU_CLR_S (first
, gomp_cpuset_size
, copy
);
307 gomp_places_list_len
++;
312 if (gomp_places_list_len
== 0)
315 gomp_error ("Error reading %s topology",
316 level
== 2 ? "core" : "socket");
317 free (gomp_places_list
);
318 gomp_places_list
= NULL
;
327 gomp_affinity_print_place (void *p
)
329 unsigned long i
, max
= 8 * gomp_cpuset_size
, len
;
330 cpu_set_t
*cpusetp
= (cpu_set_t
*) p
;
331 bool notfirst
= false;
333 for (i
= 0, len
= 0; i
< max
; i
++)
334 if (CPU_ISSET_S (i
, gomp_cpuset_size
, cpusetp
))
341 fprintf (stderr
, "%lu", i
);
348 fprintf (stderr
, ":%lu", len
);
352 fprintf (stderr
, ":%lu", len
);
357 #include "../posix/affinity.c"