1 /* Copyright (C) 2018-2021 Free Software Foundation, Inc.
2 Contributed by Jakub Jelinek <jakub@redhat.com>.
3
4 This file is part of the GNU Offloading and Multi Processing Library
5 (libgomp).
6
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.
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
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
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/>. */
25
26 #include "libgomp.h"
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #ifdef HAVE_INTTYPES_H
34 # include <inttypes.h> /* For PRIx64. */
35 #endif
36 #ifdef HAVE_UNAME
37 #include <sys/utsname.h>
38 #endif
39
40 bool
gomp_print_string(const char * str,size_t len)41 gomp_print_string (const char *str, size_t len)
42 {
43 return fwrite (str, 1, len, stderr) != len;
44 }
45
46 void
gomp_set_affinity_format(const char * format,size_t len)47 gomp_set_affinity_format (const char *format, size_t len)
48 {
49 if (len < gomp_affinity_format_len)
50 memcpy (gomp_affinity_format_var, format, len);
51 else
52 {
53 char *p;
54 if (gomp_affinity_format_len)
55 p = gomp_realloc (gomp_affinity_format_var, len + 1);
56 else
57 p = gomp_malloc (len + 1);
58 memcpy (p, format, len);
59 gomp_affinity_format_var = p;
60 gomp_affinity_format_len = len + 1;
61 }
62 gomp_affinity_format_var[len] = '\0';
63 }
64
65 void
omp_set_affinity_format(const char * format)66 omp_set_affinity_format (const char *format)
67 {
68 gomp_set_affinity_format (format, strlen (format));
69 }
70
71 size_t
omp_get_affinity_format(char * buffer,size_t size)72 omp_get_affinity_format (char *buffer, size_t size)
73 {
74 size_t len = strlen (gomp_affinity_format_var);
75 if (size)
76 {
77 if (len < size)
78 memcpy (buffer, gomp_affinity_format_var, len + 1);
79 else
80 {
81 memcpy (buffer, gomp_affinity_format_var, size - 1);
82 buffer[size - 1] = '\0';
83 }
84 }
85 return len;
86 }
87
88 void
gomp_display_string(char * buffer,size_t size,size_t * ret,const char * str,size_t len)89 gomp_display_string (char *buffer, size_t size, size_t *ret,
90 const char *str, size_t len)
91 {
92 size_t r = *ret;
93 if (size && r < size)
94 {
95 size_t l = len;
96 if (size - r < len)
97 l = size - r;
98 memcpy (buffer + r, str, l);
99 }
100 *ret += len;
101 if (__builtin_expect (r > *ret, 0))
102 gomp_fatal ("overflow in omp_capture_affinity");
103 }
104
105 static void
gomp_display_repeat(char * buffer,size_t size,size_t * ret,char c,size_t len)106 gomp_display_repeat (char *buffer, size_t size, size_t *ret,
107 char c, size_t len)
108 {
109 size_t r = *ret;
110 if (size && r < size)
111 {
112 size_t l = len;
113 if (size - r < len)
114 l = size - r;
115 memset (buffer + r, c, l);
116 }
117 *ret += len;
118 if (__builtin_expect (r > *ret, 0))
119 gomp_fatal ("overflow in omp_capture_affinity");
120 }
121
122 static void
gomp_display_num(char * buffer,size_t size,size_t * ret,bool zero,bool right,size_t sz,char * buf)123 gomp_display_num (char *buffer, size_t size, size_t *ret,
124 bool zero, bool right, size_t sz, char *buf)
125 {
126 size_t l = strlen (buf);
127 if (sz == (size_t) -1 || l >= sz)
128 {
129 gomp_display_string (buffer, size, ret, buf, l);
130 return;
131 }
132 if (zero)
133 {
134 if (buf[0] == '-')
135 gomp_display_string (buffer, size, ret, buf, 1);
136 else if (buf[0] == '0' && buf[1] == 'x')
137 gomp_display_string (buffer, size, ret, buf, 2);
138 gomp_display_repeat (buffer, size, ret, '0', sz - l);
139 if (buf[0] == '-')
140 gomp_display_string (buffer, size, ret, buf + 1, l - 1);
141 else if (buf[0] == '0' && buf[1] == 'x')
142 gomp_display_string (buffer, size, ret, buf + 2, l - 2);
143 else
144 gomp_display_string (buffer, size, ret, buf, l);
145 }
146 else if (right)
147 {
148 gomp_display_repeat (buffer, size, ret, ' ', sz - l);
149 gomp_display_string (buffer, size, ret, buf, l);
150 }
151 else
152 {
153 gomp_display_string (buffer, size, ret, buf, l);
154 gomp_display_repeat (buffer, size, ret, ' ', sz - l);
155 }
156 }
157
158 static void
gomp_display_int(char * buffer,size_t size,size_t * ret,bool zero,bool right,size_t sz,int num)159 gomp_display_int (char *buffer, size_t size, size_t *ret,
160 bool zero, bool right, size_t sz, int num)
161 {
162 char buf[3 * sizeof (int) + 2];
163 sprintf (buf, "%d", num);
164 gomp_display_num (buffer, size, ret, zero, right, sz, buf);
165 }
166
167 static void
gomp_display_string_len(char * buffer,size_t size,size_t * ret,bool right,size_t sz,char * str,size_t len)168 gomp_display_string_len (char *buffer, size_t size, size_t *ret,
169 bool right, size_t sz, char *str, size_t len)
170 {
171 if (sz == (size_t) -1 || len >= sz)
172 {
173 gomp_display_string (buffer, size, ret, str, len);
174 return;
175 }
176
177 if (right)
178 {
179 gomp_display_repeat (buffer, size, ret, ' ', sz - len);
180 gomp_display_string (buffer, size, ret, str, len);
181 }
182 else
183 {
184 gomp_display_string (buffer, size, ret, str, len);
185 gomp_display_repeat (buffer, size, ret, ' ', sz - len);
186 }
187 }
188
189 static void
gomp_display_hostname(char * buffer,size_t size,size_t * ret,bool right,size_t sz)190 gomp_display_hostname (char *buffer, size_t size, size_t *ret,
191 bool right, size_t sz)
192 {
193 #ifdef HAVE_GETHOSTNAME
194 {
195 char buf[256];
196 char *b = buf;
197 size_t len = 256;
198 do
199 {
200 b[len - 1] = '\0';
201 if (gethostname (b, len - 1) == 0)
202 {
203 size_t l = strlen (b);
204 if (l < len - 1)
205 {
206 gomp_display_string_len (buffer, size, ret,
207 right, sz, b, l);
208 if (b != buf)
209 free (b);
210 return;
211 }
212 }
213 if (len == 1048576)
214 break;
215 len = len * 2;
216 if (len == 512)
217 b = gomp_malloc (len);
218 else
219 b = gomp_realloc (b, len);
220 }
221 while (1);
222 if (b != buf)
223 free (b);
224 }
225 #endif
226 #ifdef HAVE_UNAME
227 {
228 struct utsname buf;
229 if (uname (&buf) == 0)
230 {
231 gomp_display_string_len (buffer, size, ret, right, sz,
232 buf.nodename, strlen (buf.nodename));
233 return;
234 }
235 }
236 #endif
237 gomp_display_string_len (buffer, size, ret, right, sz, "node", 4);
238 }
239
240 struct affinity_types_struct {
241 char long_str[18];
242 char long_len;
243 char short_c; };
244
245 static struct affinity_types_struct affinity_types[] =
246 {
247 #define AFFINITY_TYPE(l, s) \
248 { #l, sizeof (#l) - 1, s }
249 AFFINITY_TYPE (team_num, 't'),
250 AFFINITY_TYPE (num_teams, 'T'),
251 AFFINITY_TYPE (nesting_level, 'L'),
252 AFFINITY_TYPE (thread_num, 'n'),
253 AFFINITY_TYPE (num_threads, 'N'),
254 AFFINITY_TYPE (ancestor_tnum, 'a'),
255 AFFINITY_TYPE (host, 'H'),
256 AFFINITY_TYPE (process_id, 'P'),
257 AFFINITY_TYPE (native_thread_id, 'i'),
258 AFFINITY_TYPE (thread_affinity, 'A')
259 #undef AFFINITY_TYPE
260 };
261
262 size_t
gomp_display_affinity(char * buffer,size_t size,const char * format,gomp_thread_handle handle,struct gomp_team_state * ts,unsigned int place)263 gomp_display_affinity (char *buffer, size_t size,
264 const char *format, gomp_thread_handle handle,
265 struct gomp_team_state *ts, unsigned int place)
266 {
267 size_t ret = 0;
268 do
269 {
270 const char *p = strchr (format, '%');
271 bool zero = false;
272 bool right = false;
273 size_t sz = -1;
274 char c;
275 int val;
276 if (p == NULL)
277 p = strchr (format, '\0');
278 if (p != format)
279 gomp_display_string (buffer, size, &ret,
280 format, p - format);
281 if (*p == '\0')
282 break;
283 p++;
284 if (*p == '%')
285 {
286 gomp_display_string (buffer, size, &ret, "%", 1);
287 format = p + 1;
288 continue;
289 }
290 if (*p == '0')
291 {
292 zero = true;
293 p++;
294 if (*p != '.')
295 gomp_fatal ("leading zero not followed by dot in affinity format");
296 }
297 if (*p == '.')
298 {
299 right = true;
300 p++;
301 }
302 if (*p >= '1' && *p <= '9')
303 {
304 char *end;
305 sz = strtoul (p, &end, 10);
306 p = end;
307 }
308 else if (zero || right)
309 gomp_fatal ("leading zero or right justification in affinity format "
310 "requires size");
311 c = *p;
312 if (c == '{')
313 {
314 int i;
315 for (i = 0;
316 i < sizeof (affinity_types) / sizeof (affinity_types[0]); ++i)
317 if (strncmp (p + 1, affinity_types[i].long_str,
318 affinity_types[i].long_len) == 0
319 && p[affinity_types[i].long_len + 1] == '}')
320 {
321 c = affinity_types[i].short_c;
322 p += affinity_types[i].long_len + 1;
323 break;
324 }
325 if (c == '{')
326 {
327 char *q = strchr (p + 1, '}');
328 if (q)
329 gomp_fatal ("unsupported long type name '%.*s' in affinity "
330 "format", (int) (q - (p + 1)), p + 1);
331 else
332 gomp_fatal ("unterminated long type name '%s' in affinity "
333 "format", p + 1);
334 }
335 }
336 switch (c)
337 {
338 case 't':
339 val = omp_get_team_num ();
340 goto do_int;
341 case 'T':
342 val = omp_get_num_teams ();
343 goto do_int;
344 case 'L':
345 val = ts->level;
346 goto do_int;
347 case 'n':
348 val = ts->team_id;
349 goto do_int;
350 case 'N':
351 val = ts->team ? ts->team->nthreads : 1;
352 goto do_int;
353 case 'a':
354 val = ts->team ? ts->team->prev_ts.team_id : -1;
355 goto do_int;
356 case 'H':
357 gomp_display_hostname (buffer, size, &ret, right, sz);
358 break;
359 case 'P':
360 #ifdef HAVE_GETPID
361 val = getpid ();
362 #else
363 val = 0;
364 #endif
365 goto do_int;
366 case 'i':
367 #if defined(LIBGOMP_USE_PTHREADS) && defined(__GNUC__)
368 {
369 char buf[3 * (sizeof (handle) + sizeof (uintptr_t) + sizeof (int))
370 + 4];
371 /* This macro returns expr unmodified for integral or pointer
372 types and 0 for anything else (e.g. aggregates). */
373 #define gomp_nonaggregate(expr) \
374 __builtin_choose_expr (__builtin_classify_type (expr) == 1 \
375 || __builtin_classify_type (expr) == 5, expr, 0)
376 /* This macro returns expr unmodified for integral types,
377 (uintptr_t) (expr) for pointer types and 0 for anything else
378 (e.g. aggregates). */
379 #define gomp_integral(expr) \
380 __builtin_choose_expr (__builtin_classify_type (expr) == 5, \
381 (uintptr_t) gomp_nonaggregate (expr), \
382 gomp_nonaggregate (expr))
383
384 if (sizeof (gomp_integral (handle)) == sizeof (unsigned long))
385 sprintf (buf, "0x%lx", (unsigned long) gomp_integral (handle));
386 #if defined (HAVE_INTTYPES_H) && defined (PRIx64)
387 else if (sizeof (gomp_integral (handle)) == sizeof (uint64_t))
388 sprintf (buf, "0x%" PRIx64, (uint64_t) gomp_integral (handle));
389 #else
390 else if (sizeof (gomp_integral (handle))
391 == sizeof (unsigned long long))
392 sprintf (buf, "0x%llx",
393 (unsigned long long) gomp_integral (handle));
394 #endif
395 else
396 sprintf (buf, "0x%x", (unsigned int) gomp_integral (handle));
397 gomp_display_num (buffer, size, &ret, zero, right, sz, buf);
398 break;
399 }
400 #else
401 val = 0;
402 goto do_int;
403 #endif
404 case 'A':
405 if (sz == (size_t) -1)
406 gomp_display_affinity_place (buffer, size, &ret,
407 place - 1);
408 else if (right)
409 {
410 size_t len = 0;
411 gomp_display_affinity_place (NULL, 0, &len, place - 1);
412 if (len < sz)
413 gomp_display_repeat (buffer, size, &ret, ' ', sz - len);
414 gomp_display_affinity_place (buffer, size, &ret, place - 1);
415 }
416 else
417 {
418 size_t start = ret;
419 gomp_display_affinity_place (buffer, size, &ret, place - 1);
420 if (ret - start < sz)
421 gomp_display_repeat (buffer, size, &ret, ' ', sz - (ret - start));
422 }
423 break;
424 do_int:
425 gomp_display_int (buffer, size, &ret, zero, right, sz, val);
426 break;
427 default:
428 gomp_fatal ("unsupported type %c in affinity format", c);
429 }
430 format = p + 1;
431 }
432 while (1);
433 return ret;
434 }
435
436 size_t
omp_capture_affinity(char * buffer,size_t size,const char * format)437 omp_capture_affinity (char *buffer, size_t size, const char *format)
438 {
439 struct gomp_thread *thr = gomp_thread ();
440 size_t ret
441 = gomp_display_affinity (buffer, size,
442 format && *format
443 ? format : gomp_affinity_format_var,
444 gomp_thread_self (), &thr->ts, thr->place);
445 if (size)
446 {
447 if (ret >= size)
448 buffer[size - 1] = '\0';
449 else
450 buffer[ret] = '\0';
451 }
452 return ret;
453 }
ialias(omp_capture_affinity)454 ialias (omp_capture_affinity)
455
456 void
457 omp_display_affinity (const char *format)
458 {
459 char buf[512];
460 char *b;
461 size_t ret = ialias_call (omp_capture_affinity) (buf, sizeof buf, format);
462 if (ret < sizeof buf)
463 {
464 buf[ret] = '\n';
465 gomp_print_string (buf, ret + 1);
466 return;
467 }
468 b = gomp_malloc (ret + 1);
469 ialias_call (omp_capture_affinity) (b, ret + 1, format);
470 b[ret] = '\n';
471 gomp_print_string (b, ret + 1);
472 free (b);
473 }
474
475 void
gomp_display_affinity_thread(gomp_thread_handle handle,struct gomp_team_state * ts,unsigned int place)476 gomp_display_affinity_thread (gomp_thread_handle handle,
477 struct gomp_team_state *ts, unsigned int place)
478 {
479 char buf[512];
480 char *b;
481 size_t ret = gomp_display_affinity (buf, sizeof buf, gomp_affinity_format_var,
482 handle, ts, place);
483 if (ret < sizeof buf)
484 {
485 buf[ret] = '\n';
486 gomp_print_string (buf, ret + 1);
487 return;
488 }
489 b = gomp_malloc (ret + 1);
490 gomp_display_affinity (b, ret + 1, gomp_affinity_format_var,
491 handle, ts, place);
492 b[ret] = '\n';
493 gomp_print_string (b, ret + 1);
494 free (b);
495 }
496