re PR rtl-optimization/63191 (32-bit gcc uses excessive memory during dead store...
[official-gcc.git] / libgomp / config / linux / affinity.c
blobc5b2cb810063b0a7641165628d73754f2eb74897
1 /* Copyright (C) 2006-2017 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>
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)
46 #endif
48 void
49 gomp_init_affinity (void)
51 if (gomp_places_list == NULL)
53 if (!gomp_affinity_init_level (1, ULONG_MAX, true))
54 return;
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;
65 void
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]);
72 void **
73 gomp_affinity_alloc (unsigned long count, bool quiet)
75 unsigned long i;
76 void **ret;
77 char *p;
79 if (gomp_cpusetp == NULL)
81 if (!quiet)
82 gomp_error ("Could not get CPU affinity set");
83 return NULL;
86 ret = malloc (count * sizeof (void *) + count * gomp_cpuset_size);
87 if (ret == NULL)
89 if (!quiet)
90 gomp_error ("Out of memory trying to allocate places list");
91 return NULL;
94 p = (char *) (ret + count);
95 for (i = 0; i < count; i++, p += gomp_cpuset_size)
96 ret[i] = p;
97 return ret;
100 void
101 gomp_affinity_init_place (void *p)
103 cpu_set_t *cpusetp = (cpu_set_t *) p;
104 CPU_ZERO_S (gomp_cpuset_size, cpusetp);
107 bool
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;
113 for (;;)
115 if (num >= max)
117 if (!quiet)
118 gomp_error ("Logical CPU number %lu out of range", num);
119 return false;
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))
127 if (!quiet)
128 gomp_error ("Logical CPU number %lu+%ld out of range",
129 num, stride);
130 return false;
132 num += stride;
136 bool
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);
143 return false;
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);
148 return false;
150 CPU_CLR_S (num, gomp_cpuset_size, cpusetp);
151 return true;
154 bool
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);
169 return false;
171 CPU_SET_S (i + stride, gomp_cpuset_size, destp);
173 return true;
176 bool
177 gomp_affinity_same_place (void *p, void *q)
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
186 bool
187 gomp_affinity_finalize_place_list (bool quiet)
189 unsigned long i, j;
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;
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];
208 if (j == 0)
210 if (!quiet)
211 gomp_error ("None of the places contain usable logical CPUs");
212 return false;
214 else if (j < gomp_places_list_len)
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;
222 return true;
225 bool
226 gomp_affinity_init_level (int level, unsigned long count, bool quiet)
228 unsigned long i, max = 8 * gomp_cpuset_size;
230 if (gomp_cpusetp)
232 unsigned long maxcount
233 = gomp_cpuset_popcount (gomp_cpuset_size, gomp_cpusetp);
234 if (count > maxcount)
235 count = maxcount;
237 gomp_places_list = gomp_affinity_alloc (count, quiet);
238 gomp_places_list_len = 0;
239 if (gomp_places_list == NULL)
240 return false;
241 /* SMT (threads). */
242 if (level == 1)
244 for (i = 0; i < max && gomp_places_list_len < count; i++)
245 if (CPU_ISSET_S (i, gomp_cpuset_size, gomp_cpusetp))
247 gomp_affinity_init_place (gomp_places_list[gomp_places_list_len]);
248 gomp_affinity_add_cpus (gomp_places_list[gomp_places_list_len],
249 i, 1, 0, true);
250 ++gomp_places_list_len;
252 return true;
254 else
256 char name[sizeof ("/sys/devices/system/cpu/cpu/topology/"
257 "thread_siblings_list") + 3 * sizeof (unsigned long)];
258 size_t prefix_len = sizeof ("/sys/devices/system/cpu/cpu") - 1;
259 cpu_set_t *copy = gomp_alloca (gomp_cpuset_size);
260 FILE *f;
261 char *line = NULL;
262 size_t linelen = 0;
264 memcpy (name, "/sys/devices/system/cpu/cpu", prefix_len);
265 memcpy (copy, gomp_cpusetp, gomp_cpuset_size);
266 for (i = 0; i < max && gomp_places_list_len < count; i++)
267 if (CPU_ISSET_S (i, gomp_cpuset_size, copy))
269 sprintf (name + prefix_len, "%lu/topology/%s_siblings_list",
270 i, level == 2 ? "thread" : "core");
271 f = fopen (name, "r");
272 if (f != NULL)
274 if (getline (&line, &linelen, f) > 0)
276 char *p = line;
277 bool seen_i = false;
278 void *pl = gomp_places_list[gomp_places_list_len];
279 gomp_affinity_init_place (pl);
280 while (*p && *p != '\n')
282 unsigned long first, last;
283 errno = 0;
284 first = strtoul (p, &p, 10);
285 if (errno)
286 break;
287 last = first;
288 if (*p == '-')
290 errno = 0;
291 last = strtoul (p + 1, &p, 10);
292 if (errno || last < first)
293 break;
295 for (; first <= last; first++)
296 if (CPU_ISSET_S (first, gomp_cpuset_size, copy)
297 && gomp_affinity_add_cpus (pl, first, 1, 0,
298 true))
300 CPU_CLR_S (first, gomp_cpuset_size, copy);
301 if (first == i)
302 seen_i = true;
304 if (*p == ',')
305 ++p;
307 if (seen_i)
308 gomp_places_list_len++;
310 fclose (f);
313 if (gomp_places_list_len == 0)
315 if (!quiet)
316 gomp_error ("Error reading %s topology",
317 level == 2 ? "core" : "socket");
318 free (gomp_places_list);
319 gomp_places_list = NULL;
320 return false;
322 return true;
324 return false;
327 void
328 gomp_affinity_print_place (void *p)
330 unsigned long i, max = 8 * gomp_cpuset_size, len;
331 cpu_set_t *cpusetp = (cpu_set_t *) p;
332 bool notfirst = false;
334 for (i = 0, len = 0; i < max; i++)
335 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
337 if (len == 0)
339 if (notfirst)
340 fputc (',', stderr);
341 notfirst = true;
342 fprintf (stderr, "%lu", i);
344 ++len;
346 else
348 if (len > 1)
349 fprintf (stderr, ":%lu", len);
350 len = 0;
352 if (len > 1)
353 fprintf (stderr, ":%lu", len);
357 omp_get_place_num_procs (int place_num)
359 if (place_num < 0 || place_num >= gomp_places_list_len)
360 return 0;
362 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
363 return gomp_cpuset_popcount (gomp_cpuset_size, cpusetp);
366 void
367 omp_get_place_proc_ids (int place_num, int *ids)
369 if (place_num < 0 || place_num >= gomp_places_list_len)
370 return;
372 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
373 unsigned long i, max = 8 * gomp_cpuset_size;
374 for (i = 0; i < max; i++)
375 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
376 *ids++ = i;
379 void
380 gomp_get_place_proc_ids_8 (int place_num, int64_t *ids)
382 if (place_num < 0 || place_num >= gomp_places_list_len)
383 return;
385 cpu_set_t *cpusetp = (cpu_set_t *) gomp_places_list[place_num];
386 unsigned long i, max = 8 * gomp_cpuset_size;
387 for (i = 0; i < max; i++)
388 if (CPU_ISSET_S (i, gomp_cpuset_size, cpusetp))
389 *ids++ = i;
392 ialias(omp_get_place_num_procs)
393 ialias(omp_get_place_proc_ids)
395 #else
397 #include "../../affinity.c"
399 #endif