(root)/
gcc-13.2.0/
libgomp/
affinity-fmt.c
       1  /* Copyright (C) 2018-2023 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)
      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
      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
      69  omp_set_affinity_format (const char *format)
      70  {
      71    gomp_set_affinity_format (format, strlen (format));
      72  }
      73  
      74  size_t
      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
      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
     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
     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
     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
     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
     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
     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
     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  }
     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
     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  }