public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [gomp5] Implement omp_[sg]et_affinity_format, omp_{capture,display}_affinity, OMP_DISPLAY_AFFINITY and OMP_AFFINITY_FORMAT
@ 2018-05-23 14:59 Jakub Jelinek
  0 siblings, 0 replies; only message in thread
From: Jakub Jelinek @ 2018-05-23 14:59 UTC (permalink / raw)
  To: gcc-patches

Hi!

The following patch implements functions and env vars to query and display
affinity related information.

Tested on x86_64-linux, committed to gomp-5.0 branch.

2018-05-23  Jakub Jelinek  <jakub@redhat.com>

	* configure.ac (HAVE_UNAME, HAVE_GETHOSTNAME, HAVE_GETPID): Add
	new tests.
	* configure.tgt: Add -DUSING_INITIAL_EXEC_TLS to XCFLAGS for Linux.
	* Makefile.am (libgomp_la_SOURCES): Add affinity-fmt.c.
	* libgomp.map (OMP_5.0): Export omp_{capture,display}_affinity{,_},
	and omp_[gs]et_affinity_format{,_}.
	* libgomp.h (gomp_display_affinity_var, gomp_affinity_format_var,
	gomp_affinity_format_len): Declare.
	(GOMP_NEEDS_THREAD_HANDLE): Define if needed.
	(struct gomp_thread): Add handle field if GOMP_NEEDS_THREAD_HANDLE is
	defined.
	(gomp_display_affinity_place): Declare.
	(gomp_set_affinity_format, gomp_display_string): Likewise.
	(gomp_thread_handle): New typedef.
	(gomp_display_affinity, gomp_display_affinity_thread): Declare.
	(gomp_thread_self, gomp_thread_to_pthread_t): New inline functions.
	* affinity-fmt.c: New file.
	* affinity.c (gomp_display_affinity_place): New function.
	* config/linux/affinity.c (gomp_display_affinity_place): New function.
	* env.c (gomp_display_affinity_var, gomp_affinity_format_var,
	gomp_affinity_format_len): New variables.
	(handle_omp_display_env): Print OMP_DISPLAY_AFFINITY and
	OMP_AFFINITY_FORMAT.
	(initialize_env): Handle OMP_DISPLAY_AFFINITY and OMP_AFFINITY_FORMAT
	env vars.
	* fortran.c: Include stdio.h and string.h.
	(omp_set_affinity_format_, omp_get_affinity_format_,
	omp_display_affinity_, omp_capture_affinity_): New functions.
	* omp.h.in (omp_set_affinity_format, omp_get_affinity_format,
	omp_display_affinity, omp_capture_affinity): Declare.
	* omp_lib.f90.in (omp_set_affinity_format, omp_get_affinity_format,
	omp_display_affinity, omp_capture_affinity): Add new interfaces.
	* omp_lib.h.in (omp_set_affinity_format, omp_get_affinity_format,
	omp_display_affinity, omp_capture_affinity): New externs.
	* team.c (struct gomp_thread_start_data): Add handle field.
	(gomp_team_start): Handle OMP_DISPLAY_AFFINITY env var.
	* configure: Regenerated.
	* config.h.in: Regenerated.
	* Makefile.in: Regenerated.
	* testsuite/libgomp.c-c++-common/display-affinity-1.c: New test.
	* testsuite/libgomp.fortran/display-affinity-1.f90: New test.

--- libgomp/configure.ac.jj	2018-04-30 13:19:48.198834863 +0200
+++ libgomp/configure.ac	2018-05-22 14:15:24.425935883 +0200
@@ -266,6 +266,41 @@ if test $ac_cv_func_clock_gettime = no;
 	       [Define to 1 if you have the `clock_gettime' function.])])
 fi
 
+# Check for uname.
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+  [#include <string.h>
+   #include <stdlib.h>
+   #include <sys/utsname.h>],
+  [struct utsname buf;
+   volatile size_t len = 0;
+   if (!uname (buf))
+     len = strlen (buf.nodename);])],
+  AC_DEFINE(HAVE_UNAME, 1,
+[	Define if uname is supported and struct utsname has nodename field.]))
+
+# Check for gethostname.
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+  [#include <unistd.h>],
+  [
+changequote(,)dnl
+   char buf[256];
+   if (gethostname (buf, sizeof (buf) - 1) == 0)
+     buf[255] = '\0';
+changequote([,])dnl
+  ])],
+  AC_DEFINE(HAVE_GETHOSTNAME, 1,
+[	Define if gethostname is supported.]))
+
+# Check for getpid.
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+  [#include <unistd.h>],
+  [int pid = getpid ();])],
+  AC_DEFINE(HAVE_GETPID, 1,
+[	Define if getpid is supported.]))
+
 # See if we support thread-local storage.
 GCC_CHECK_TLS
 
--- libgomp/configure.tgt.jj	2017-05-04 15:04:53.677371383 +0200
+++ libgomp/configure.tgt	2018-05-23 14:34:01.875414884 +0200
@@ -18,7 +18,7 @@ if test $gcc_cv_have_tls = yes ; then
 	;;
 
     *-*-linux* | *-*-gnu*)
-	XCFLAGS="${XCFLAGS} -ftls-model=initial-exec"
+	XCFLAGS="${XCFLAGS} -ftls-model=initial-exec -DUSING_INITIAL_EXEC_TLS"
 	;;
 
     *-*-rtems*)
--- libgomp/Makefile.am.jj	2017-05-04 15:04:53.679371358 +0200
+++ libgomp/Makefile.am	2018-05-21 17:21:48.717963247 +0200
@@ -63,7 +63,8 @@ libgomp_la_SOURCES = alloc.c atomic.c ba
 	parallel.c sections.c single.c task.c team.c work.c lock.c mutex.c \
 	proc.c sem.c bar.c ptrlock.c time.c fortran.c affinity.c target.c \
 	splay-tree.c libgomp-plugin.c oacc-parallel.c oacc-host.c oacc-init.c \
-	oacc-mem.c oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c
+	oacc-mem.c oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c \
+	affinity-fmt.c
 
 include $(top_srcdir)/plugin/Makefrag.am
 
--- libgomp/libgomp.map.jj	2018-04-30 13:19:48.356834924 +0200
+++ libgomp/libgomp.map	2018-05-23 14:08:47.362850982 +0200
@@ -164,6 +164,18 @@ OMP_4.5 {
 	omp_target_disassociate_ptr;
 } OMP_4.0;
 
+OMP_5.0 {
+  global:
+	omp_capture_affinity;
+	omp_capture_affinity_;
+	omp_display_affinity;
+	omp_display_affinity_;
+	omp_get_affinity_format;
+	omp_get_affinity_format_;
+	omp_set_affinity_format;
+	omp_set_affinity_format_;
+} OMP_4.5;
+
 GOMP_1.0 {
   global:
 	GOMP_atomic_end;
--- libgomp/libgomp.h.jj	2018-04-30 13:21:05.440865896 +0200
+++ libgomp/libgomp.h	2018-05-23 16:20:40.149705792 +0200
@@ -365,6 +365,9 @@ extern void **gomp_places_list;
 extern unsigned long gomp_places_list_len;
 extern unsigned int gomp_num_teams_var;
 extern int gomp_debug_var;
+extern bool gomp_display_affinity_var;
+extern char *gomp_affinity_format_var;
+extern size_t gomp_affinity_format_len;
 extern int goacc_device_num;
 extern char *goacc_device_type;
 
@@ -613,6 +616,19 @@ struct gomp_thread
 
   /* User pthread thread pool */
   struct gomp_thread_pool *thread_pool;
+
+#if defined(LIBGOMP_USE_PTHREADS) \
+    && (!defined(HAVE_TLS) \
+	|| !defined(__GLIBC__) \
+	|| !defined(USING_INITIAL_EXEC_TLS))
+  /* pthread_t of the thread containing this gomp_thread.
+     On Linux when using initial-exec TLS,
+     (typeof (pthread_t)) gomp_thread () - pthread_self ()
+     is constant in all threads, so we can optimize and not
+     store it.  */
+#define GOMP_NEEDS_THREAD_HANDLE 1
+  pthread_t handle;
+#endif
 };
 
 
@@ -709,6 +725,24 @@ extern bool gomp_affinity_finalize_place
 extern bool gomp_affinity_init_level (int, unsigned long, bool);
 extern void gomp_affinity_print_place (void *);
 extern void gomp_get_place_proc_ids_8 (int, int64_t *);
+extern void gomp_display_affinity_place (char *, size_t, size_t *, int);
+
+/* affinity-fmt.c */
+
+extern void gomp_set_affinity_format (const char *, size_t);
+extern void gomp_display_string (char *, size_t, size_t *, const char *,
+				 size_t);
+#ifdef LIBGOMP_USE_PTHREADS
+typedef pthread_t gomp_thread_handle;
+#else
+typedef struct {} gomp_thread_handle;
+#endif
+extern size_t gomp_display_affinity (char *, size_t, const char *,
+				     gomp_thread_handle,
+				     struct gomp_team_state *, unsigned int);
+extern void gomp_display_affinity_thread (gomp_thread_handle,
+					  struct gomp_team_state *,
+					  unsigned int) __attribute__((cold));
 
 /* iter.c */
 
@@ -1131,4 +1165,42 @@ task_to_priority_node (enum priority_que
   return (struct priority_node *) ((char *) task
 				   + priority_queue_offset (type));
 }
+
+#ifdef LIBGOMP_USE_PTHREADS
+static inline gomp_thread_handle
+gomp_thread_self (void)
+{
+  return pthread_self ();
+}
+
+static inline gomp_thread_handle
+gomp_thread_to_pthread_t (struct gomp_thread *thr)
+{
+  struct gomp_thread *this_thr = gomp_thread ();
+  if (thr == this_thr)
+    return pthread_self ();
+#ifdef GOMP_NEEDS_THREAD_HANDLE
+  return thr->handle;
+#else
+  /* On Linux with initial-exec TLS, the pthread_t of the thread containing
+     thr can be computed from thr, this_thr and pthread_self (),
+     as the distance between this_thr and pthread_self () is constant.  */
+  return pthread_self () + ((uintptr_t) thr - (uintptr_t) this_thr);
+#endif
+}
+#else
+static inline gomp_thread_handle
+gomp_thread_self (void)
+{
+  return (gomp_thread_handle) {};
+}
+
+static inline gomp_thread_handle
+gomp_thread_to_pthread_t (struct gomp_thread *thr)
+{
+  (void) thr;
+  return gomp_thread_self ();
+}
+#endif
+
 #endif /* LIBGOMP_H */
--- libgomp/affinity-fmt.c.jj	2018-05-21 17:29:19.988327335 +0200
+++ libgomp/affinity-fmt.c	2018-05-23 16:22:32.610813049 +0200
@@ -0,0 +1,473 @@
+/* Copyright (C) 2018 Free Software Foundation, Inc.
+   Contributed by Jakub Jelinek <jakub@redhat.com>.
+
+   This file is part of the GNU Offloading and Multi Processing Library
+   (libgomp).
+
+   Libgomp is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+   more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "libgomp.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_UNAME
+#include <sys/utsname.h>
+#endif
+
+void
+gomp_set_affinity_format (const char *format, size_t len)
+{
+  if (len < gomp_affinity_format_len)
+    memcpy (gomp_affinity_format_var, format, len);
+  else
+    {
+      char *p;
+      if (gomp_affinity_format_len)
+	p = gomp_realloc (gomp_affinity_format_var, len + 1);
+      else
+	p = gomp_malloc (len + 1);
+      memcpy (p, format, len);
+      gomp_affinity_format_var = p;
+      gomp_affinity_format_len = len + 1;
+    }
+  gomp_affinity_format_var[len] = '\0';
+}
+
+void
+omp_set_affinity_format (const char *format)
+{
+  gomp_set_affinity_format (format, strlen (format));
+}
+
+size_t
+omp_get_affinity_format (char *buffer, size_t size)
+{
+  size_t len = strlen (gomp_affinity_format_var);
+  if (size)
+    {
+      if (len < size)
+	memcpy (buffer, gomp_affinity_format_var, len + 1);
+      else
+	{
+	  memcpy (buffer, gomp_affinity_format_var, size - 1);
+	  buffer[size - 1] = '\0';
+	}
+    }
+  return len;
+}
+
+void
+gomp_display_string (char *buffer, size_t size, size_t *ret,
+		     const char *str, size_t len)
+{
+  size_t r = *ret;
+  if (size && r < size)
+    {
+      size_t l = len;
+      if (size - r < len)
+	l = size - r;
+      memcpy (buffer + r, str, l);
+    }
+  *ret += len;
+  if (__builtin_expect (r > *ret, 0))
+    gomp_fatal ("overflow in omp_capture_affinity");
+}
+
+static void
+gomp_display_repeat (char *buffer, size_t size, size_t *ret,
+		     char c, size_t len)
+{
+  size_t r = *ret;
+  if (size && r < size)
+    {
+      size_t l = len;
+      if (size - r < len)
+	l = size - r;
+      memset (buffer + r, c, l);
+    }
+  *ret += len;
+  if (__builtin_expect (r > *ret, 0))
+    gomp_fatal ("overflow in omp_capture_affinity");
+}
+
+static void
+gomp_display_num (char *buffer, size_t size, size_t *ret,
+		  bool zero, bool right, size_t sz, char *buf)
+{
+  size_t l = strlen (buf);
+  if (sz == (size_t) -1 || l >= sz)
+    {
+      gomp_display_string (buffer, size, ret, buf, l);
+      return;
+    }
+  if (zero)
+    {
+      if (buf[0] == '-')
+	gomp_display_string (buffer, size, ret, buf, 1);
+      else if (buf[0] == '0' && buf[1] == 'x')
+	gomp_display_string (buffer, size, ret, buf, 2);
+      gomp_display_repeat (buffer, size, ret, '0', sz - l);
+      if (buf[0] == '-')
+	gomp_display_string (buffer, size, ret, buf + 1, l - 1);
+      else if (buf[0] == '0' && buf[1] == 'x')
+	gomp_display_string (buffer, size, ret, buf + 2, l - 2);
+      else
+	gomp_display_string (buffer, size, ret, buf, l);
+    }
+  else if (right)
+    {
+      gomp_display_repeat (buffer, size, ret, ' ', sz - l);
+      gomp_display_string (buffer, size, ret, buf, l);
+    }
+  else
+    {
+      gomp_display_string (buffer, size, ret, buf, l);
+      gomp_display_repeat (buffer, size, ret, ' ', sz - l);
+    }
+}
+
+static void
+gomp_display_int (char *buffer, size_t size, size_t *ret,
+		  bool zero, bool right, size_t sz, int num)
+{
+  char buf[3 * sizeof (int) + 2];
+  sprintf (buf, "%d", num);
+  gomp_display_num (buffer, size, ret, zero, right, sz, buf);
+}
+
+static void
+gomp_display_string_len (char *buffer, size_t size, size_t *ret,
+			 bool right, size_t sz, char *str, size_t len)
+{
+  if (sz == (size_t) -1 || len >= sz)
+    {
+      gomp_display_string (buffer, size, ret, str, len);
+      return;
+    }
+
+  if (right)
+    {
+      gomp_display_repeat (buffer, size, ret, ' ', sz - len);
+      gomp_display_string (buffer, size, ret, str, len);
+    }
+  else
+    {
+      gomp_display_string (buffer, size, ret, str, len);
+      gomp_display_repeat (buffer, size, ret, ' ', sz - len);
+    }
+}
+
+static void
+gomp_display_hostname (char *buffer, size_t size, size_t *ret,
+		       bool right, size_t sz)
+{
+#ifdef HAVE_GETHOSTNAME
+  {
+    char buf[256];
+    char *b = buf;
+    size_t len = 256;
+    do
+      {
+	b[len - 1] = '\0';
+	if (gethostname (b, len - 1) == 0)
+	  {
+	    size_t l = strlen (b);
+	    if (l < len - 1)
+	      {
+		gomp_display_string_len (buffer, size, ret,
+					 right, sz, b, l);
+		if (b != buf)
+		  free (b);
+		return;
+	      }
+	  }
+	if (len == 1048576)
+	  break;
+	len = len * 2;
+	if (len == 512)
+	  b = gomp_malloc (len);
+	else
+	  b = gomp_realloc (b, len);
+      }
+    while (1);
+    if (b != buf)
+      free (b);
+  }
+#endif
+#ifdef HAVE_UNAME
+  {
+    struct utsname buf;
+    if (uname (&buf) == 0)
+      {
+	gomp_display_string_len (buffer, size, ret, right, sz,
+				 buf.nodename, strlen (buf.nodename));
+	return;
+      }
+  }
+#endif
+  gomp_display_string_len (buffer, size, ret, right, sz, "node", 4);
+}
+
+struct affinity_types_struct {
+  char long_str[18];
+  char long_len;
+  char short_c; };
+
+static struct affinity_types_struct affinity_types[] =
+{
+#define AFFINITY_TYPE(l, s) \
+  { #l, sizeof (#l) - 1, s }
+  AFFINITY_TYPE (thread_level, 'L'),
+  AFFINITY_TYPE (thread_num, 'n'),
+  AFFINITY_TYPE (host, 'h'),
+  AFFINITY_TYPE (process_id, 'P'),
+  AFFINITY_TYPE (thread_identifier, 'T'),
+  AFFINITY_TYPE (num_threads, 'N'),
+  AFFINITY_TYPE (ancestor_tnum, 'A'),
+  AFFINITY_TYPE (thread_affinity, 'a')
+#undef AFFINITY_TYPE
+};
+
+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)
+{
+  size_t ret = 0;
+  do
+    {
+      const char *p = strchr (format, '%');
+      bool zero = false;
+      bool right = false;
+      size_t sz = -1;
+      char c;
+      int val;
+      if (p == NULL)
+	p = strchr (format, '\0');
+      if (p != format)
+	gomp_display_string (buffer, size, &ret,
+			     format, p - format);
+      if (*p == '\0')
+	break;
+      p++;
+      if (*p == '%')
+	{
+	  gomp_display_string (buffer, size, &ret, "%", 1);
+	  format = p + 1;
+	  continue;
+	}
+      if (*p == '0')
+	{
+	  zero = true;
+	  p++;
+	  if (*p != '.')
+	    gomp_fatal ("leading zero not followed by dot in affinity format");
+	}
+      if (*p == '.')
+	{
+	  right = true;
+	  p++;
+	}
+      if (*p >= '1' && *p <= '9')
+	{
+	  char *end;
+	  sz = strtoul (p, &end, 10);
+	  p = end;
+	}
+      else if (zero || right)
+	gomp_fatal ("leading zero or right justification in affinity format "
+		    "requires size");
+      c = *p;
+      if (c == '{')
+	{
+	  int i;
+	  for (i = 0;
+	       i < sizeof (affinity_types) / sizeof (affinity_types[0]); ++i)
+	    if (strncmp (p + 1, affinity_types[i].long_str,
+			 affinity_types[i].long_len) == 0
+		&& p[affinity_types[i].long_len + 1] == '}')
+	      {
+		c = affinity_types[i].short_c;
+		p += affinity_types[i].long_len + 1;
+		break;
+	      }
+	  if (c == '{')
+	    {
+	      char *q = strchr (p + 1, '}');
+	      if (q)
+		gomp_fatal ("unsupported long type name '%.*s' in affinity "
+			    "format", (int) (q - (p + 1)), p + 1);
+	      else
+		gomp_fatal ("unterminated long type name '%s' in affinity "
+			    "format", p + 1);
+	    }
+	}
+      switch (c)
+	{
+	case 'L':
+	  val = ts->level;
+	  goto do_int;
+	case 'n':
+	  val = ts->team_id;
+	  goto do_int;
+	case 'h':
+	  gomp_display_hostname (buffer, size, &ret, right, sz);
+	  break;
+	case 'P':
+#ifdef HAVE_GETPID
+	  val = getpid ();
+#else
+	  val = 0;
+#endif
+	  goto do_int;
+	case 'T':
+#if defined(LIBGOMP_USE_PTHREADS) && defined(__GNUC__)
+	  /* Handle integral pthread_t.  */
+	  if (__builtin_classify_type (handle) == 1)
+	    {
+	      char buf[3 * (sizeof (handle) + sizeof (int)) + 4];
+
+	      if (sizeof (handle) == sizeof (long))
+		sprintf (buf, "0x%lx", (long) handle);
+	      else if (sizeof (handle) == sizeof (long long))
+		sprintf (buf, "0x%llx", (long long) handle);
+	      else
+		sprintf (buf, "0x%x", (int) handle);
+	      gomp_display_num (buffer, size, &ret, zero, right, sz, buf);
+	      break;
+	    }
+	  /* And pointer pthread_t.  */
+	  else if (__builtin_classify_type (handle) == 5)
+	    {
+	      char buf[3 * (sizeof (uintptr_t) + sizeof (int)) + 4];
+
+	      if (sizeof (uintptr_t) == sizeof (long))
+		sprintf (buf, "0x%lx", (long) (uintptr_t) handle);
+	      else if (sizeof (uintptr_t) == sizeof (long long))
+		sprintf (buf, "0x%llx", (long long) (uintptr_t) handle);
+	      else
+		sprintf (buf, "0x%x", (int) (uintptr_t) handle);
+	      gomp_display_num (buffer, size, &ret, zero, right, sz, buf);
+	      break;
+	    }
+#endif
+	  val = 0;
+	  goto do_int;
+	case 'N':
+	  val = ts->team ? ts->team->nthreads : 1;
+	  goto do_int;
+	case 'A':
+	  val = ts->team ? ts->team->prev_ts.team_id : -1;
+	  goto do_int;
+	case 'a':
+	  if (sz == (size_t) -1)
+	    gomp_display_affinity_place (buffer, size, &ret,
+					 place - 1);
+	  else if (right)
+	    {
+	      size_t len = 0;
+	      gomp_display_affinity_place (NULL, 0, &len, place - 1);
+	      if (len < sz)
+		gomp_display_repeat (buffer, size, &ret, ' ', sz - len);
+	      gomp_display_affinity_place (buffer, size, &ret, place - 1);
+	    }
+	  else
+	    {
+	      size_t start = ret;
+	      gomp_display_affinity_place (buffer, size, &ret, place - 1);
+	      if (ret - start < sz)
+		gomp_display_repeat (buffer, size, &ret, ' ', sz - (ret - start));
+	    }
+	  break;
+	do_int:
+	  gomp_display_int (buffer, size, &ret, zero, right, sz, val);
+	  break;
+	default:
+	  gomp_fatal ("unsupported type %c in affinity format", c);
+	}
+      format = p + 1;
+    }
+  while (1);
+  return ret;
+}
+
+size_t
+omp_capture_affinity (char *buffer, size_t size, const char *format)
+{
+  struct gomp_thread *thr = gomp_thread ();
+  size_t ret
+    = gomp_display_affinity (buffer, size,
+			     format && *format
+			     ? format : gomp_affinity_format_var,
+			     gomp_thread_self (), &thr->ts, thr->place);
+  if (size)
+    {
+      if (ret >= size)
+	buffer[size - 1] = '\0';
+      else
+	buffer[ret] = '\0';
+    }
+  return ret;
+}
+ialias (omp_capture_affinity)
+
+void
+omp_display_affinity (const char *format)
+{
+  char buf[512];
+  char *b;
+  size_t ret = ialias_call (omp_capture_affinity) (buf, sizeof buf, format);
+  if (ret < sizeof buf)
+    {
+      buf[ret] = '\n';
+      fwrite (buf, 1, ret + 1, stderr);
+      return;
+    }
+  b = gomp_malloc (ret + 1);
+  ialias_call (omp_capture_affinity) (b, ret + 1, format);
+  b[ret] = '\n';
+  fwrite (b, 1, ret + 1, stderr);
+  free (b);
+}
+
+void
+gomp_display_affinity_thread (gomp_thread_handle handle,
+			      struct gomp_team_state *ts, unsigned int place)
+{
+  char buf[512];
+  char *b;
+  size_t ret = gomp_display_affinity (buf, sizeof buf, gomp_affinity_format_var,
+				      handle, ts, place);
+  if (ret < sizeof buf)
+    {
+      buf[ret] = '\n';
+      fwrite (buf, 1, ret + 1, stderr);
+      return;
+    }
+  b = gomp_malloc (ret + 1);
+  gomp_display_affinity (b, ret + 1, gomp_affinity_format_var,
+  			 handle, ts, place);
+  b[ret] = '\n';
+  fwrite (b, 1, ret + 1, stderr);
+  free (b);
+}
--- libgomp/affinity.c.jj	2018-04-30 13:21:02.853864869 +0200
+++ libgomp/affinity.c	2018-05-23 11:37:46.299744109 +0200
@@ -138,5 +138,18 @@ gomp_get_place_proc_ids_8 (int place_num
   (void) ids;
 }
 
+void
+gomp_display_affinity_place (char *buffer, size_t size, size_t *ret,
+			     int place)
+{
+  cpu_set_t *cpusetp;
+  char buf[sizeof (long) * 3 + 4];
+  if (gomp_available_cpus > 1)
+    sprintf (buf, "0-%lu", gomp_available_cpus - 1);
+  else
+    strcpy (buf, "0");
+  gomp_display_string (buffer, size, ret, buf, strlen (buf));
+}
+
 ialias(omp_get_place_num_procs)
 ialias(omp_get_place_proc_ids)
--- libgomp/config/linux/affinity.c.jj	2018-04-30 13:20:51.454860277 +0200
+++ libgomp/config/linux/affinity.c	2018-05-23 11:24:14.809081402 +0200
@@ -396,6 +396,56 @@ gomp_get_place_proc_ids_8 (int place_num
       *ids++ = i;
 }
 
+void
+gomp_display_affinity_place (char *buffer, size_t size, size_t *ret,
+			     int place)
+{
+  cpu_set_t *cpusetp;
+  char buf[sizeof (long) * 3 + 4];
+  if (place >= 0 && place < gomp_places_list_len)
+    cpusetp = (cpu_set_t *) gomp_places_list[place];
+  else if (gomp_cpusetp)
+    cpusetp = gomp_cpusetp;
+  else
+    {
+      if (gomp_available_cpus > 1)
+	sprintf (buf, "0-%lu", gomp_available_cpus - 1);
+      else
+	strcpy (buf, "0");
+      gomp_display_string (buffer, size, ret, buf, strlen (buf));
+      return;
+    }
+
+  unsigned long i, max = 8 * gomp_cpuset_size, start;
+  bool prev_set = false;
+  start = max;
+  for (i = 0; i <= max; i++)
+    {
+      bool this_set;
+      if (i == max)
+	this_set = false;
+      else
+	this_set = CPU_ISSET_S (i, gomp_cpuset_size, cpusetp);
+      if (this_set != prev_set)
+	{
+	  prev_set = this_set;
+	  if (this_set)
+	    {
+	      char *p = buf;
+	      if (start != max)
+		*p++ = ',';
+	      sprintf (p, "%lu", i);
+	      start = i;
+	    }
+	  else if (i == start + 1)
+	    continue;
+	  else
+	    sprintf (buf, "-%lu", i - 1);
+	  gomp_display_string (buffer, size, ret, buf, strlen (buf));
+	}
+    }
+}
+
 ialias(omp_get_place_num_procs)
 ialias(omp_get_place_proc_ids)
 
--- libgomp/env.c.jj	2018-04-30 13:21:04.806865641 +0200
+++ libgomp/env.c	2018-05-23 12:38:58.023091979 +0200
@@ -88,6 +88,9 @@ void **gomp_places_list;
 unsigned long gomp_places_list_len;
 int gomp_debug_var;
 unsigned int gomp_num_teams_var;
+bool gomp_display_affinity_var;
+char *gomp_affinity_format_var = "level %L thread %T affinity %a";
+size_t gomp_affinity_format_len;
 char *goacc_device_type;
 int goacc_device_num;
 
@@ -1197,6 +1200,10 @@ handle_omp_display_env (unsigned long st
 	   gomp_global_icv.default_device_var);
   fprintf (stderr, "  OMP_MAX_TASK_PRIORITY = '%d'\n",
 	   gomp_max_task_priority_var);
+  fprintf (stderr, "  OMP_DISPLAY_AFFINITY = '%s'\n",
+	   gomp_display_affinity_var ? "TRUE" : "FALSE");
+  fprintf (stderr, "  OMP_AFFINITY_FORMAT = '%s'\n",
+	   gomp_affinity_format_var);
 
   if (verbose)
     {
@@ -1228,6 +1235,7 @@ initialize_env (void)
   parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
   parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
   parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
+  parse_boolean ("OMP_DISPLAY_AFFINITY", &gomp_display_affinity_var);
   parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
   parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
   parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
@@ -1277,6 +1285,13 @@ initialize_env (void)
     }
   if (gomp_global_icv.bind_var != omp_proc_bind_false)
     gomp_init_affinity ();
+
+  {
+    const char *env = getenv ("OMP_AFFINITY_FORMAT");
+    if (env != NULL)
+      gomp_set_affinity_format (env, strlen (env));
+  }
+
   wait_policy = parse_wait_policy ();
   if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
     {
--- libgomp/fortran.c.jj	2018-04-30 13:21:03.011864928 +0200
+++ libgomp/fortran.c	2018-05-23 16:15:31.826411733 +0200
@@ -28,6 +28,8 @@
 #include "libgomp.h"
 #include "libgomp_f.h"
 #include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
 #include <limits.h>
 
 #ifdef HAVE_ATTRIBUTE_ALIAS
@@ -576,3 +578,84 @@ omp_get_max_task_priority_ (void)
 {
   return omp_get_max_task_priority ();
 }
+
+void
+omp_set_affinity_format_ (const char *format, size_t format_len)
+{
+  gomp_set_affinity_format (format, format_len);
+}
+
+int32_t
+omp_get_affinity_format_ (char *buffer, size_t buffer_len)
+{
+  size_t len = strlen (gomp_affinity_format_var);
+  if (buffer_len)
+    {
+      if (len < buffer_len)
+	{
+	  memcpy (buffer, gomp_affinity_format_var, len);
+	  memset (buffer + len, ' ', buffer_len - len);
+	}
+      else
+	memcpy (buffer, gomp_affinity_format_var, buffer_len);
+    }
+  return len;
+}
+
+void
+omp_display_affinity_ (const char *format, size_t format_len)
+{
+  char *fmt = NULL, fmt_buf[256];
+  char buf[512];
+  if (format_len)
+    {
+      fmt = format_len < 256 ? fmt_buf : gomp_malloc (format_len + 1);
+      memcpy (fmt, format, format_len);
+      fmt[format_len] = '\0';
+    }
+  struct gomp_thread *thr = gomp_thread ();
+  size_t ret
+    = gomp_display_affinity (buf, sizeof buf,
+			     format_len ? fmt : gomp_affinity_format_var,
+			     gomp_thread_self (), &thr->ts, thr->place);
+  if (ret < sizeof buf)
+    {
+      buf[ret] = '\n';
+      fwrite (buf, 1, ret + 1, stderr);
+    }
+  else
+    {
+      char *b = gomp_malloc (ret + 1);
+      gomp_display_affinity (buf, sizeof buf,
+			     format_len ? fmt : gomp_affinity_format_var,
+			     gomp_thread_self (), &thr->ts, thr->place);
+      b[ret] = '\n';
+      fwrite (b, 1, ret + 1, stderr);
+      free (b);
+    }
+  if (fmt && fmt != fmt_buf)
+    free (fmt);
+}
+
+int32_t
+omp_capture_affinity_ (char *buffer, const char *format,
+		       size_t buffer_len, size_t format_len)
+{
+  char *fmt = NULL, fmt_buf[256];
+  if (format_len)
+    {
+      fmt = format_len < 256 ? fmt_buf : gomp_malloc (format_len + 1);
+      memcpy (fmt, format, format_len);
+      fmt[format_len] = '\0';
+    }
+  struct gomp_thread *thr = gomp_thread ();
+  size_t ret
+    = gomp_display_affinity (buffer, buffer_len,
+			     format_len ? fmt : gomp_affinity_format_var,
+			     gomp_thread_self (), &thr->ts, thr->place);
+  if (fmt && fmt != fmt_buf)
+    free (fmt);
+  if (ret < buffer_len)
+    memset (buffer + ret, ' ', buffer_len - ret);
+  return ret;
+}
--- libgomp/omp.h.in.jj	2018-05-04 12:31:28.863633774 +0200
+++ libgomp/omp.h.in	2018-05-21 15:54:08.496902995 +0200
@@ -166,6 +166,13 @@ extern int omp_target_associate_ptr (con
 				     __SIZE_TYPE__, int) __GOMP_NOTHROW;
 extern int omp_target_disassociate_ptr (const void *, int) __GOMP_NOTHROW;
 
+extern void omp_set_affinity_format (const char *) __GOMP_NOTHROW;
+extern __SIZE_TYPE__ omp_get_affinity_format (char *, __SIZE_TYPE__)
+  __GOMP_NOTHROW;
+extern void omp_display_affinity (const char *) __GOMP_NOTHROW;
+extern __SIZE_TYPE__ omp_capture_affinity (char *, __SIZE_TYPE__, const char *)
+  __GOMP_NOTHROW;
+
 #ifdef __cplusplus
 }
 #endif
--- libgomp/omp_lib.f90.in.jj	2018-04-30 13:19:49.305835311 +0200
+++ libgomp/omp_lib.f90.in	2018-05-23 13:14:15.873893636 +0200
@@ -433,4 +433,31 @@
           end function omp_get_max_task_priority
         end interface
 
+        interface
+          subroutine omp_set_affinity_format (format)
+            character(len=*), intent(in) :: format
+          end subroutine omp_set_affinity_format
+        end interface
+
+        interface
+          function omp_get_affinity_format (buffer)
+            integer (4) :: omp_get_affinity_format
+            character(len=*), intent(out) :: buffer
+          end function omp_get_affinity_format
+        end interface
+
+        interface
+          subroutine omp_display_affinity (format)
+            character(len=*), intent(in) :: format
+          end subroutine omp_display_affinity
+        end interface
+
+        interface
+          function omp_capture_affinity (buffer, format)
+            integer (4) :: omp_capture_affinity
+            character(len=*), intent(out) :: buffer
+            character(len=*), intent(in) :: format
+          end function omp_capture_affinity
+        end interface
+
       end module omp_lib
--- libgomp/omp_lib.h.in.jj	2018-04-30 13:21:07.207866607 +0200
+++ libgomp/omp_lib.h.in	2018-05-23 13:21:07.605241351 +0200
@@ -126,3 +126,8 @@
 
       external omp_get_max_task_priority
       integer(4) omp_get_max_task_priority
+
+      external omp_set_affinity_format, omp_get_affinity_format
+      external omp_display_affinity, omp_capture_affinity
+      integer(4) omp_get_affinity_format
+      integer(4) omp_capture_affinity
--- libgomp/team.c.jj	2018-04-30 13:19:48.674835063 +0200
+++ libgomp/team.c	2018-05-23 16:45:09.478108168 +0200
@@ -58,6 +58,7 @@ struct gomp_thread_start_data
   struct gomp_thread_pool *thread_pool;
   unsigned int place;
   bool nested;
+  pthread_t handle;
 };
 
 
@@ -89,6 +90,9 @@ gomp_thread_start (void *xdata)
   thr->ts = data->ts;
   thr->task = data->task;
   thr->place = data->place;
+#ifdef GOMP_NEEDS_THREAD_HANDLE
+  thr->handle = data->handle;
+#endif
 
   thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
 
@@ -312,6 +316,7 @@ gomp_team_start (void (*fn) (void *), vo
   unsigned int s = 0, rest = 0, p = 0, k = 0;
   unsigned int affinity_count = 0;
   struct gomp_thread **affinity_thr = NULL;
+  bool force_display = false;
 
   thr = gomp_thread ();
   nested = thr->ts.level;
@@ -319,7 +324,12 @@ gomp_team_start (void (*fn) (void *), vo
   task = thr->task;
   icv = task ? &task->icv : &gomp_global_icv;
   if (__builtin_expect (gomp_places_list != NULL, 0) && thr->place == 0)
-    gomp_init_affinity ();
+    {
+      gomp_init_affinity ();
+      if (__builtin_expect (gomp_display_affinity_var, 0) && nthreads == 1)
+	gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
+				      thr->place);
+    }
 
   /* Always save the previous state, even if this isn't a nested team.
      In particular, we should save any work share state from an outer
@@ -338,6 +348,9 @@ gomp_team_start (void (*fn) (void *), vo
 #endif
   thr->ts.static_trip = 0;
   thr->task = &team->implicit_task[0];
+#ifdef GOMP_NEEDS_THREAD_HANDLE
+  thr->handle = pthread_self ();
+#endif
   nthreads_var = icv->nthreads_var;
   if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
       && thr->ts.level < gomp_nthreads_var_list_len)
@@ -465,7 +478,7 @@ gomp_team_start (void (*fn) (void *), vo
 	  pool->threads
 	    = gomp_realloc (pool->threads,
 			    pool->threads_size
-			    * sizeof (struct gomp_thread_data *));
+			    * sizeof (struct gomp_thread *));
 	}
 
       /* Release existing idle threads.  */
@@ -540,6 +553,7 @@ gomp_team_start (void (*fn) (void *), vo
 						+ place_partition_len))
 		{
 		  unsigned int l;
+		  force_display = true;
 		  if (affinity_thr == NULL)
 		    {
 		      unsigned int j;
@@ -719,12 +733,11 @@ gomp_team_start (void (*fn) (void *), vo
     }
 
   start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
-			    * (nthreads-i));
+			    * (nthreads - i));
 
   /* Launch new threads.  */
   for (; i < nthreads; ++i)
     {
-      pthread_t pt;
       int err;
 
       start_data->ts.place_partition_off = thr->ts.place_partition_off;
@@ -814,7 +827,9 @@ gomp_team_start (void (*fn) (void *), vo
       start_data->nested = nested;
 
       attr = gomp_adjust_thread_attr (attr, &thread_attr);
-      err = pthread_create (&pt, attr, gomp_thread_start, start_data++);
+      err = pthread_create (&start_data->handle, attr, gomp_thread_start,
+			    start_data);
+      start_data++;
       if (err != 0)
 	gomp_fatal ("Thread creation failed: %s", strerror (err));
     }
@@ -854,6 +869,42 @@ gomp_team_start (void (*fn) (void *), vo
       gomp_mutex_unlock (&gomp_managed_threads_lock);
 #endif
     }
+  if (__builtin_expect (gomp_display_affinity_var, 0))
+    {
+      if (nested
+	  || nthreads != old_threads_used
+	  || force_display)
+	{
+	  gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
+					thr->place);
+	  if (nested)
+	    {
+	      start_data -= nthreads - 1;
+	      for (i = 1; i < nthreads; ++i)
+		{
+		  gomp_display_affinity_thread (
+#ifdef LIBGOMP_USE_PTHREADS
+						start_data->handle,
+#else
+						gomp_thread_self (),
+#endif
+						&start_data->ts,
+						start_data->place);
+		  start_data++;
+		}
+	    }
+	  else
+	    {
+	      for (i = 1; i < nthreads; ++i)
+		{
+		  gomp_thread_handle handle
+		    = gomp_thread_to_pthread_t (pool->threads[i]);
+		  gomp_display_affinity_thread (handle, &pool->threads[i]->ts,
+						pool->threads[i]->place);
+		}
+	    }
+	}
+    }
   if (__builtin_expect (affinity_thr != NULL, 0)
       && team->prev_ts.place_partition_len > 64)
     free (affinity_thr);
--- libgomp/configure.jj	2018-04-30 13:21:02.531864728 +0200
+++ libgomp/configure	2018-05-22 14:16:34.830984930 +0200
@@ -15784,6 +15784,72 @@ fi
 
 fi
 
+# Check for uname.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+   #include <stdlib.h>
+   #include <sys/utsname.h>
+int
+main ()
+{
+struct utsname buf;
+   volatile size_t len = 0;
+   if (!uname (buf))
+     len = strlen (buf.nodename);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_UNAME 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# Check for gethostname.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+
+   char buf[256];
+   if (gethostname (buf, sizeof (buf) - 1) == 0)
+     buf[255] = '\0';
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_GETHOSTNAME 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# Check for getpid.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+int pid = getpid ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+$as_echo "#define HAVE_GETPID 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
 # See if we support thread-local storage.
 
 
--- libgomp/config.h.in.jj	2017-05-04 15:04:53.606372292 +0200
+++ libgomp/config.h.in	2018-05-22 14:16:32.000000000 +0200
@@ -33,9 +33,15 @@
 /* Define to 1 if you have the `getgid' function. */
 #undef HAVE_GETGID
 
+/* Define if gethostname is supported. */
+#undef HAVE_GETHOSTNAME
+
 /* Define to 1 if you have the `getloadavg' function. */
 #undef HAVE_GETLOADAVG
 
+/* Define if getpid is supported. */
+#undef HAVE_GETPID
+
 /* Define to 1 if you have the `getuid' function. */
 #undef HAVE_GETUID
 
@@ -103,6 +109,9 @@
 /* Define to 1 if the target supports thread-local storage. */
 #undef HAVE_TLS
 
+/* Define if uname is supported and struct utsname has nodename field. */
+#undef HAVE_UNAME
+
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
--- libgomp/Makefile.in.jj	2018-04-30 13:19:46.934834362 +0200
+++ libgomp/Makefile.in	2018-05-21 17:21:39.227956241 +0200
@@ -180,7 +180,8 @@ am_libgomp_la_OBJECTS = alloc.lo atomic.
 	sem.lo bar.lo ptrlock.lo time.lo fortran.lo affinity.lo \
 	target.lo splay-tree.lo libgomp-plugin.lo oacc-parallel.lo \
 	oacc-host.lo oacc-init.lo oacc-mem.lo oacc-async.lo \
-	oacc-plugin.lo oacc-cuda.lo priority_queue.lo $(am__objects_1)
+	oacc-plugin.lo oacc-cuda.lo priority_queue.lo affinity-fmt.lo \
+	$(am__objects_1)
 libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -436,7 +437,7 @@ libgomp_la_SOURCES = alloc.c atomic.c ba
 	affinity.c target.c splay-tree.c libgomp-plugin.c \
 	oacc-parallel.c oacc-host.c oacc-init.c oacc-mem.c \
 	oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c \
-	$(am__append_3)
+	affinity-fmt.c $(am__append_3)
 
 # Nvidia PTX OpenACC plugin.
 @PLUGIN_NVPTX_TRUE@libgomp_plugin_nvptx_version_info = -version-info $(libtool_VERSION)
@@ -600,6 +601,7 @@ distclean-compile:
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity-fmt.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bar.Plo@am__quote@
--- libgomp/testsuite/libgomp.c-c++-common/display-affinity-1.c.jj	2018-05-23 10:06:58.261621753 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/display-affinity-1.c	2018-05-23 11:21:57.641972727 +0200
@@ -0,0 +1,91 @@
+/* { dg-set-target-env-var OMP_PROC_BIND "spread,close" } */
+/* { dg-set-target-env-var OMP_PLACES "cores" } */
+/* { dg-set-target-env-var OMP_NUM_THREADS "4" } */
+/* { dg-set-target-env-var OMP_AFFINITY_FORMAT "hello" } */
+
+#include <omp.h>
+#include <string.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+#define FMT "L:%0.5L%%%n>%32h<!%.33{host}!%.6P_%T_%0.18T_%0.7{ancestor_tnum} %18a"
+  char buf[] = FMT, hostname[256], buf2[512 + 32], *q;
+  size_t l, l2, l3;
+  char *r = getenv ("OMP_AFFINITY_FORMAT");
+  if (r && strcmp (r, "hello") == 0)
+    {
+      if (omp_get_affinity_format (NULL, 0) != 5)
+	abort ();
+      if (omp_get_affinity_format (buf2, 3) != 5
+	  || strcmp (buf2, "he") != 0)
+	abort ();
+      if (omp_get_affinity_format (buf2, 6) != 5
+	  || strcmp (buf2, "hello") != 0)
+	abort ();
+    }
+  omp_set_affinity_format (buf);
+  memset (buf, '^', sizeof (buf));
+  if (omp_get_affinity_format (NULL, 0) != sizeof (buf) - 1)
+    abort ();
+  if (omp_get_affinity_format (buf, 3) != sizeof (buf) - 1
+      || buf[0] != FMT[0] || buf[1] != FMT[1] || buf[2] != '\0')
+    abort ();
+  memset (buf, ' ', sizeof (buf));
+  if (omp_get_affinity_format (buf, sizeof (buf) - 1) != sizeof (buf) - 1
+      || strncmp (buf, FMT, sizeof (buf) - 2) != 0
+      || buf[sizeof (buf) - 2] != '\0')
+    abort ();
+  memset (buf, '-', sizeof (buf));
+  if (omp_get_affinity_format (buf, sizeof (buf)) != sizeof (buf) - 1
+      || strcmp (buf, FMT) != 0)
+    abort ();
+  memset (buf, '0', sizeof (buf));
+  omp_display_affinity (NULL);
+  omp_display_affinity ("");
+  omp_display_affinity ("%%%0.9N");
+  omp_set_affinity_format ("%{host}");
+  l = omp_capture_affinity (hostname, sizeof hostname, NULL);
+  if (l < sizeof (hostname))
+    {
+      if (strlen (hostname) != l)
+	abort ();
+      l2 = omp_capture_affinity (NULL, 0,
+				 "%0.5{thread_level}%%%32{host}|||%.33h"
+				 "%0.7A%3N!%N!");
+      if (l2 != (5 + 1 + (l > 32 ? l : 32) + 3 + (l > 33 ? l : 33)
+		 + 7 + 3 + 1 + 1 + 1))
+	abort ();
+      omp_set_affinity_format ("%.5L%%%32h|||%.33{host}%0.7{ancestor_tnum}"
+			       "%3{num_threads}!%{num_threads}!");
+      l3 = omp_capture_affinity (buf2, sizeof buf2, "");
+      if (l3 != l2)
+	abort ();
+      if (memcmp (buf2, "    0%", 5 + 1) != 0)
+	abort ();
+      q = buf2 + 6;
+      if (memcmp (q, hostname, l) != 0)
+	abort ();
+      q += l;
+      if (l < 32)
+	for (l3 = 32 - l; l3; l3--)
+	  if (*q++ != ' ')
+	    abort ();
+      if (memcmp (q, "|||", 3) != 0)
+	abort ();
+      q += 3;
+      if (l < 33)
+	for (l3 = 33 - l; l3; l3--)
+	  if (*q++ != ' ')
+	    abort ();
+      if (memcmp (q, hostname, l) != 0)
+	abort ();
+      q += l;
+      if (strcmp (q, "-0000011  !1!") != 0)
+	abort ();
+    }
+  #pragma omp parallel num_threads (4) proc_bind(spread)
+  omp_display_affinity ("%0.2A!%n!%.4L!%N;%a");
+  return 0;
+}
--- libgomp/testsuite/libgomp.fortran/display-affinity-1.f90.jj	2018-05-23 13:45:12.788535876 +0200
+++ libgomp/testsuite/libgomp.fortran/display-affinity-1.f90	2018-05-23 14:24:01.349865094 +0200
@@ -0,0 +1,33 @@
+! { dg-set-target-env-var OMP_PROC_BIND "spread,close" }
+! { dg-set-target-env-var OMP_PLACES "cores" }
+! { dg-set-target-env-var OMP_NUM_THREADS "4" }
+! { dg-set-target-env-var OMP_AFFINITY_FORMAT "hello" }
+
+  use omp_lib
+  character(len=68) :: buf, buf2
+  character(len=8) :: buf3
+  character(len=1) :: buf4
+  integer :: l1, l2
+
+  buf = 'L:%0.5L%%%n>%32h<!%.33{host}!%.6P_%T_%0.18T_%0.7{ancestor_tnum} %18a'
+  call omp_set_affinity_format (format = buf)
+  if (omp_get_affinity_format (buf4) /= 68) stop 1
+  if (buf4 /= 'L') stop 2
+  if (omp_get_affinity_format (buf2) /= 68) stop 3
+  if (buf2 /= buf) stop 4
+  if (omp_get_affinity_format (buf3) /= 68) stop 5
+  if (buf3 /= 'L:%0.5L%') stop 6
+  call omp_display_affinity ('')
+  call omp_display_affinity ('%%%0.9N')
+  l1 = omp_capture_affinity (buf4, '%0.5{thread_level}%%|||%0.7A%3N!%N!')
+  buf = '%.5L%%|||%0.7{ancestor_tnum}%3{num_threads}!%{num_threads}!'
+  call omp_set_affinity_format (trim (buf))
+  l2 = omp_capture_affinity (buf2, '')
+  if (l1 /= l2) stop 7
+  if (l1 /= 22) stop 8
+  if (buf2 /= '    0%|||-0000011  !1!') stop 9
+  if (buf4 /= '0') stop 10
+!$omp parallel num_threads (4) proc_bind(spread)
+  call omp_display_affinity ('%0.2A!%n!%.4L!%N;%a')
+!$omp end parallel
+end

	Jakub

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2018-05-23 14:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-23 14:59 [gomp5] Implement omp_[sg]et_affinity_format, omp_{capture,display}_affinity, OMP_DISPLAY_AFFINITY and OMP_AFFINITY_FORMAT Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).