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