public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support
@ 2018-12-03 16:51 Maciej W. Rozycki
  2018-12-05 10:12 ` Chung-Lin Tang
                   ` (2 more replies)
  0 siblings, 3 replies; 38+ messages in thread
From: Maciej W. Rozycki @ 2018-12-03 16:51 UTC (permalink / raw)
  To: gcc-patches
  Cc: Thomas Schwinge, Chung-Lin Tang, Jakub Jelinek, Catherine Moore

Add generic support for the OpenACC 2.6 `acc_get_property' and 
`acc_get_property_string' routines, as well as full handlers for the 
host and the NVPTX offload targets and a minimal handler for the HSA 
offload target.

Include test cases for both C/C++ and Fortran support, both producing:

OpenACC vendor: GNU
OpenACC name: GOMP
OpenACC driver: 1.0

with the host driver and output like:

OpenACC vendor: Nvidia
OpenACC total memory: 12651462656
OpenACC free memory: 12202737664
OpenACC name: TITAN V
OpenACC driver: 9.1

with the NVPTX driver.

	include/
	* gomp-constants.h (GOMP_DEVICE_CURRENT): New macro.
	(GOMP_DEVICE_PROPERTY_MEMORY, GOMP_DEVICE_PROPERTY_FREE_MEMORY)
	(GOMP_DEVICE_PROPERTY_NAME, GOMP_DEVICE_PROPERTY_VENDOR)
	(GOMP_DEVICE_PROPERTY_DRIVER): Likewise.
	(GOMP_DEVICE_PROPERTY_STRING_MASK): Likewise.

	libgomp/
	* libgomp.h (gomp_device_descr): Add `get_property_func' member.
	* libgomp-plugin.h (gomp_device_property_value): New union.
	(gomp_device_property_value): New prototype.
	* openacc.h (acc_device_t): Add `acc_device_current' enumeration
	constant.
	(acc_device_property_t): New enum.
	(acc_get_property, acc_get_property_string): New prototypes.
	* oacc-init.c (acc_get_device_type): Also assert on
	`!acc_device_current' result.
	(get_property_any, acc_get_property, acc_get_property_string): 
	New functions.
	* openacc.f90 (openacc_kinds): From `iso_fortran_env' also 
	import `int64'.  Add `acc_device_current' and 
	`acc_property_memory', `acc_property_free_memory', 
	`acc_property_name', `acc_property_vendor' and
	`acc_property_driver' constants.  Add `acc_device_property' data
	type.
	(openacc_internal): Add `acc_get_property' and 
	`acc_get_property_string' interfaces.  Add `acc_get_property_h',
	`acc_get_property_string_h', `acc_get_property_l' and 
	`acc_get_property_string_l'.
	(openacc_c_string): New module.
	* oacc-host.c (host_get_property): New function.
	(host_dispatch): Wire it.
	* target.c (gomp_load_plugin_for_device): Handle `get_property'.
	* libgomp.map (OACC_2.6): Add `acc_get_property', 
	`acc_get_property_h_', `acc_get_property_string' and 
	`acc_get_property_string_h_' symbols.
	* libgomp.texi (OpenACC Runtime Library Routines): Add 
	`acc_get_property'.
	(acc_get_property): New node.

	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function.
	* plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName', 
	`cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo' 
	calls.
	(GOMP_OFFLOAD_get_property): New function.

	* testsuite/libgomp.oacc-c-c++-common/acc-get-property.c: New 
	test.
	* testsuite/libgomp.oacc-fortran/acc-get-property.f: New test.
---
Hi,

 This has passed regression-testing with the `x86_64-linux-gnu' target and 
the `nvptx-none' offload target.  I will appreciate feedback and if none 
has been given in a couple of days' time, then I will commit this change 
to the og8 branch.

  Maciej
---
 include/gomp-constants.h                                       |   14 +
 libgomp/libgomp-plugin.h                                       |    8 
 libgomp/libgomp.h                                              |    1 
 libgomp/libgomp.map                                            |    4 
 libgomp/libgomp.texi                                           |   39 +++
 libgomp/oacc-host.c                                            |   22 +
 libgomp/oacc-init.c                                            |   99 ++++++++
 libgomp/openacc.f90                                            |  116 +++++++++-
 libgomp/openacc.h                                              |   15 +
 libgomp/plugin/plugin-hsa.c                                    |   26 ++
 libgomp/plugin/plugin-nvptx.c                                  |   91 +++++++
 libgomp/target.c                                               |    1 
 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c |   37 +++
 libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f      |   33 ++
 14 files changed, 504 insertions(+), 2 deletions(-)

gcc-openacc-acc-get-property.diff
Index: gcc-openacc-gcc-8-branch/include/gomp-constants.h
===================================================================
--- gcc-openacc-gcc-8-branch.orig/include/gomp-constants.h
+++ gcc-openacc-gcc-8-branch/include/gomp-constants.h
@@ -215,10 +215,24 @@ enum gomp_map_kind
 #define GOMP_DEVICE_NVIDIA_PTX		5
 #define GOMP_DEVICE_INTEL_MIC		6
 #define GOMP_DEVICE_HSA			7
+#define GOMP_DEVICE_CURRENT		8
 
 #define GOMP_DEVICE_ICV			-1
 #define GOMP_DEVICE_HOST_FALLBACK	-2
 
+/* Device property codes.  Keep in sync with
+   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t
+   as well as libgomp/libgomp-plugin.h.  */
+/* Start from 1 to catch uninitialized use.  */
+#define GOMP_DEVICE_PROPERTY_MEMORY		1
+#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
+#define GOMP_DEVICE_PROPERTY_NAME		0x10001
+#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
+#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
+
+/* Internal property mask to tell numeric and string values apart.  */
+#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
+
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED		(1 << 0)
 #define GOMP_TASK_FLAG_FINAL		(1 << 1)
Index: gcc-openacc-gcc-8-branch/libgomp/libgomp-plugin.h
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/libgomp-plugin.h
+++ gcc-openacc-gcc-8-branch/libgomp/libgomp-plugin.h
@@ -55,6 +55,13 @@ enum offload_target_type
   OFFLOAD_TARGET_TYPE_HSA = 7
 };
 
+/* Container type for passing device properties.  */
+union gomp_device_property_value
+{
+  void *ptr;
+  uintmax_t val;
+};
+
 /* Opaque type to represent plugin-dependent implementation of an
    OpenACC asynchronous queue.  */
 struct goacc_asyncqueue;  
@@ -99,6 +106,7 @@ extern const char *GOMP_OFFLOAD_get_name
 extern unsigned int GOMP_OFFLOAD_get_caps (void);
 extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
+extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
 extern unsigned GOMP_OFFLOAD_version (void);
Index: gcc-openacc-gcc-8-branch/libgomp/libgomp.h
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/libgomp.h
+++ gcc-openacc-gcc-8-branch/libgomp/libgomp.h
@@ -988,6 +988,7 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
   __typeof (GOMP_OFFLOAD_get_type) *get_type_func;
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
+  __typeof (GOMP_OFFLOAD_get_property) *get_property_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
Index: gcc-openacc-gcc-8-branch/libgomp/libgomp.map
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/libgomp.map
+++ gcc-openacc-gcc-8-branch/libgomp/libgomp.map
@@ -442,6 +442,10 @@ OACC_2.5 {
 
 OACC_2.6 {
   global:
+	acc_get_property;
+	acc_get_property_h_;
+	acc_get_property_string;
+	acc_get_property_string_h_;
 	acc_attach;
 	acc_attach_async;
 	acc_detach;
Index: gcc-openacc-gcc-8-branch/libgomp/libgomp.texi
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/libgomp.texi
+++ gcc-openacc-gcc-8-branch/libgomp/libgomp.texi
@@ -1867,6 +1867,7 @@ version 2.5.
 * acc_get_device_type::         Get type of device accelerator to be used.
 * acc_set_device_num::          Set device number to use.
 * acc_get_device_num::          Get device number to be used.
+* acc_get_property::            Get device property.
 * acc_async_test::              Tests for completion of a specific asynchronous
                                 operation.
 * acc_async_test_all::          Tests for completion of all asychronous
@@ -2049,6 +2050,44 @@ region.
 
 
 
+@node acc_get_property
+@section @code{acc_get_property} -- Get device property.
+@cindex acc_get_property
+@cindex acc_get_property_string
+@table @asis
+@item @emph{Description}
+These routines return the value of the specified @var{property} for the
+device being queried according to @var{devicenum} and @var{devicetype}.
+Integer-valued and string-valued properties are returned by
+@code{acc_get_property} and @code{acc_get_property_string} respectively.
+The Fortran @code{acc_get_property_string} subroutine returns the string
+retrieved in its fourth argument while the remaining entry points are
+functions, which pass the return value as their result.
+
+@item @emph{C/C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
+@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
+@item                   @tab @code{integer devicenum}
+@item                   @tab @code{integer(kind=acc_device_kind) devicetype}
+@item                   @tab @code{integer(kind=acc_device_property) property}
+@item                   @tab @code{integer(kind=acc_device_property) acc_get_property}
+@item                   @tab @code{character(*) string}
+@end multitable
+
+@item @emph{Reference}:
+@uref{https://www.openacc.org, OpenACC specification v2.6}, section
+3.2.6.
+@end table
+
+
+
 @node acc_async_test
 @section @code{acc_async_test} -- Test for completion of a specific asynchronous operation.
 @table @asis
Index: gcc-openacc-gcc-8-branch/libgomp/oacc-host.c
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/oacc-host.c
+++ gcc-openacc-gcc-8-branch/libgomp/oacc-host.c
@@ -60,6 +60,27 @@ host_get_num_devices (void)
   return 1;
 }
 
+static union gomp_device_property_value
+host_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= host_get_num_devices ())
+    return nullval;
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_NAME:
+      return (union gomp_device_property_value) { .ptr = "GOMP" };
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "GNU" };
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      return (union gomp_device_property_value) { .ptr = VERSION };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 host_init_device (int n __attribute__ ((unused)))
 {
@@ -270,6 +291,7 @@ static struct gomp_device_descr host_dis
     .get_caps_func = host_get_caps,
     .get_type_func = host_get_type,
     .get_num_devices_func = host_get_num_devices,
+    .get_property_func = host_get_property,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
     .version_func = host_version,
Index: gcc-openacc-gcc-8-branch/libgomp/oacc-init.c
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/oacc-init.c
+++ gcc-openacc-gcc-8-branch/libgomp/oacc-init.c
@@ -717,7 +717,8 @@ acc_get_device_type (void)
     }
 
   assert (res != acc_device_default
-	  && res != acc_device_not_host);
+	  && res != acc_device_not_host
+	  && res != acc_device_current);
 
   return res;
 }
@@ -826,6 +827,102 @@ acc_set_device_num (int ord, acc_device_
 
 ialias (acc_set_device_num)
 
+static union gomp_device_property_value
+get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  union gomp_device_property_value propval;
+  struct gomp_device_descr *dev;
+  struct goacc_thread *thr;
+
+  if (d == acc_device_none)
+    return (union gomp_device_property_value) { .val = 0 };
+
+  goacc_lazy_initialize ();
+  thr = goacc_thread ();
+
+  if (d == acc_device_current && (!thr || !thr->dev))
+    return (union gomp_device_property_value) { .val = 0 };
+
+  acc_prof_info prof_info;
+  acc_api_info api_info;
+  bool profiling_setup_p
+    = __builtin_expect (goacc_profiling_setup_p (thr, &prof_info, &api_info),
+			false);
+
+  if (d == acc_device_current)
+    {
+      if (profiling_setup_p)
+	{
+	  prof_info.device_type = acc_device_type (thr->dev->type);
+	  prof_info.device_number = thr->dev->target_id;
+	}
+
+      dev = thr->dev;
+    }
+  else
+    {
+      int num_devices;
+
+      if (profiling_setup_p)
+	{
+	  prof_info.device_type = d;
+	  prof_info.device_number = ord;
+	}
+
+      gomp_mutex_lock (&acc_device_lock);
+
+      dev = resolve_device (d, false);
+
+      num_devices = dev->get_num_devices_func ();
+
+      if (num_devices <= 0 || ord >= num_devices)
+        acc_dev_num_out_of_range (d, ord, num_devices);
+
+      dev += ord;
+
+      gomp_mutex_lock (&dev->lock);
+      if (dev->state == GOMP_DEVICE_UNINITIALIZED)
+        gomp_init_device (dev);
+      gomp_mutex_unlock (&dev->lock);
+
+      gomp_mutex_unlock (&acc_device_lock);
+    }
+
+  assert (dev);
+
+  propval = dev->get_property_func (dev->target_id, prop);
+
+  if (profiling_setup_p)
+    {
+      thr->prof_info = NULL;
+      thr->api_info = NULL;
+    }
+
+  return propval;
+}
+
+size_t
+acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return 0;
+  else
+    return get_property_any (ord, d, prop).val;
+}
+
+ialias (acc_get_property)
+
+const char *
+acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return get_property_any (ord, d, prop).ptr;
+  else
+    return NULL;
+}
+
+ialias (acc_get_property_string)
+
 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
    if the user disables the builtin, or calls it via a pointer, we'll need this
    version.
Index: gcc-openacc-gcc-8-branch/libgomp/openacc.f90
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/openacc.f90
+++ gcc-openacc-gcc-8-branch/libgomp/openacc.f90
@@ -28,7 +28,7 @@
 !  <http://www.gnu.org/licenses/>.
 
 module openacc_kinds
-  use iso_fortran_env, only: int32
+  use iso_fortran_env, only: int32, int64
   implicit none
 
   private :: int32
@@ -46,6 +46,21 @@ module openacc_kinds
   ! integer (acc_device_kind), parameter :: acc_device_host_nonshm = 3 removed.
   integer (acc_device_kind), parameter :: acc_device_not_host = 4
   integer (acc_device_kind), parameter :: acc_device_nvidia = 5
+  integer (acc_device_kind), parameter :: acc_device_current = 8
+
+  public :: acc_device_property
+
+  integer, parameter :: acc_device_property = int64
+
+  public :: acc_property_memory, acc_property_free_memory
+  public :: acc_property_name, acc_property_vendor, acc_property_driver
+
+  ! Keep in sync with include/gomp-constants.h.
+  integer (acc_device_property), parameter :: acc_property_memory = 1
+  integer (acc_device_property), parameter :: acc_property_free_memory = 2
+  integer (acc_device_property), parameter :: acc_property_name = Z'10001'
+  integer (acc_device_property), parameter :: acc_property_vendor = Z'10002'
+  integer (acc_device_property), parameter :: acc_property_driver = Z'10003'
 
   public :: acc_handle_kind
 
@@ -93,6 +108,22 @@ module openacc_internal
       integer (acc_device_kind) d
     end function
 
+    function acc_get_property_h (n, d, p)
+      import
+      integer (acc_device_property) :: acc_get_property_h
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+    end function
+
+    subroutine acc_get_property_string_h (n, d, p, s)
+      import
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+      character (*) :: s
+    end subroutine
+
     subroutine acc_set_default_async_h (a)
       import
       integer a
@@ -570,6 +601,24 @@ module openacc_internal
       integer (c_int), value :: d
     end function
 
+    function acc_get_property_l (n, d, p) &
+        bind (C, name = "acc_get_property")
+      use iso_c_binding, only: c_int, c_size_t
+      integer (c_size_t) :: acc_get_property_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
+    function acc_get_property_string_l (n, d, p) &
+        bind (C, name = "acc_get_property_string")
+      use iso_c_binding, only: c_int, c_ptr
+      type (c_ptr) :: acc_get_property_string_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
     function acc_async_test_l (a) &
         bind (C, name = "acc_async_test")
       use iso_c_binding, only: c_int
@@ -830,6 +879,14 @@ module openacc
     procedure :: acc_get_device_num_h
   end interface
 
+  interface acc_get_property
+    procedure :: acc_get_property_h
+  end interface
+
+  interface acc_get_property_string
+    procedure :: acc_get_property_string_h
+  end interface
+
   interface acc_set_default_async
     procedure :: acc_set_default_async_h
   end interface
@@ -1030,6 +1087,19 @@ module openacc
 
 end module
 
+module openacc_c_string
+  implicit none
+
+  interface
+    function strlen (s) bind (C, name = "strlen")
+      use iso_c_binding, only: c_ptr, c_size_t
+      type (c_ptr), intent(in), value :: s
+      integer (c_size_t) :: strlen
+    end function
+  end interface
+
+end module
+
 function acc_get_num_devices_h (d)
   use openacc_internal, only: acc_get_num_devices_l
   use openacc_kinds
@@ -1068,6 +1138,50 @@ function acc_get_device_num_h (d)
   acc_get_device_num_h = acc_get_device_num_l (d)
 end function
 
+function acc_get_property_h (n, d, p)
+  use iso_c_binding, only: c_int
+  use openacc_internal, only: acc_get_property_l
+  use openacc_kinds
+  integer (acc_device_property) :: acc_get_property_h
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+
+  integer (c_int) :: pint
+
+  pint = int (p, c_int)
+  acc_get_property_h = acc_get_property_l (n, d, pint)
+end function
+
+subroutine acc_get_property_string_h (n, d, p, s)
+  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer
+  use openacc_internal, only: acc_get_property_string_l
+  use openacc_c_string, only: strlen
+  use openacc_kinds
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+  character (*) :: s
+
+  integer (c_int) :: pint
+  type (c_ptr) :: cptr
+  integer :: clen
+  character (kind=c_char, len=1), pointer :: sptr (:)
+  integer :: slen
+  integer :: i
+
+  pint = int (p, c_int)
+  cptr = acc_get_property_string_l (n, d, pint)
+  clen = int (strlen (cptr))
+  call c_f_pointer (cptr, sptr, [clen])
+
+  s = ""
+  slen = min (clen, len (s))
+  do i = 1, slen
+    s (i:i) = sptr (i)
+  end do
+end subroutine
+
 function acc_async_test_h (a)
   use openacc_internal, only: acc_async_test_l
   logical acc_async_test_h
Index: gcc-openacc-gcc-8-branch/libgomp/openacc.h
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/openacc.h
+++ gcc-openacc-gcc-8-branch/libgomp/openacc.h
@@ -57,12 +57,23 @@ typedef enum acc_device_t {
   acc_device_nvidia = 5,
   /* not supported */ _acc_device_intel_mic = 6,
   /* not supported */ _acc_device_hsa = 7,
+  acc_device_current = 8,
   _ACC_device_hwm,
   /* Ensure enumeration is layout compatible with int.  */
   _ACC_highest = __INT_MAX__,
   _ACC_neg = -1
 } acc_device_t;
 
+typedef enum acc_device_property_t {
+  /* Keep in sync with include/gomp-constants.h.  */
+  /* Start from 1 to catch uninitialized use.  */
+  acc_property_memory = 1,
+  acc_property_free_memory = 2,
+  acc_property_name = 0x10001,
+  acc_property_vendor = 0x10002,
+  acc_property_driver = 0x10003
+} acc_device_property_t;
+
 typedef enum acc_async_t {
   /* Keep in sync with include/gomp-constants.h.  */
   acc_async_default = 0,
@@ -75,6 +86,10 @@ void acc_set_device_type (acc_device_t) 
 acc_device_t acc_get_device_type (void) __GOACC_NOTHROW;
 void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW;
 int acc_get_device_num (acc_device_t) __GOACC_NOTHROW;
+size_t acc_get_property
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
+const char *acc_get_property_string
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
 void acc_set_default_async (int) __GOACC_NOTHROW;
 int acc_get_default_async (void) __GOACC_NOTHROW;
 int acc_async_test (int) __GOACC_NOTHROW;
Index: gcc-openacc-gcc-8-branch/libgomp/plugin/plugin-hsa.c
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/plugin/plugin-hsa.c
+++ gcc-openacc-gcc-8-branch/libgomp/plugin/plugin-hsa.c
@@ -689,6 +689,32 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
+/* Part of the libgomp plugin interface.  Return the value of property
+   PROP of agent number N.  */
+
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (!init_hsa_context ())
+    return nullval;
+  if (n >= hsa_context.agent_count)
+    {
+      GOMP_PLUGIN_error
+	("Request for a property of a non-existing HSA device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "AMD" };
+    default:
+      return nullval;
+    }
+}
+
 /* Part of the libgomp plugin interface.  Initialize agent number N so that it
    can be used for computation.  Return TRUE on success.  */
 
Index: gcc-openacc-gcc-8-branch/libgomp/plugin/plugin-nvptx.c
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/plugin/plugin-nvptx.c
+++ gcc-openacc-gcc-8-branch/libgomp/plugin/plugin-nvptx.c
@@ -63,6 +63,9 @@ CUDA_ONE_CALL (cuCtxSynchronize)	\
 CUDA_ONE_CALL (cuDeviceGet)		\
 CUDA_ONE_CALL (cuDeviceGetAttribute)	\
 CUDA_ONE_CALL (cuDeviceGetCount)	\
+CUDA_ONE_CALL (cuDeviceGetName)		\
+CUDA_ONE_CALL (cuDeviceTotalMem)	\
+CUDA_ONE_CALL (cuDriverGetVersion)	\
 CUDA_ONE_CALL (cuEventCreate)		\
 CUDA_ONE_CALL (cuEventDestroy)		\
 CUDA_ONE_CALL (cuEventElapsedTime)	\
@@ -88,6 +91,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync)	\
 CUDA_ONE_CALL (cuMemFree)		\
 CUDA_ONE_CALL (cuMemFreeHost)		\
 CUDA_ONE_CALL (cuMemGetAddressRange)	\
+CUDA_ONE_CALL (cuMemGetInfo)		\
 CUDA_ONE_CALL (cuMemHostGetDevicePointer)\
 CUDA_ONE_CALL (cuModuleGetFunction)	\
 CUDA_ONE_CALL (cuModuleGetGlobal)	\
@@ -1014,6 +1018,93 @@ GOMP_OFFLOAD_get_num_devices (void)
   return nvptx_get_num_devices ();
 }
 
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value propval = { .val = 0 };
+
+  pthread_mutex_lock (&ptx_dev_lock);
+
+  if (!nvptx_init () || n >= nvptx_get_num_devices ())
+    {
+      pthread_mutex_unlock (&ptx_dev_lock);
+      return propval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_MEMORY:
+      {
+	size_t total_mem;
+	CUdevice dev;
+
+	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
+	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, dev);
+	propval.val = total_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
+      {
+	size_t total_mem;
+	size_t free_mem;
+	CUdevice ctxdev;
+	CUdevice dev;
+
+	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
+	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
+	if (dev == ctxdev)
+	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	else if (ptx_devices[n])
+	  {
+	    CUcontext old_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_devices[n]->ctx);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
+	  }
+	else
+	  {
+	    CUcontext new_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
+			    dev);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
+	  }
+	propval.val = free_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_NAME:
+      {
+	static char name[256];
+	CUdevice dev;
+
+	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
+	CUDA_CALL_ERET (propval, cuDeviceGetName, name, sizeof (name), dev);
+	propval.ptr = name;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      propval.ptr = "Nvidia";
+      break;
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      {
+	static char ver[11];
+	int v;
+
+	CUDA_CALL_ERET (propval, cuDriverGetVersion, &v);
+	snprintf (ver, sizeof (ver) - 1, "%u.%u", v / 1000, v % 1000 / 10);
+	propval.ptr = ver;
+      }
+      break;
+    default:
+      break;
+    }
+
+  pthread_mutex_unlock (&ptx_dev_lock);
+  return propval;
+}
+
 bool
 GOMP_OFFLOAD_init_device (int n)
 {
Index: gcc-openacc-gcc-8-branch/libgomp/target.c
===================================================================
--- gcc-openacc-gcc-8-branch.orig/libgomp/target.c
+++ gcc-openacc-gcc-8-branch/libgomp/target.c
@@ -3477,6 +3477,7 @@ gomp_load_plugin_for_device (struct gomp
   DLSYM (get_caps);
   DLSYM (get_type);
   DLSYM (get_num_devices);
+  DLSYM (get_property);
   DLSYM (init_device);
   DLSYM (fini_device);
   DLSYM (load_image);
Index: gcc-openacc-gcc-8-branch/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
===================================================================
--- /dev/null
+++ gcc-openacc-gcc-8-branch/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
@@ -0,0 +1,37 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions. */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+int main ()
+{
+  const char *s;
+  size_t v;
+  int r;
+
+  /* Verify that the vendor is a proper non-empty string.  */
+  s = acc_get_property_string (0, acc_device_default, acc_property_vendor);
+  r = !s || !strlen (s);
+  if (s)
+    printf ("OpenACC vendor: %s\n", s);
+
+  /* For the rest just check that they do not crash.  */
+  v = acc_get_property (0, acc_device_default, acc_property_memory);
+  if (v)
+    printf ("OpenACC total memory: %zd\n", v);
+  v = acc_get_property (0, acc_device_default, acc_property_free_memory);
+  if (v)
+    printf ("OpenACC free memory: %zd\n", v);
+  s = acc_get_property_string (0, acc_device_default, acc_property_name);
+  if (s)
+    printf ("OpenACC name: %s\n", s);
+  s = acc_get_property_string (0, acc_device_default, acc_property_driver);
+  if (s)
+    printf ("OpenACC driver: %s\n", s);
+
+  return r;
+}
Index: gcc-openacc-gcc-8-branch/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f
===================================================================
--- /dev/null
+++ gcc-openacc-gcc-8-branch/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f
@@ -0,0 +1,33 @@
+! Test the `acc_get_property' and '`acc_get_property_string' library
+! functions.
+! { dg-do run }
+
+      USE OPENACC
+      IMPLICIT NONE
+
+      INTEGER(ACC_DEVICE_PROPERTY) V
+      CHARACTER*256 S
+      LOGICAL R
+
+      ! Verify that the vendor is a non-empty string.
+      CALL ACC_GET_PROPERTY_STRING (0, ACC_DEVICE_DEFAULT,
+     +                              ACC_PROPERTY_VENDOR, S)
+      R = S /= ""
+      IF (S /= "") PRINT "(A, A)", "OpenACC vendor: ", TRIM (S)
+
+      ! For the rest just check that they do not crash.
+      V = ACC_GET_PROPERTY (0, ACC_DEVICE_DEFAULT,
+     +                      ACC_PROPERTY_MEMORY)
+      IF (V /= 0) PRINT "(A, I0)", "OpenACC total memory: ", V
+      V = ACC_GET_PROPERTY (0, ACC_DEVICE_DEFAULT,
+     +                      ACC_PROPERTY_FREE_MEMORY)
+      IF (V /= 0) PRINT "(A, I0)", "OpenACC free memory: ", V
+      CALL ACC_GET_PROPERTY_STRING (0, ACC_DEVICE_DEFAULT,
+     +                              ACC_PROPERTY_NAME, S)
+      IF (S /= "") PRINT "(A, A)", "OpenACC name: ", TRIM (S)
+      CALL ACC_GET_PROPERTY_STRING (0, ACC_DEVICE_DEFAULT,
+     +                              ACC_PROPERTY_DRIVER, S)
+      IF (S /= "") PRINT "(A, A)", "OpenACC driver: ", TRIM (S)
+
+      IF (.NOT. R) STOP 1
+      END

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support
  2018-12-03 16:51 [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support Maciej W. Rozycki
@ 2018-12-05 10:12 ` Chung-Lin Tang
  2018-12-05 18:17   ` Maciej W. Rozycki
  2019-01-08 17:42 ` Thomas Schwinge
  2019-10-07 18:41 ` Thomas Schwinge
  2 siblings, 1 reply; 38+ messages in thread
From: Chung-Lin Tang @ 2018-12-05 10:12 UTC (permalink / raw)
  To: Maciej W. Rozycki, gcc-patches
  Cc: Thomas Schwinge, Chung-Lin Tang, Jakub Jelinek, Catherine Moore,
	Tom de Vries

Hi Maciej, please see below:

On 2018/12/4 12:51 AM, Maciej W. Rozycki wrote:
> +module openacc_c_string
> +  implicit none
> +
> +  interface
> +    function strlen (s) bind (C, name = "strlen")
> +      use iso_c_binding, only: c_ptr, c_size_t
> +      type (c_ptr), intent(in), value :: s
> +      integer (c_size_t) :: strlen
> +    end function
> +  end interface
> +
> +end module

> +subroutine acc_get_property_string_h (n, d, p, s)
> +  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer
> +  use openacc_internal, only: acc_get_property_string_l
> +  use openacc_c_string, only: strlen
> +  use openacc_kinds
...> +  pint = int (p, c_int)
> +  cptr = acc_get_property_string_l (n, d, pint)
> +  clen = int (strlen (cptr))
> +  call c_f_pointer (cptr, sptr, [clen])

AFAIK, things like strlen are already available in iso_c_binding, in forms like "C_strlen".
Can you check again if that 'openacc_c_string' module is really necessary?

> +union gomp_device_property_value
> +GOMP_OFFLOAD_get_property (int n, int prop)
> +{
> +  union gomp_device_property_value propval = { .val = 0 };
> +
> +  pthread_mutex_lock (&ptx_dev_lock);
> +
> +  if (!nvptx_init () || n >= nvptx_get_num_devices ())
> +    {
> +      pthread_mutex_unlock (&ptx_dev_lock);
> +      return propval;
> +    }
> +
> +  switch (prop)
> +    {
> +    case GOMP_DEVICE_PROPERTY_MEMORY:
> +      {
> +	size_t total_mem;
> +	CUdevice dev;
> +
> +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
> +	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, dev);
> +	propval.val = total_mem;
> +      }
> +      break;
> +    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
> +      {
> +	size_t total_mem;
> +	size_t free_mem;
> +	CUdevice ctxdev;
> +	CUdevice dev;
> +
> +	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
> +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
> +	if (dev == ctxdev)
> +	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> +	else if (ptx_devices[n])
> +	  {
> +	    CUcontext old_ctx;
> +
> +	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_devices[n]->ctx);
> +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> +	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
> +	  }
> +	else
> +	  {
> +	    CUcontext new_ctx;
> +
> +	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
> +			    dev);
> +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> +	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
> +	  }

(I'm CCing Tom here, as he is maintainer for these parts)

As we discussed earlier on our internal list, I think properly using GOMP_OFFLOAD_init_device
is the right way, instead of using the lower level CUDA context create/destroy.

I did not mean for you to first init the device and then immediately destroy it by
GOMP_OFFLOAD_fini_device, just to obtain the property, but for you to just take the opportunity to initialize
it for use, and leave it there until program exit. That should save resources overall.
(BTW, CUDA contexts should be quite expensive to create/destroy, using a cuCtxCreate/Destroy pair is probably
almost as slow)

Tom, do you have any comments on how to best write this part?

Thanks,
Chung-Lin

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support
  2018-12-05 10:12 ` Chung-Lin Tang
@ 2018-12-05 18:17   ` Maciej W. Rozycki
  2018-12-10  9:06     ` Chung-Lin Tang
  0 siblings, 1 reply; 38+ messages in thread
From: Maciej W. Rozycki @ 2018-12-05 18:17 UTC (permalink / raw)
  To: Chung-Lin Tang
  Cc: gcc-patches, Thomas Schwinge, Jakub Jelinek, Catherine Moore,
	Tom de Vries

Hi Chung-Lin,

> > +module openacc_c_string
> > +  implicit none
> > +
> > +  interface
> > +    function strlen (s) bind (C, name = "strlen")
> > +      use iso_c_binding, only: c_ptr, c_size_t
> > +      type (c_ptr), intent(in), value :: s
> > +      integer (c_size_t) :: strlen
> > +    end function
> > +  end interface
> > +
> > +end module
> 
> > +subroutine acc_get_property_string_h (n, d, p, s)
> > +  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer
> > +  use openacc_internal, only: acc_get_property_string_l
> > +  use openacc_c_string, only: strlen
> > +  use openacc_kinds
> ...> +  pint = int (p, c_int)
> > +  cptr = acc_get_property_string_l (n, d, pint)
> > +  clen = int (strlen (cptr))
> > +  call c_f_pointer (cptr, sptr, [clen])
> 
> AFAIK, things like strlen are already available in iso_c_binding, in forms
> like "C_strlen".
> Can you check again if that 'openacc_c_string' module is really necessary?

 Any pointers please?

 I can't see `c_strlen' or any equivalent interface defined either in the 
Fortran 2003 language standard or in GCC documentation, and neither `grep' 
over the GCC tree shows anything relevant.  The `iso_c_binding' module 
defines only a bunch of procedures according to said documentation.  The 
`strlen' function provided here has been taken from one of our Fortran 
test cases, which strongly indicates there's no such API already available 
or whoever wrote the test case would have chosen to use it I suppose.

> > +union gomp_device_property_value
> > +GOMP_OFFLOAD_get_property (int n, int prop)
> > +{
> > +  union gomp_device_property_value propval = { .val = 0 };
> > +
> > +  pthread_mutex_lock (&ptx_dev_lock);
> > +
> > +  if (!nvptx_init () || n >= nvptx_get_num_devices ())
> > +    {
> > +      pthread_mutex_unlock (&ptx_dev_lock);
> > +      return propval;
> > +    }
> > +
> > +  switch (prop)
> > +    {
> > +    case GOMP_DEVICE_PROPERTY_MEMORY:
> > +      {
> > +	size_t total_mem;
> > +	CUdevice dev;
> > +
> > +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
> > +	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, dev);
> > +	propval.val = total_mem;
> > +      }
> > +      break;
> > +    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
> > +      {
> > +	size_t total_mem;
> > +	size_t free_mem;
> > +	CUdevice ctxdev;
> > +	CUdevice dev;
> > +
> > +	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
> > +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
> > +	if (dev == ctxdev)
> > +	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> > +	else if (ptx_devices[n])
> > +	  {
> > +	    CUcontext old_ctx;
> > +
> > +	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_devices[n]->ctx);
> > +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> > +	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
> > +	  }
> > +	else
> > +	  {
> > +	    CUcontext new_ctx;
> > +
> > +	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
> > +			    dev);
> > +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> > +	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
> > +	  }
> 
> (I'm CCing Tom here, as he is maintainer for these parts)
> 
> As we discussed earlier on our internal list, I think properly using
> GOMP_OFFLOAD_init_device
> is the right way, instead of using the lower level CUDA context
> create/destroy.
> 
> I did not mean for you to first init the device and then immediately destroy
> it by
> GOMP_OFFLOAD_fini_device, just to obtain the property, but for you to just
> take the opportunity to initialize
> it for use, and leave it there until program exit. That should save resources
> overall.
> (BTW, CUDA contexts should be quite expensive to create/destroy, using a
> cuCtxCreate/Destroy pair is probably
> almost as slow)

 I have argued that this looks like a corner-case use case to me, as 
querying for the remaining (rather than total) memory available to a 
device that hasn't been (yet) used looks like of hardly any use to me, 
because obviously at such a stage no memory has been used.  The OpenACC 
standard does require us to handle such a request somehow, with returning 
0 being another option, however I thought we may well have a quick peek 
without pulling in all the state.

 I guess I have no strong opinion either way and I can adapt accordingly.

 NB that would have to be `gomp_init_device' rather than 
`GOMP_OFFLOAD_init_device' AFAICS.

  Maciej

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support
  2018-12-05 18:17   ` Maciej W. Rozycki
@ 2018-12-10  9:06     ` Chung-Lin Tang
  2018-12-20 14:25       ` Maciej W. Rozycki
  0 siblings, 1 reply; 38+ messages in thread
From: Chung-Lin Tang @ 2018-12-10  9:06 UTC (permalink / raw)
  To: Maciej W. Rozycki, Chung-Lin Tang
  Cc: gcc-patches, Thomas Schwinge, Jakub Jelinek, Catherine Moore,
	Tom de Vries

On 2018/12/6 2:16 AM, Maciej W. Rozycki wrote:
>> AFAIK, things like strlen are already available in iso_c_binding, in forms
>> like "C_strlen".
>> Can you check again if that 'openacc_c_string' module is really necessary?
>   Any pointers please?
> 
>   I can't see `c_strlen' or any equivalent interface defined either in the
> Fortran 2003 language standard or in GCC documentation, and neither `grep'
> over the GCC tree shows anything relevant.  The `iso_c_binding' module
> defines only a bunch of procedures according to said documentation.  The
> `strlen' function provided here has been taken from one of our Fortran
> test cases, which strongly indicates there's no such API already available
> or whoever wrote the test case would have chosen to use it I suppose.

Okay I see. I think I mixed up the common convention with the actual interface
standard.

>>> +	    CUcontext new_ctx;
>>> +
>>> +	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
>>> +			    dev);
>>> +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
>>> +	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
>>> +	  }
>> (I'm CCing Tom here, as he is maintainer for these parts)
>>
>> As we discussed earlier on our internal list, I think properly using
>> GOMP_OFFLOAD_init_device
>> is the right way, instead of using the lower level CUDA context
>> create/destroy.
>>
>> I did not mean for you to first init the device and then immediately destroy
>> it by
>> GOMP_OFFLOAD_fini_device, just to obtain the property, but for you to just
>> take the opportunity to initialize
>> it for use, and leave it there until program exit. That should save resources
>> overall.
>> (BTW, CUDA contexts should be quite expensive to create/destroy, using a
>> cuCtxCreate/Destroy pair is probably
>> almost as slow)
>   I have argued that this looks like a corner-case use case to me, as
> querying for the remaining (rather than total) memory available to a
> device that hasn't been (yet) used looks like of hardly any use to me,
> because obviously at such a stage no memory has been used.  The OpenACC
> standard does require us to handle such a request somehow, with returning
> 0 being another option, however I thought we may well have a quick peek
> without pulling in all the state.
> 
>   I guess I have no strong opinion either way and I can adapt accordingly.
> 
>   NB that would have to be `gomp_init_device' rather than
> `GOMP_OFFLOAD_init_device' AFAICS.

You'll have to use GOMP_OFFLOAD_init_device, as you are inside the plugin, gomp_init_device()
should not be available.

However, looking into this further, the checking conventions of GOMP_OFFLOAD_init_device
will have to be slightly tweaked to accommodate possible further initing from libgomp proper,
so this may requirement a longer string of changes...I think it's not worth it, or can
be adjusted later. I now think your current approach with the CUDA contexts is okay.

I think the patch is okay, although still needs approval from Thomas and Tom to commit.

Thanks,
Chung-Lin

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support
  2018-12-10  9:06     ` Chung-Lin Tang
@ 2018-12-20 14:25       ` Maciej W. Rozycki
  0 siblings, 0 replies; 38+ messages in thread
From: Maciej W. Rozycki @ 2018-12-20 14:25 UTC (permalink / raw)
  To: Chung-Lin Tang
  Cc: gcc-patches, Thomas Schwinge, Jakub Jelinek, Catherine Moore,
	Tom de Vries

On Mon, 10 Dec 2018, Chung-Lin Tang wrote:

> I think the patch is okay, although still needs approval from Thomas and Tom
> to commit.

 I have committed this change now, thank you for your review.

  Maciej

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support
  2018-12-03 16:51 [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support Maciej W. Rozycki
  2018-12-05 10:12 ` Chung-Lin Tang
@ 2019-01-08 17:42 ` Thomas Schwinge
  2019-10-07 18:41 ` Thomas Schwinge
  2 siblings, 0 replies; 38+ messages in thread
From: Thomas Schwinge @ 2019-01-08 17:42 UTC (permalink / raw)
  To: Maciej W. Rozycki, gcc-patches
  Cc: Chung-Lin Tang, Jakub Jelinek, Catherine Moore

[-- Attachment #1: Type: text/plain, Size: 728 bytes --]

Hi Maciej!

On Mon, 3 Dec 2018 16:51:14 +0000, "Maciej W. Rozycki" <macro@codesourcery.com> wrote:
> Add generic support for the OpenACC 2.6 `acc_get_property' and 
> `acc_get_property_string' routines, as well as full handlers for the 
> host and the NVPTX offload targets and a minimal handler for the HSA 
> offload target.

..., but a similar minimal handler for the Intel MIC offload plugin
missing.  ;-) (... which "for reasons" doesn't live in "libgomp/plugin/",
next to the other plugins.)

To fix that, I pushed the attached to openacc-gcc-8-branch, with the code
copied and adjusted from your minimal handler for the HSA offload target,
but also with an additional TODO added.


Grüße
 Thomas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-OpenACC-2.6-acc_get_property-support-restore-Int.patch --]
[-- Type: text/x-diff, Size: 2548 bytes --]

From c632bd83096f1a4e4ed59161797087ff800e4c23 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Tue, 8 Jan 2019 15:21:35 +0100
Subject: [PATCH] Add OpenACC 2.6 `acc_get_property' support: restore Intel MIC
 offloading

The "OpenACC 2.6 `acc_get_property' support" changes regressed the relevant
libgomp OpenMP execution test cases to no longer consider Intel MIC offloading
because of:

    libgomp: while loading libgomp-plugin-intelmic.so.1: [...]/libgomp-plugin-intelmic.so.1: undefined symbol: GOMP_OFFLOAD_get_property

	liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
	New function.
---
 liboffloadmic/ChangeLog.openacc               | 10 +++++++++
 .../plugin/libgomp-plugin-intelmic.cpp        | 21 +++++++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 liboffloadmic/ChangeLog.openacc

diff --git a/liboffloadmic/ChangeLog.openacc b/liboffloadmic/ChangeLog.openacc
new file mode 100644
index 000000000000..2e666da2ce0c
--- /dev/null
+++ b/liboffloadmic/ChangeLog.openacc
@@ -0,0 +1,10 @@
+2019-01-08  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
+	New function.
+\f
+Copyright (C) 2019 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
index d1678d0514e9..f74941c2b549 100644
--- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
+++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
@@ -174,6 +174,27 @@ GOMP_OFFLOAD_get_num_devices (void)
   return num_devices;
 }
 
+extern "C" union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= num_devices)
+    {
+      GOMP_PLUGIN_error
+	("Request for a property of a non-existing Intel MIC device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = /* TODO: "error: invalid conversion from 'const void*' to 'void*' [-fpermissive]" */ (char *) "Intel" };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 offload (const char *file, uint64_t line, int device, const char *name,
 	 int num_vars, VarDesc *vars, const void **async_data)
-- 
2.17.1


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Add OpenACC 2.6 `acc_get_property' support
  2018-12-03 16:51 [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support Maciej W. Rozycki
  2018-12-05 10:12 ` Chung-Lin Tang
  2019-01-08 17:42 ` Thomas Schwinge
@ 2019-10-07 18:41 ` Thomas Schwinge
  2019-11-05 15:09   ` Harwath, Frederik
  2019-11-14 15:41   ` [PATCH] " Frederik Harwath
  2 siblings, 2 replies; 38+ messages in thread
From: Thomas Schwinge @ 2019-10-07 18:41 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Frederik Harwath


[-- Attachment #1.1: Type: text/plain, Size: 8090 bytes --]

Hi Jakub!

On 2018-12-03T16:51:14+0000, "Maciej W. Rozycki" <macro@codesourcery.com> wrote:
> Add generic support for the OpenACC 2.6 `acc_get_property' and 
> `acc_get_property_string' routines [...]

..., which allow for user code to query the implementation for stuff like:

> OpenACC vendor: GNU
> OpenACC name: GOMP
> OpenACC driver: 1.0
>
> with the host driver and output like:
>
> OpenACC vendor: Nvidia
> OpenACC total memory: 12651462656
> OpenACC free memory: 12202737664
> OpenACC name: TITAN V
> OpenACC driver: 9.1
>
> with the NVPTX driver.

(With 's%OpenACC%Device%', as I understand this; see my comment below.)

Before Frederik starts working on integrating this into GCC trunk, do you
(Jakub) agree with the libgomp plugin interface changes as implemented by
Maciej?  For example, top-level 'GOMP_OFFLOAD_get_property' function in
'struct gomp_device_descr' instead of stuffing this into its
'acc_dispatch_t openacc'.  (I never understood why the OpenACC functions
need to be segregated like they are.)

For reference I'm attaching the latest version of the patch, that is the
commit from openacc-gcc-9-branch, plus a small fix-up.


And, some first remarks (or, "thinking aloud", not a conclusive review)
while I have a look at this myself:

> --- a/include/gomp-constants.h
> +++ b/include/gomp-constants.h
> @@ -215,10 +215,24 @@ enum gomp_map_kind
>  #define GOMP_DEVICE_NVIDIA_PTX		5
>  #define GOMP_DEVICE_INTEL_MIC		6
>  #define GOMP_DEVICE_HSA			7
> +#define GOMP_DEVICE_CURRENT		8

This is used for 'acc_device_current', relevant only for
'acc_get_property', to return "the value of the property for the current
device".  This should probably use a more special (negative?) value
instead of eight, so that when additional real device types are added
later on, we can just add them with increasing numbers, and keep the
scanning code simple.

(Use of 'acc_device_current' as an argument to other functions taking an
'acc_device_t' is undefined, and should be rejected with 'gomp_fatal'?)

Also, 'acc_device_current' is a libgomp-internal thing (doesn't interface
with the compiler proper), so strictly speaking 'GOMP_DEVICE_CURRENT'
isn't needed in 'include/gomp-constants.h'.  But probably still a good
idea to list it there, in this canonical place, to keep the several lists
of device types coherent.

(I have not checked how 'acc_device_current' is actually implemented in
the following.)

> +/* Device property codes.  Keep in sync with
> +   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t
> +   as well as libgomp/libgomp-plugin.h.  */

Same thing, libgomp-internal, not sure whether to list these here?

> +/* Start from 1 to catch uninitialized use.  */

Hmm, not sure about that either.  Don't think we're generally doing that?

(But I see PGI have 'acc_property_none = 0', oh well.)

> +#define GOMP_DEVICE_PROPERTY_MEMORY		1
> +#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
> +#define GOMP_DEVICE_PROPERTY_NAME		0x10001
> +#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
> +#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
> +
> +/* Internal property mask to tell numeric and string values apart.  */
> +#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000


> --- a/libgomp/plugin/plugin-nvptx.c
> +++ b/libgomp/plugin/plugin-nvptx.c

> +union gomp_device_property_value
> +GOMP_OFFLOAD_get_property (int n, int prop)
> +{
> +  union gomp_device_property_value propval = { .val = 0 };
> +
> +  pthread_mutex_lock (&ptx_dev_lock);
> +
> +  if (!nvptx_init () || n >= nvptx_get_num_devices ())
> +    {
> +      pthread_mutex_unlock (&ptx_dev_lock);
> +      return propval;
> +    }

Isn't it implicit that 'get_num_devices' has been called while loading
the plugin, so we don't have to do any initialization that here?  (But I
may be misremembering that.)

> +  switch (prop)
> +    {
> +    case GOMP_DEVICE_PROPERTY_MEMORY:
> +      {
> +	size_t total_mem;
> +	CUdevice dev;
> +
> +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);

Isn't that already known as 'ptx_devices[n]'?  (Likewise elsewhere.)

> +	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, dev);
> +	propval.val = total_mem;
> +      }
> +      break;

> +    case GOMP_DEVICE_PROPERTY_NAME:
> +      {
> +	static char name[256];
> +	CUdevice dev;
> +
> +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
> +	CUDA_CALL_ERET (propval, cuDeviceGetName, name, sizeof (name), dev);
> +	propval.ptr = name;
> +      }
> +      break;

Uh, that's not thread-safe, is it?

From a quick look at OpenACC 2.7, that doesn't specify what exactly to
return here (that is, which "class" of memory; who's the "owner" of the
memory object).  (So, returning a 'malloc'ed object would be a memory
leak, for example.)  Best would probably be to return some 'const char *'
living in read-only program memory.  (But that likely is not available,
otherwise I suppose Maciej would have done that.)

Otherwise, perhaps make this 'name' a property of 'struct ptx_device' in
the nvptx plugin here, and keep it live while the device is open
('nvptx_open_device'), together with other per-device data?

> +    case GOMP_DEVICE_PROPERTY_DRIVER:
> +      {
> +	static char ver[11];
> +	int v;
> +
> +	CUDA_CALL_ERET (propval, cuDriverGetVersion, &v);
> +	snprintf (ver, sizeof (ver) - 1, "%u.%u", v / 1000, v % 1000 / 10);
> +	propval.ptr = ver;
> +      }
> +      break;

Similar here.

Is that 'snprintf' formatting the generic way to display a CUDA driver
version number?  

As, in theory, such Nvidia GPU offloading support could also be
implemented via the Nouveau/Mesa GalliumCompute driver, should the string
returned here actually include "CUDA Driver"?

> +    default:
> +      break;

Should this 'GOMP_PLUGIN_error' or even 'GOMP_PLUGIN_fatal'?  (Similar
then elsewhere.)


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
> @@ -0,0 +1,37 @@
> +/* Test the `acc_get_property' and '`acc_get_property_string' library
> +   functions. */
> +/* { dg-do run } */
> +
> +#include <openacc.h>
> +#include <stddef.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +int main ()
> +{
> +  const char *s;
> +  size_t v;
> +  int r;
> +
> +  /* Verify that the vendor is a proper non-empty string.  */
> +  s = acc_get_property_string (0, acc_device_default, acc_property_vendor);
> +  r = !s || !strlen (s);
> +  if (s)
> +    printf ("OpenACC vendor: %s\n", s);

Should we check the actual string returned, as defined by OpenACC/our
implementation, as applicable?  Use '#if defined ACC_DEVICE_TYPE_[...]'.
(See 'libgomp/testsuite/libgomp.oacc-c-c++-common/avoid-offloading-2.c',
for example.)

Isn't this the "Device vendor" instead of the "OpenACC vendor"?  Similar
for all other 'printf's?

> +
> +  /* For the rest just check that they do not crash.  */
> +  v = acc_get_property (0, acc_device_default, acc_property_memory);
> +  if (v)
> +    printf ("OpenACC total memory: %zd\n", v);
> +  v = acc_get_property (0, acc_device_default, acc_property_free_memory);
> +  if (v)
> +    printf ("OpenACC free memory: %zd\n", v);
> +  s = acc_get_property_string (0, acc_device_default, acc_property_name);
> +  if (s)
> +    printf ("OpenACC name: %s\n", s);
> +  s = acc_get_property_string (0, acc_device_default, acc_property_driver);
> +  if (s)
> +    printf ("OpenACC driver: %s\n", s);
> +
> +  return r;
> +}

Likewise, as we define the implementation, we can declare that something
reasonable must have been returned, so don't need 'if (s)' checks, but
should instead verify 's' to the extent possible.

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f

Similar.  (See
'libgomp/testsuite/libgomp.oacc-fortran/avoid-offloading-2.f', for
example.)

These tests only use 'acc_device_default', should they also check other
valid as well as invalid values?


Grüße
 Thomas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-Add-OpenACC-2.6-acc_get_property-support.patch --]
[-- Type: text/x-diff, Size: 31237 bytes --]

From 4674caa90e82c209db51bf1fb5d7ec42364d47a2 Mon Sep 17 00:00:00 2001
From: "Maciej W. Rozycki" <macro@codesourcery.com>
Date: Thu, 20 Dec 2018 14:10:17 +0000
Subject: [PATCH] Add OpenACC 2.6 `acc_get_property' support

Add generic support for the OpenACC 2.6 `acc_get_property' and
`acc_get_property_string' routines, as well as full handlers for the
host and the NVPTX offload targets and a minimal handler for the HSA
offload target.

Include test cases for both C/C++ and Fortran support, both producing:

OpenACC vendor: GNU
OpenACC name: GOMP
OpenACC driver: 1.0

with the host driver and output like:

OpenACC vendor: Nvidia
OpenACC total memory: 12651462656
OpenACC free memory: 12202737664
OpenACC name: TITAN V
OpenACC driver: 9.1

with the NVPTX driver.

	include/
	* gomp-constants.h (GOMP_DEVICE_CURRENT): New macro.
	(GOMP_DEVICE_PROPERTY_MEMORY, GOMP_DEVICE_PROPERTY_FREE_MEMORY)
	(GOMP_DEVICE_PROPERTY_NAME, GOMP_DEVICE_PROPERTY_VENDOR)
	(GOMP_DEVICE_PROPERTY_DRIVER): Likewise.
	(GOMP_DEVICE_PROPERTY_STRING_MASK): Likewise.

	libgomp/
	* libgomp.h (gomp_device_descr): Add `get_property_func' member.
	* libgomp-plugin.h (gomp_device_property_value): New union.
	(gomp_device_property_value): New prototype.
	* openacc.h (acc_device_t): Add `acc_device_current' enumeration
	constant.
	(acc_device_property_t): New enum.
	(acc_get_property, acc_get_property_string): New prototypes.
	* oacc-init.c (acc_get_device_type): Also assert on
	`!acc_device_current' result.
	(get_property_any, acc_get_property, acc_get_property_string):
	New functions.
	* openacc.f90 (openacc_kinds): From `iso_fortran_env' also
	import `int64'.  Add `acc_device_current' and
	`acc_property_memory', `acc_property_free_memory',
	`acc_property_name', `acc_property_vendor' and
	`acc_property_driver' constants.  Add `acc_device_property' data
	type.
	(openacc_internal): Add `acc_get_property' and
	`acc_get_property_string' interfaces.  Add `acc_get_property_h',
	`acc_get_property_string_h', `acc_get_property_l' and
	`acc_get_property_string_l'.
	(openacc_c_string): New module.
	* oacc-host.c (host_get_property): New function.
	(host_dispatch): Wire it.
	* target.c (gomp_load_plugin_for_device): Handle `get_property'.
	* libgomp.map (OACC_2.6): Add `acc_get_property',
	`acc_get_property_h_', `acc_get_property_string' and
	`acc_get_property_string_h_' symbols.
	* libgomp.texi (OpenACC Runtime Library Routines): Add
	`acc_get_property'.
	(acc_get_property): New node.

	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function.
	* plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName',
	`cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo'
	calls.
	(GOMP_OFFLOAD_get_property): New function.

	* testsuite/libgomp.oacc-c-c++-common/acc-get-property.c: New
	test.
	* testsuite/libgomp.oacc-fortran/acc-get-property.f: New test.
---
 include/ChangeLog.openacc                     |   8 ++
 include/gomp-constants.h                      |  14 +++
 libgomp/ChangeLog.openacc                     |  44 +++++++
 libgomp/libgomp-plugin.h                      |   8 ++
 libgomp/libgomp.h                             |   1 +
 libgomp/libgomp.map                           |   4 +
 libgomp/libgomp.texi                          |  39 ++++++
 libgomp/oacc-host.c                           |  22 ++++
 libgomp/oacc-init.c                           |  75 ++++++++++-
 libgomp/openacc.f90                           | 116 +++++++++++++++++-
 libgomp/openacc.h                             |  15 +++
 libgomp/plugin/cuda-lib.def                   |   4 +
 libgomp/plugin/plugin-hsa.c                   |  26 ++++
 libgomp/plugin/plugin-nvptx.c                 |  87 +++++++++++++
 libgomp/target.c                              |   1 +
 .../acc-get-property.c                        |  37 ++++++
 .../libgomp.oacc-fortran/acc-get-property.f   |  33 +++++
 17 files changed, 532 insertions(+), 2 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f

diff --git a/include/ChangeLog.openacc b/include/ChangeLog.openacc
index bd8dba0544c..2cbb9919f60 100644
--- a/include/ChangeLog.openacc
+++ b/include/ChangeLog.openacc
@@ -1,3 +1,11 @@
+2018-12-20  Maciej W. Rozycki  <macro@codesourcery.com>
+
+	* gomp-constants.h (GOMP_DEVICE_CURRENT): New macro.
+	(GOMP_DEVICE_PROPERTY_MEMORY, GOMP_DEVICE_PROPERTY_FREE_MEMORY)
+	(GOMP_DEVICE_PROPERTY_NAME, GOMP_DEVICE_PROPERTY_VENDOR)
+	(GOMP_DEVICE_PROPERTY_DRIVER): Likewise.
+	(GOMP_DEVICE_PROPERTY_STRING_MASK): Likewise.
+
 2018-12-19  Julian Brown  <julian@codesourcery.com>
             Maciej W. Rozycki  <macro@codesourcery.com>
 
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index dae4eea66de..5634babd840 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -215,10 +215,24 @@ enum gomp_map_kind
 #define GOMP_DEVICE_NVIDIA_PTX		5
 #define GOMP_DEVICE_INTEL_MIC		6
 #define GOMP_DEVICE_HSA			7
+#define GOMP_DEVICE_CURRENT		8
 
 #define GOMP_DEVICE_ICV			-1
 #define GOMP_DEVICE_HOST_FALLBACK	-2
 
+/* Device property codes.  Keep in sync with
+   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t
+   as well as libgomp/libgomp-plugin.h.  */
+/* Start from 1 to catch uninitialized use.  */
+#define GOMP_DEVICE_PROPERTY_MEMORY		1
+#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
+#define GOMP_DEVICE_PROPERTY_NAME		0x10001
+#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
+#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
+
+/* Internal property mask to tell numeric and string values apart.  */
+#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
+
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED		(1 << 0)
 #define GOMP_TASK_FLAG_FINAL		(1 << 1)
diff --git a/libgomp/ChangeLog.openacc b/libgomp/ChangeLog.openacc
index 6c1defe2011..963e28621e4 100644
--- a/libgomp/ChangeLog.openacc
+++ b/libgomp/ChangeLog.openacc
@@ -1,3 +1,47 @@
+2018-12-20  Maciej W. Rozycki  <macro@codesourcery.com>
+
+	* libgomp.h (gomp_device_descr): Add `get_property_func' member.
+	* libgomp-plugin.h (gomp_device_property_value): New union.
+	(gomp_device_property_value): New prototype.
+	* openacc.h (acc_device_t): Add `acc_device_current' enumeration
+	constant.
+	(acc_device_property_t): New enum.
+	(acc_get_property, acc_get_property_string): New prototypes.
+	* oacc-init.c (acc_get_device_type): Also assert on
+	`!acc_device_current' result.
+	(get_property_any, acc_get_property, acc_get_property_string):
+	New functions.
+	* openacc.f90 (openacc_kinds): From `iso_fortran_env' also
+	import `int64'.  Add `acc_device_current' and
+	`acc_property_memory', `acc_property_free_memory',
+	`acc_property_name', `acc_property_vendor' and
+	`acc_property_driver' constants.  Add `acc_device_property' data
+	type.
+	(openacc_internal): Add `acc_get_property' and
+	`acc_get_property_string' interfaces.  Add `acc_get_property_h',
+	`acc_get_property_string_h', `acc_get_property_l' and
+	`acc_get_property_string_l'.
+	(openacc_c_string): New module.
+	* oacc-host.c (host_get_property): New function.
+	(host_dispatch): Wire it.
+	* target.c (gomp_load_plugin_for_device): Handle `get_property'.
+	* libgomp.map (OACC_2.6): Add `acc_get_property',
+	`acc_get_property_h_', `acc_get_property_string' and
+	`acc_get_property_string_h_' symbols.
+	* libgomp.texi (OpenACC Runtime Library Routines): Add
+	`acc_get_property'.
+	(acc_get_property): New node.
+
+	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function.
+	* plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName',
+	`cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo'
+	calls.
+	(GOMP_OFFLOAD_get_property): New function.
+
+	* testsuite/libgomp.oacc-c-c++-common/acc-get-property.c: New
+	test.
+	* testsuite/libgomp.oacc-fortran/acc-get-property.f: New test.
+
 2018-12-19  Julian Brown  <julian@codesourcery.com>
             Maciej W. Rozycki  <macro@codesourcery.com>
 
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index be7c994faeb..da8ce260564 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -53,6 +53,13 @@ enum offload_target_type
   OFFLOAD_TARGET_TYPE_HSA = 7
 };
 
+/* Container type for passing device properties.  */
+union gomp_device_property_value
+{
+  void *ptr;
+  uintmax_t val;
+};
+
 /* Opaque type to represent plugin-dependent implementation of an
    OpenACC asynchronous queue.  */
 struct goacc_asyncqueue;
@@ -93,6 +100,7 @@ extern const char *GOMP_OFFLOAD_get_name (void);
 extern unsigned int GOMP_OFFLOAD_get_caps (void);
 extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
+extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
 extern unsigned GOMP_OFFLOAD_version (void);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 9c9157d826c..31403ba67a9 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1049,6 +1049,7 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
   __typeof (GOMP_OFFLOAD_get_type) *get_type_func;
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
+  __typeof (GOMP_OFFLOAD_get_property) *get_property_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index aa76ee309ff..717ae668400 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -478,6 +478,10 @@ OACC_2.5 {
 
 OACC_2.6 {
   global:
+	acc_get_property;
+	acc_get_property_h_;
+	acc_get_property_string;
+	acc_get_property_string_h_;
 	acc_attach;
 	acc_attach_async;
 	acc_detach;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index e2e384ae8b6..b2fc35b32c2 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -1848,6 +1848,7 @@ acceleration device.
 * acc_get_device_type::         Get type of device accelerator to be used.
 * acc_set_device_num::          Set device number to use.
 * acc_get_device_num::          Get device number to be used.
+* acc_get_property::            Get device property.
 * acc_async_test::              Tests for completion of a specific asynchronous
                                 operation.
 * acc_async_test_all::          Tests for completion of all asychronous
@@ -2030,6 +2031,44 @@ region.
 
 
 
+@node acc_get_property
+@section @code{acc_get_property} -- Get device property.
+@cindex acc_get_property
+@cindex acc_get_property_string
+@table @asis
+@item @emph{Description}
+These routines return the value of the specified @var{property} for the
+device being queried according to @var{devicenum} and @var{devicetype}.
+Integer-valued and string-valued properties are returned by
+@code{acc_get_property} and @code{acc_get_property_string} respectively.
+The Fortran @code{acc_get_property_string} subroutine returns the string
+retrieved in its fourth argument while the remaining entry points are
+functions, which pass the return value as their result.
+
+@item @emph{C/C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
+@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
+@item                   @tab @code{integer devicenum}
+@item                   @tab @code{integer(kind=acc_device_kind) devicetype}
+@item                   @tab @code{integer(kind=acc_device_property) property}
+@item                   @tab @code{integer(kind=acc_device_property) acc_get_property}
+@item                   @tab @code{character(*) string}
+@end multitable
+
+@item @emph{Reference}:
+@uref{https://www.openacc.org, OpenACC specification v2.6}, section
+3.2.6.
+@end table
+
+
+
 @node acc_async_test
 @section @code{acc_async_test} -- Test for completion of a specific asynchronous operation.
 @table @asis
diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c
index b19b7479afd..beeca287e15 100644
--- a/libgomp/oacc-host.c
+++ b/libgomp/oacc-host.c
@@ -60,6 +60,27 @@ host_get_num_devices (void)
   return 1;
 }
 
+static union gomp_device_property_value
+host_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= host_get_num_devices ())
+    return nullval;
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_NAME:
+      return (union gomp_device_property_value) { .ptr = "GOMP" };
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "GNU" };
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      return (union gomp_device_property_value) { .ptr = VERSION };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 host_init_device (int n __attribute__ ((unused)))
 {
@@ -273,6 +294,7 @@ static struct gomp_device_descr host_dispatch =
     .get_caps_func = host_get_caps,
     .get_type_func = host_get_type,
     .get_num_devices_func = host_get_num_devices,
+    .get_property_func = host_get_property,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
     .version_func = host_version,
diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index 7e34c856f33..0cd673ecc20 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -597,7 +597,8 @@ acc_get_device_type (void)
     }
 
   assert (res != acc_device_default
-	  && res != acc_device_not_host);
+	  && res != acc_device_not_host
+	  && res != acc_device_current);
 
   return res;
 }
@@ -671,6 +672,78 @@ acc_set_device_num (int ord, acc_device_t d)
 
 ialias (acc_set_device_num)
 
+static union gomp_device_property_value
+get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  union gomp_device_property_value propval;
+  struct gomp_device_descr *dev;
+  struct goacc_thread *thr;
+
+  if (d == acc_device_none)
+    return (union gomp_device_property_value) { .val = 0 };
+
+  goacc_lazy_initialize ();
+  thr = goacc_thread ();
+
+  if (d == acc_device_current && (!thr || !thr->dev))
+    return (union gomp_device_property_value) { .val = 0 };
+
+  if (d == acc_device_current)
+    {
+      dev = thr->dev;
+    }
+  else
+    {
+      int num_devices;
+
+      gomp_mutex_lock (&acc_device_lock);
+
+      dev = resolve_device (d, false);
+
+      num_devices = dev->get_num_devices_func ();
+
+      if (num_devices <= 0 || ord >= num_devices)
+        acc_dev_num_out_of_range (d, ord, num_devices);
+
+      dev += ord;
+
+      gomp_mutex_lock (&dev->lock);
+      if (dev->state == GOMP_DEVICE_UNINITIALIZED)
+        gomp_init_device (dev);
+      gomp_mutex_unlock (&dev->lock);
+
+      gomp_mutex_unlock (&acc_device_lock);
+    }
+
+  assert (dev);
+
+  propval = dev->get_property_func (dev->target_id, prop);
+
+  return propval;
+}
+
+size_t
+acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return 0;
+  else
+    return get_property_any (ord, d, prop).val;
+}
+
+ialias (acc_get_property)
+
+const char *
+acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return get_property_any (ord, d, prop).ptr;
+  else
+    return NULL;
+}
+
+ialias (acc_get_property_string)
+
 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
    if the user disables the builtin, or calls it via a pointer, we'll need this
    version.
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index bc205453f82..05ed3cd83db 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -28,7 +28,7 @@
 !  <http://www.gnu.org/licenses/>.
 
 module openacc_kinds
-  use iso_fortran_env, only: int32
+  use iso_fortran_env, only: int32, int64
   implicit none
 
   private :: int32
@@ -46,6 +46,21 @@ module openacc_kinds
   ! integer (acc_device_kind), parameter :: acc_device_host_nonshm = 3 removed.
   integer (acc_device_kind), parameter :: acc_device_not_host = 4
   integer (acc_device_kind), parameter :: acc_device_nvidia = 5
+  integer (acc_device_kind), parameter :: acc_device_current = 8
+
+  public :: acc_device_property
+
+  integer, parameter :: acc_device_property = int64
+
+  public :: acc_property_memory, acc_property_free_memory
+  public :: acc_property_name, acc_property_vendor, acc_property_driver
+
+  ! Keep in sync with include/gomp-constants.h.
+  integer (acc_device_property), parameter :: acc_property_memory = 1
+  integer (acc_device_property), parameter :: acc_property_free_memory = 2
+  integer (acc_device_property), parameter :: acc_property_name = Z'10001'
+  integer (acc_device_property), parameter :: acc_property_vendor = Z'10002'
+  integer (acc_device_property), parameter :: acc_property_driver = Z'10003'
 
   public :: acc_handle_kind
 
@@ -86,6 +101,22 @@ module openacc_internal
       integer (acc_device_kind) d
     end subroutine
 
+    function acc_get_property_h (n, d, p)
+      import
+      integer (acc_device_property) :: acc_get_property_h
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+    end function
+
+    subroutine acc_get_property_string_h (n, d, p, s)
+      import
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+      character (*) :: s
+    end subroutine
+
     function acc_get_device_num_h (d)
       import
       integer acc_get_device_num_h
@@ -511,6 +542,24 @@ module openacc_internal
       integer (c_int), value :: d
     end function
 
+    function acc_get_property_l (n, d, p) &
+        bind (C, name = "acc_get_property")
+      use iso_c_binding, only: c_int, c_size_t
+      integer (c_size_t) :: acc_get_property_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
+    function acc_get_property_string_l (n, d, p) &
+        bind (C, name = "acc_get_property_string")
+      use iso_c_binding, only: c_int, c_ptr
+      type (c_ptr) :: acc_get_property_string_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
     function acc_async_test_l (a) &
         bind (C, name = "acc_async_test")
       use iso_c_binding, only: c_int
@@ -752,6 +801,14 @@ module openacc
     procedure :: acc_get_device_num_h
   end interface
 
+  interface acc_get_property
+    procedure :: acc_get_property_h
+  end interface
+
+  interface acc_get_property_string
+    procedure :: acc_get_property_string_h
+  end interface
+
   interface acc_async_test
     procedure :: acc_async_test_h
   end interface
@@ -932,6 +989,19 @@ module openacc
 
 end module
 
+module openacc_c_string
+  implicit none
+
+  interface
+    function strlen (s) bind (C, name = "strlen")
+      use iso_c_binding, only: c_ptr, c_size_t
+      type (c_ptr), intent(in), value :: s
+      integer (c_size_t) :: strlen
+    end function
+  end interface
+
+end module
+
 function acc_get_num_devices_h (d)
   use openacc_internal, only: acc_get_num_devices_l
   use openacc_kinds
@@ -970,6 +1040,50 @@ function acc_get_device_num_h (d)
   acc_get_device_num_h = acc_get_device_num_l (d)
 end function
 
+function acc_get_property_h (n, d, p)
+  use iso_c_binding, only: c_int
+  use openacc_internal, only: acc_get_property_l
+  use openacc_kinds
+  integer (acc_device_property) :: acc_get_property_h
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+
+  integer (c_int) :: pint
+
+  pint = int (p, c_int)
+  acc_get_property_h = acc_get_property_l (n, d, pint)
+end function
+
+subroutine acc_get_property_string_h (n, d, p, s)
+  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer
+  use openacc_internal, only: acc_get_property_string_l
+  use openacc_c_string, only: strlen
+  use openacc_kinds
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+  character (*) :: s
+
+  integer (c_int) :: pint
+  type (c_ptr) :: cptr
+  integer :: clen
+  character (kind=c_char, len=1), pointer :: sptr (:)
+  integer :: slen
+  integer :: i
+
+  pint = int (p, c_int)
+  cptr = acc_get_property_string_l (n, d, pint)
+  clen = int (strlen (cptr))
+  call c_f_pointer (cptr, sptr, [clen])
+
+  s = ""
+  slen = min (clen, len (s))
+  do i = 1, slen
+    s (i:i) = sptr (i)
+  end do
+end subroutine
+
 function acc_async_test_h (a)
   use openacc_internal, only: acc_async_test_l
   logical acc_async_test_h
diff --git a/libgomp/openacc.h b/libgomp/openacc.h
index 8af3478f366..26084dc5ddd 100644
--- a/libgomp/openacc.h
+++ b/libgomp/openacc.h
@@ -57,12 +57,23 @@ typedef enum acc_device_t {
   acc_device_nvidia = 5,
   /* not supported */ _acc_device_intel_mic = 6,
   /* not supported */ _acc_device_hsa = 7,
+  acc_device_current = 8,
   _ACC_device_hwm,
   /* Ensure enumeration is layout compatible with int.  */
   _ACC_highest = __INT_MAX__,
   _ACC_neg = -1
 } acc_device_t;
 
+typedef enum acc_device_property_t {
+  /* Keep in sync with include/gomp-constants.h.  */
+  /* Start from 1 to catch uninitialized use.  */
+  acc_property_memory = 1,
+  acc_property_free_memory = 2,
+  acc_property_name = 0x10001,
+  acc_property_vendor = 0x10002,
+  acc_property_driver = 0x10003
+} acc_device_property_t;
+
 typedef enum acc_async_t {
   /* Keep in sync with include/gomp-constants.h.  */
   acc_async_noval = -1,
@@ -74,6 +85,10 @@ void acc_set_device_type (acc_device_t) __GOACC_NOTHROW;
 acc_device_t acc_get_device_type (void) __GOACC_NOTHROW;
 void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW;
 int acc_get_device_num (acc_device_t) __GOACC_NOTHROW;
+size_t acc_get_property
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
+const char *acc_get_property_string
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
 int acc_async_test (int) __GOACC_NOTHROW;
 int acc_async_test_all (void) __GOACC_NOTHROW;
 void acc_wait (int) __GOACC_NOTHROW;
diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def
index a16badcfa9d..cd91b39b1d2 100644
--- a/libgomp/plugin/cuda-lib.def
+++ b/libgomp/plugin/cuda-lib.def
@@ -8,6 +8,9 @@ CUDA_ONE_CALL (cuCtxSynchronize)
 CUDA_ONE_CALL (cuDeviceGet)
 CUDA_ONE_CALL (cuDeviceGetAttribute)
 CUDA_ONE_CALL (cuDeviceGetCount)
+CUDA_ONE_CALL (cuDeviceGetName)
+CUDA_ONE_CALL (cuDeviceTotalMem)
+CUDA_ONE_CALL (cuDriverGetVersion)
 CUDA_ONE_CALL (cuEventCreate)
 CUDA_ONE_CALL (cuEventDestroy)
 CUDA_ONE_CALL (cuEventElapsedTime)
@@ -35,6 +38,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync)
 CUDA_ONE_CALL (cuMemFree)
 CUDA_ONE_CALL (cuMemFreeHost)
 CUDA_ONE_CALL (cuMemGetAddressRange)
+CUDA_ONE_CALL (cuMemGetInfo)
 CUDA_ONE_CALL (cuMemHostGetDevicePointer)
 CUDA_ONE_CALL (cuModuleGetFunction)
 CUDA_ONE_CALL (cuModuleGetGlobal)
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index a2b9bdbeb34..3c990c52067 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -689,6 +689,32 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
+/* Part of the libgomp plugin interface.  Return the value of property
+   PROP of agent number N.  */
+
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (!init_hsa_context ())
+    return nullval;
+  if (n >= hsa_context.agent_count)
+    {
+      GOMP_PLUGIN_error
+	("Request for a property of a non-existing HSA device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "AMD" };
+    default:
+      return nullval;
+    }
+}
+
 /* Part of the libgomp plugin interface.  Initialize agent number N so that it
    can be used for computation.  Return TRUE on success.  */
 
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index b7a1a6c40f5..cb18e875a40 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -1001,6 +1001,93 @@ GOMP_OFFLOAD_get_num_devices (void)
   return nvptx_get_num_devices ();
 }
 
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value propval = { .val = 0 };
+
+  pthread_mutex_lock (&ptx_dev_lock);
+
+  if (!nvptx_init () || n >= nvptx_get_num_devices ())
+    {
+      pthread_mutex_unlock (&ptx_dev_lock);
+      return propval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_MEMORY:
+      {
+	size_t total_mem;
+	CUdevice dev;
+
+	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
+	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, dev);
+	propval.val = total_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
+      {
+	size_t total_mem;
+	size_t free_mem;
+	CUdevice ctxdev;
+	CUdevice dev;
+
+	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
+	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
+	if (dev == ctxdev)
+	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	else if (ptx_devices[n])
+	  {
+	    CUcontext old_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_devices[n]->ctx);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
+	  }
+	else
+	  {
+	    CUcontext new_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
+			    dev);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
+	  }
+	propval.val = free_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_NAME:
+      {
+	static char name[256];
+	CUdevice dev;
+
+	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
+	CUDA_CALL_ERET (propval, cuDeviceGetName, name, sizeof (name), dev);
+	propval.ptr = name;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      propval.ptr = "Nvidia";
+      break;
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      {
+	static char ver[11];
+	int v;
+
+	CUDA_CALL_ERET (propval, cuDriverGetVersion, &v);
+	snprintf (ver, sizeof (ver) - 1, "%u.%u", v / 1000, v % 1000 / 10);
+	propval.ptr = ver;
+      }
+      break;
+    default:
+      break;
+    }
+
+  pthread_mutex_unlock (&ptx_dev_lock);
+  return propval;
+}
+
 bool
 GOMP_OFFLOAD_init_device (int n)
 {
diff --git a/libgomp/target.c b/libgomp/target.c
index 62b8ee4759e..8e6b4264b72 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -3614,6 +3614,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (get_caps);
   DLSYM (get_type);
   DLSYM (get_num_devices);
+  DLSYM (get_property);
   DLSYM (init_device);
   DLSYM (fini_device);
   DLSYM (load_image);
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
new file mode 100644
index 00000000000..5bf1b849e2b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
@@ -0,0 +1,37 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions. */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+int main ()
+{
+  const char *s;
+  size_t v;
+  int r;
+
+  /* Verify that the vendor is a proper non-empty string.  */
+  s = acc_get_property_string (0, acc_device_default, acc_property_vendor);
+  r = !s || !strlen (s);
+  if (s)
+    printf ("OpenACC vendor: %s\n", s);
+
+  /* For the rest just check that they do not crash.  */
+  v = acc_get_property (0, acc_device_default, acc_property_memory);
+  if (v)
+    printf ("OpenACC total memory: %zd\n", v);
+  v = acc_get_property (0, acc_device_default, acc_property_free_memory);
+  if (v)
+    printf ("OpenACC free memory: %zd\n", v);
+  s = acc_get_property_string (0, acc_device_default, acc_property_name);
+  if (s)
+    printf ("OpenACC name: %s\n", s);
+  s = acc_get_property_string (0, acc_device_default, acc_property_driver);
+  if (s)
+    printf ("OpenACC driver: %s\n", s);
+
+  return r;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f
new file mode 100644
index 00000000000..9ffeb05148e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f
@@ -0,0 +1,33 @@
+! Test the `acc_get_property' and '`acc_get_property_string' library
+! functions.
+! { dg-do run }
+
+      USE OPENACC
+      IMPLICIT NONE
+
+      INTEGER(ACC_DEVICE_PROPERTY) V
+      CHARACTER*256 S
+      LOGICAL R
+
+      ! Verify that the vendor is a non-empty string.
+      CALL ACC_GET_PROPERTY_STRING (0, ACC_DEVICE_DEFAULT,
+     +                              ACC_PROPERTY_VENDOR, S)
+      R = S /= ""
+      IF (S /= "") PRINT "(A, A)", "OpenACC vendor: ", TRIM (S)
+
+      ! For the rest just check that they do not crash.
+      V = ACC_GET_PROPERTY (0, ACC_DEVICE_DEFAULT,
+     +                      ACC_PROPERTY_MEMORY)
+      IF (V /= 0) PRINT "(A, I0)", "OpenACC total memory: ", V
+      V = ACC_GET_PROPERTY (0, ACC_DEVICE_DEFAULT,
+     +                      ACC_PROPERTY_FREE_MEMORY)
+      IF (V /= 0) PRINT "(A, I0)", "OpenACC free memory: ", V
+      CALL ACC_GET_PROPERTY_STRING (0, ACC_DEVICE_DEFAULT,
+     +                              ACC_PROPERTY_NAME, S)
+      IF (S /= "") PRINT "(A, A)", "OpenACC name: ", TRIM (S)
+      CALL ACC_GET_PROPERTY_STRING (0, ACC_DEVICE_DEFAULT,
+     +                              ACC_PROPERTY_DRIVER, S)
+      IF (S /= "") PRINT "(A, A)", "OpenACC driver: ", TRIM (S)
+
+      IF (.NOT. R) STOP 1
+      END
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: 0001-Add-OpenACC-2.6-acc_get_property-support-restore-Int.patch --]
[-- Type: text/x-diff, Size: 2460 bytes --]

From 1fa609ba73e9990ae7a65b083047f0ee219167b3 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Tue, 8 Jan 2019 15:21:35 +0100
Subject: [PATCH] Add OpenACC 2.6 `acc_get_property' support: restore Intel MIC
 offloading

The "OpenACC 2.6 `acc_get_property' support" changes regressed the relevant
libgomp OpenMP execution test cases to no longer consider Intel MIC offloading
because of:

    libgomp: while loading libgomp-plugin-intelmic.so.1: [...]/libgomp-plugin-intelmic.so.1: undefined symbol: GOMP_OFFLOAD_get_property

	liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
	New function.
---
 liboffloadmic/ChangeLog.openacc               |  5 +++++
 .../plugin/libgomp-plugin-intelmic.cpp        | 21 +++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/liboffloadmic/ChangeLog.openacc b/liboffloadmic/ChangeLog.openacc
index 521d4490f0b..75f8ee518e4 100644
--- a/liboffloadmic/ChangeLog.openacc
+++ b/liboffloadmic/ChangeLog.openacc
@@ -1,3 +1,8 @@
+2019-01-08  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
+	New function.
+
 2019-02-26  Chung-Lin Tang  <cltang@codesourcery.com>
 
 	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_version):
diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
index d1678d0514e..ed78c8d9dd4 100644
--- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
+++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
@@ -174,6 +174,27 @@ GOMP_OFFLOAD_get_num_devices (void)
   return num_devices;
 }
 
+extern "C" union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= num_devices)
+    {
+      GOMP_PLUGIN_error
+       ("Request for a property of a non-existing Intel MIC device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = /* TODO: "error: invalid conversion from 'const void*' to 'void*' [-fpermissive]" */ (char *) "Intel" };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 offload (const char *file, uint64_t line, int device, const char *name,
 	 int num_vars, VarDesc *vars, const void **async_data)
-- 
2.17.1


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Add OpenACC 2.6 `acc_get_property' support
  2019-10-07 18:41 ` Thomas Schwinge
@ 2019-11-05 15:09   ` Harwath, Frederik
  2019-11-14 15:41   ` [PATCH] " Frederik Harwath
  1 sibling, 0 replies; 38+ messages in thread
From: Harwath, Frederik @ 2019-11-05 15:09 UTC (permalink / raw)
  To: Thomas Schwinge, Jakub Jelinek; +Cc: gcc-patches

Hi Thomas,

> On 07.10.19 20:41, Thomas Schwinge wrote:
> > On 2018-12-03T16:51:14+0000, "Maciej W. Rozycki" <macro@codesourcery.com> wrote:
> > Add generic support for the OpenACC 2.6 `acc_get_property' and
> > `acc_get_property_string' routines [...]
>
> ..., which allow for user code to query the implementation for stuff like:
>
> > OpenACC vendor: GNU
> > OpenACC name: GOMP
> > OpenACC driver: 1.0
>
> [...]
>
> > --- a/include/gomp-constants.h
> > +++ b/include/gomp-constants.h
> > @@ -215,10 +215,24 @@ enum gomp_map_kind
> >  #define GOMP_DEVICE_NVIDIA_PTX		5
> >  #define GOMP_DEVICE_INTEL_MIC		6
> >  #define GOMP_DEVICE_HSA			7
> > +#define GOMP_DEVICE_CURRENT		8
>
> This is used for 'acc_device_current', relevant only for
> 'acc_get_property', to return "the value of the property for the current
> device".  This should probably use a more special (negative?) value
> instead of eight, so that when additional real device types are added
> later on, we can just add them with increasing numbers, and keep the
> scanning code simple.

Yes, I use the first unused negative value.

> (Use of 'acc_device_current' as an argument to other functions taking an
> 'acc_device_t' is undefined, and should be rejected with 'gomp_fatal'?)

So far, there seems to be essentially no validity checking for acc_device_t
and other enums in the relevant parts of the code. I have added such checks
to public functions which take acc_device_t arguments.

> > --- a/libgomp/plugin/plugin-nvptx.c
> > +++ b/libgomp/plugin/plugin-nvptx.c
>
> > +union gomp_device_property_value
> > +GOMP_OFFLOAD_get_property (int n, int prop)
> > +{
> > +  union gomp_device_property_value propval = { .val = 0 };
> > +
> > +  pthread_mutex_lock (&ptx_dev_lock);
> > +
> > +  if (!nvptx_init () || n >= nvptx_get_num_devices ())
> > +    {
> > +      pthread_mutex_unlock (&ptx_dev_lock);
> > +      return propval;
> > +    }
>
> Isn't it implicit that 'get_num_devices' has been called while loading
> the plugin, so we don't have to do any initialization that here?  (But I
> may be misremembering that.)

Yes, a call path for nvptx_get_num_devices during initialization, in case we
are using the nvptx plugin:
acc_init (oacc_init.c) -> gomp_init_targets_once (target.c) ->
gomp_target_init (target.c) -> GOMP_OFFLOAD_get_num_devices (plugin-nvptx.c) ->
nvptx_get_num_devices

For nvptx_init, a call path is:
acc_init (oacc_init.c) -> acc_init_1 (oacc_init.c) -> gomp_init_device (oacc_init.c) ->
GOMP_OFFLOAD_init_device (plugin-nvptx.c) -> nvptx_init

Hence, yes, we should not call nvptx_init from here.


> > +  switch (prop)
> > +    {
> > +    case GOMP_DEVICE_PROPERTY_MEMORY:
> > +      {
> > +	size_t total_mem;
> > +	CUdevice dev;
> > +
> > +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
>
> Isn't that already known as 'ptx_devices[n]'?  (Likewise elsewhere.)

Yes, that gets set during GOMP_OFFLOAD_init_device.

> +	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, dev);
> +	propval.val = total_mem;
> +      }
> +      break;

> +    case GOMP_DEVICE_PROPERTY_NAME:
> +      {
> +	static char name[256];
> +	CUdevice dev;
> +
> +	CUDA_CALL_ERET (propval, cuDeviceGet, &dev, n);
> +	CUDA_CALL_ERET (propval, cuDeviceGetName, name, sizeof (name), dev);
> +	propval.ptr = name;
> +      }
> +      break;

> Uh, that's not thread-safe, is it?

Not at all.

> Otherwise, perhaps make this 'name' a property of 'struct ptx_device' in
> the nvptx plugin here, and keep it live while the device is open
> ('nvptx_open_device'), together with other per-device data?

That's what I do now.

> Is that 'snprintf' formatting the generic way to display a CUDA driver
> version number?

At least, the same formatting is applied by NVidia's deviceQuery example
from cuda-samples
(i.e. https://github.com/NVIDIA/cuda-samples/blob/master/Samples/deviceQuery/deviceQuery.cpp#L106).
For me, the output yields "CUDA Driver Version / Runtime Version 9.1 / 9.1" with
the nvidia-cuda-toolkit 9.1.


> > As, in theory, such Nvidia GPU offloading support could also be
> > implemented via the Nouveau/Mesa GalliumCompute driver, should the string
> > returned here actually include "CUDA Driver"?

This seems like a good way to disambiguate between different drivers, but I am not sure if there
are any compatibility issues that we have to consider (PGI?). The standard does not impose
any restrictions on the format of the string.


> > +    default:
> > +      break;
>
> Should this 'GOMP_PLUGIN_error' or even 'GOMP_PLUGIN_fatal'?  (Similar
> then elsewhere.)

Yes, I chose GOMP_PLUGIN_error.

> > --- /dev/null
> > +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
> > @@ -0,0 +1,37 @@
> > +/* Test the `acc_get_property' and '`acc_get_property_string' library
> > +   functions. */
> > +/* { dg-do run } */
> > +
> > +#include <openacc.h>
> > +#include <stddef.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +
> > +int main ()
> > +{
> > +  const char *s;
> > +  size_t v;
> > +  int r;
> > +
> > +  /* Verify that the vendor is a proper non-empty string.  */
> > +  s = acc_get_property_string (0, acc_device_default, acc_property_vendor);
> > +  r = !s || !strlen (s);
> > +  if (s)
> > +    printf ("OpenACC vendor: %s\n", s);
>
> Should we check the actual string returned, as defined by OpenACC/our
> implementation, as applicable?  Use '#if defined ACC_DEVICE_TYPE_[...]'.
> (See 'libgomp/testsuite/libgomp.oacc-c-c++-common/avoid-offloading-2.c',
> for example.)

Yes.

> Isn't this the "Device vendor" instead of the "OpenACC vendor"?  Similar
> for all other 'printf's?

Yes.


> These tests only use 'acc_device_default', should they also check other
> valid as well as invalid values?

That would be better.

Frederik

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-10-07 18:41 ` Thomas Schwinge
  2019-11-05 15:09   ` Harwath, Frederik
@ 2019-11-14 15:41   ` Frederik Harwath
  2019-12-16 23:06     ` Thomas Schwinge
  1 sibling, 1 reply; 38+ messages in thread
From: Frederik Harwath @ 2019-11-14 15:41 UTC (permalink / raw)
  To: gcc-patches, thomas, jakub, tdevries, mjambor

Hi,
this patch implements OpenACC 2.6 "acc_get_property" and related functions.
I have tested the patch on x86_64-linux-gnu with nvptx-none offloading.
There is no AMD GCN support yet. This will be added later on.

Can this be committed to trunk?

Best regards,
Frederik

----------------------- 8< -------------------------------------------

Add generic support for the OpenACC 2.6 `acc_get_property' and
`acc_get_property_string' routines, as well as full handlers for the
host and the NVPTX offload targets and minimal handlers for the HSA
and Intel MIC offload targets.

Included are C/C++ and Fortran tests that, in particular, print
the property values for acc_property_vendor, acc_property_memory,
acc_property_free_memory, acc_property_name, and acc_property_driver.
The output looks as follows:

Vendor: GNU
Name: GOMP
Total memory: 0
Free memory: 0
Driver: 1.0

with the host driver (where the memory related properties are not
supported for the host device and yield 0, conforming to the standard)
and output like:

OpenACC vendor: Nvidia
OpenACC total memory: 12651462656
OpenACC free memory: 12202737664
OpenACC name: TITAN V
OpenACC driver: CUDA Driver 9.1

with the NVPTX driver.

2019-11-14  Maciej W. Rozycki  <macro@codesourcery.com>
	    Frederik Harwath  <frederik@codesourcery.com>
	    Thomas Schwinge  <tschwinge@codesourcery.com>

	include/
	* gomp-constants.h (GOMP_DEVICE_CURRENT,
	GOMP_DEVICE_PROPERTY_MEMORY, GOMP_DEVICE_PROPERTY_FREE_MEMORY,
	GOMP_DEVICE_PROPERTY_NAME, GOMP_DEVICE_PROPERTY_VENDOR,
	GOMP_DEVICE_PROPERTY_DRIVER, GOMP_DEVICE_PROPERTY_STRING_MASK):
	New Macros.

	libgomp/
	* libgomp.h (gomp_device_descr): Add `get_property_func' member.
	* libgomp-plugin.h (gomp_device_property_value): New union.
	(gomp_device_property_value): New prototype.
	* openacc.h (acc_device_t): Add `acc_device_current' enumeration
	constant.
	(acc_device_property_t): New enum.
	(acc_get_property, acc_get_property_string): New prototypes.
	* oacc-init.c (acc_get_device_type): Also assert on
	`!acc_device_current' result.
	(get_property_any, acc_get_property, acc_get_property_string):
	New functions.
	* openacc.f90 (openacc_kinds): From `iso_fortran_env' also
	import `int64'.  Add `acc_device_current' and
	`acc_property_memory', `acc_property_free_memory',
	`acc_property_name', `acc_property_vendor' and
	`acc_property_driver' constants.  Add `acc_device_property' data
	type.
	(openacc_internal): Add `acc_get_property' and
	`acc_get_property_string' interfaces.  Add `acc_get_property_h',
	`acc_get_property_string_h', `acc_get_property_l' and
	`acc_get_property_string_l'.
	(openacc_c_string): New module.
	* oacc-host.c (host_get_property): New function.
	(host_dispatch): Wire it.
	* target.c (gomp_load_plugin_for_device): Handle `get_property'.
	* libgomp.map (OACC_2.6): Add `acc_get_property',
	`acc_get_property_h_', `acc_get_property_string' and
	`acc_get_property_string_h_' symbols.
	* oacc-init.c (acc_known_device_type): Add function.
	(unknown_device_type_error): Add function.
	(name_of_acc_device_t): Change to call unknown_device_type_error
	on unknown type.
	(resolve_device): Use acc_known_device_type.
	(acc_init): Fail if acc_device_t argument is not valid.
	(acc_shutdown): Likewise.
	(acc_get_num_devices): Likewise.
	(acc_set_device_type): Likewise.
	(acc_get_device_num): Likewise.
	(acc_set_device_num): Likewise.
	(get_property_any): Likewise.
	(acc_get_property): Likewise.
	(acc_get_property_string): Likewise.
	(acc_on_device): Likewise.
	(goacc_save_and_set_bind): Likewise.

	* libgomp.texi (OpenACC Runtime Library Routines): Add
	`acc_get_property'.
	(acc_get_property): New node.

	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function.
	* plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName',
	`cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo'
	calls.
	(GOMP_OFFLOAD_get_property): New function.
	(struct ptx_device): Add new field "name" ...
	(nvptx_open_device): ... and alloc and init from here.
	(nvptx_close_device): ... and free from here.
	(cuda_driver_version): Add new static variable ...
	(nvptx_init): ... and init from here.

	* testsuite/libgomp.oacc-c-c++-common/acc-get-property.c: New
	test.
	* testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c: New
	test.
	 * testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c: New
	test.
	 * testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c: New
	file with test helper functions.

	* testsuite/libgomp.oacc-fortran/acc-get-property.f90: New test.

	liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
	New function.
---
 include/gomp-constants.h                      |  14 ++
 libgomp/libgomp-plugin.h                      |   8 +
 libgomp/libgomp.h                             |   1 +
 libgomp/libgomp.map                           |   8 +
 libgomp/libgomp.texi                          |  39 +++++
 libgomp/oacc-host.c                           |  22 +++
 libgomp/oacc-init.c                           | 139 ++++++++++++++++--
 libgomp/openacc.f90                           | 116 ++++++++++++++-
 libgomp/openacc.h                             |  17 ++-
 libgomp/plugin/cuda-lib.def                   |   4 +
 libgomp/plugin/plugin-hsa.c                   |  26 ++++
 libgomp/plugin/plugin-nvptx.c                 |  85 ++++++++++-
 libgomp/target.c                              |   1 +
 .../acc-get-property-2.c                      |  68 +++++++++
 .../acc-get-property-3.c                      |  19 +++
 .../acc-get-property-aux.c                    |  60 ++++++++
 .../acc-get-property.c                        |  75 ++++++++++
 .../libgomp.oacc-fortran/acc-get-property.f90 |  80 ++++++++++
 .../plugin/libgomp-plugin-intelmic.cpp        |  22 +++
 19 files changed, 790 insertions(+), 14 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90

diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 9e356cdfeec9..150b12d0d6fd 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -178,6 +178,20 @@ enum gomp_map_kind
 
 #define GOMP_DEVICE_ICV			-1
 #define GOMP_DEVICE_HOST_FALLBACK	-2
+#define GOMP_DEVICE_CURRENT		-3
+
+/* Device property codes.  Keep in sync with
+   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t
+   as well as libgomp/libgomp-plugin.h.  */
+/* Start from 1 to catch uninitialized use.  */
+#define GOMP_DEVICE_PROPERTY_MEMORY		1
+#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
+#define GOMP_DEVICE_PROPERTY_NAME		0x10001
+#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
+#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
+
+/* Internal property mask to tell numeric and string values apart.  */
+#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
 
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED		(1 << 0)
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index 037558c43f56..5f968855f652 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -54,6 +54,13 @@ enum offload_target_type
   OFFLOAD_TARGET_TYPE_GCN = 8
 };
 
+/* Container type for passing device properties.  */
+union gomp_device_property_value
+{
+  void *ptr;
+  uintmax_t val;
+};
+
 /* Opaque type to represent plugin-dependent implementation of an
    OpenACC asynchronous queue.  */
 struct goacc_asyncqueue;
@@ -94,6 +101,7 @@ extern const char *GOMP_OFFLOAD_get_name (void);
 extern unsigned int GOMP_OFFLOAD_get_caps (void);
 extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
+extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
 extern unsigned GOMP_OFFLOAD_version (void);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index bab733d2b2da..c3f89a26532c 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1106,6 +1106,7 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
   __typeof (GOMP_OFFLOAD_get_type) *get_type_func;
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
+  __typeof (GOMP_OFFLOAD_get_property) *get_property_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index c79430f8d8d1..fba4effbb3eb 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -502,6 +502,14 @@ GOACC_2.0.1 {
 	GOACC_parallel_keyed;
 } GOACC_2.0;
 
+OACC_2.6 {
+  global:
+	acc_get_property;
+	acc_get_property_h_;
+	acc_get_property_string;
+	acc_get_property_string_h_;
+} OACC_2.5;
+
 GOMP_PLUGIN_1.0 {
   global:
 	GOMP_PLUGIN_malloc;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 6db895f62726..91afca4589d9 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -1849,6 +1849,7 @@ acceleration device.
 * acc_get_device_type::         Get type of device accelerator to be used.
 * acc_set_device_num::          Set device number to use.
 * acc_get_device_num::          Get device number to be used.
+* acc_get_property::            Get device property.
 * acc_async_test::              Tests for completion of a specific asynchronous
                                 operation.
 * acc_async_test_all::          Tests for completion of all asychronous
@@ -2038,6 +2039,44 @@ region.
 
 
 
+@node acc_get_property
+@section @code{acc_get_property} -- Get device property.
+@cindex acc_get_property
+@cindex acc_get_property_string
+@table @asis
+@item @emph{Description}
+These routines return the value of the specified @var{property} for the
+device being queried according to @var{devicenum} and @var{devicetype}.
+Integer-valued and string-valued properties are returned by
+@code{acc_get_property} and @code{acc_get_property_string} respectively.
+The Fortran @code{acc_get_property_string} subroutine returns the string
+retrieved in its fourth argument while the remaining entry points are
+functions, which pass the return value as their result.
+
+@item @emph{C/C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
+@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
+@item                   @tab @code{integer devicenum}
+@item                   @tab @code{integer(kind=acc_device_kind) devicetype}
+@item                   @tab @code{integer(kind=acc_device_property) property}
+@item                   @tab @code{integer(kind=acc_device_property) acc_get_property}
+@item                   @tab @code{character(*) string}
+@end multitable
+
+@item @emph{Reference}:
+@uref{https://www.openacc.org, OpenACC specification v2.6}, section
+3.2.6.
+@end table
+
+
+
 @node acc_async_test
 @section @code{acc_async_test} -- Test for completion of a specific asynchronous operation.
 @table @asis
diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c
index cbcac9bf7b33..70005c3656db 100644
--- a/libgomp/oacc-host.c
+++ b/libgomp/oacc-host.c
@@ -59,6 +59,27 @@ host_get_num_devices (void)
   return 1;
 }
 
+static union gomp_device_property_value
+host_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= host_get_num_devices ())
+    return nullval;
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_NAME:
+      return (union gomp_device_property_value) { .ptr = "GOMP" };
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "GNU" };
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      return (union gomp_device_property_value) { .ptr = VERSION };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 host_init_device (int n __attribute__ ((unused)))
 {
@@ -248,6 +269,7 @@ static struct gomp_device_descr host_dispatch =
     .get_caps_func = host_get_caps,
     .get_type_func = host_get_type,
     .get_num_devices_func = host_get_num_devices,
+    .get_property_func = host_get_property,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
     .version_func = host_version,
diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index e1568c535b32..5d8523cf3259 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -93,6 +93,21 @@ get_openacc_name (const char *name)
     return name;
 }
 
+
+static int
+acc_known_device_type (acc_device_t __arg)
+{
+  return __arg >= 0 && __arg < _ACC_device_hwm;
+}
+
+
+static void
+unknown_device_type_error (unsigned invalid_type)
+{
+  gomp_fatal ("unknown device type %u", invalid_type);
+}
+
+
 static const char *
 name_of_acc_device_t (enum acc_device_t type)
 {
@@ -103,8 +118,9 @@ name_of_acc_device_t (enum acc_device_t type)
     case acc_device_host: return "host";
     case acc_device_not_host: return "not_host";
     case acc_device_nvidia: return "nvidia";
-    default: gomp_fatal ("unknown device type %u", (unsigned) type);
+    default: unknown_device_type_error(type);
     }
+  return 0; /** Never reached **/
 }
 
 /* ACC_DEVICE_LOCK must be held before calling this function.  If FAIL_IS_ERROR
@@ -123,7 +139,7 @@ resolve_device (acc_device_t d, bool fail_is_error)
 	if (goacc_device_type)
 	  {
 	    /* Lookup the named device.  */
-	    while (++d != _ACC_device_hwm)
+	    while (acc_known_device_type (++d))
 	      if (dispatchers[d]
 		  && !strcasecmp (goacc_device_type,
 				  get_openacc_name (dispatchers[d]->name))
@@ -147,7 +163,7 @@ resolve_device (acc_device_t d, bool fail_is_error)
 
     case acc_device_not_host:
       /* Find the first available device after acc_device_not_host.  */
-      while (++d != _ACC_device_hwm)
+      while (acc_known_device_type (++d))
 	if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
 	  goto found;
       if (d_arg == acc_device_default)
@@ -168,7 +184,7 @@ resolve_device (acc_device_t d, bool fail_is_error)
       break;
 
     default:
-      if (d > _ACC_device_hwm)
+      if (!acc_known_device_type (d))
 	{
 	  if (fail_is_error)
 	    goto unsupported_device;
@@ -328,7 +344,6 @@ acc_shutdown_1 (acc_device_t d)
       gomp_unload_device (acc_dev);
       gomp_mutex_unlock (&acc_dev->lock);
     }
-  
   gomp_mutex_lock (&goacc_thread_lock);
 
   /* Free target-specific TLS data and close all devices.  */
@@ -494,7 +509,6 @@ goacc_attach_host_thread_to_device (int ord)
   thr->api_info = NULL;
   /* Initially, all callbacks for all events are enabled.  */
   thr->prof_callbacks_enabled = true;
-
   thr->target_tls
     = acc_dev->openacc.create_thread_data_func (ord);
 }
@@ -505,12 +519,15 @@ goacc_attach_host_thread_to_device (int ord)
 void
 acc_init (acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
   gomp_init_targets_once ();
 
   gomp_mutex_lock (&acc_device_lock);
   cached_base_dev = acc_init_1 (d, acc_construct_runtime_api, 0);
   gomp_mutex_unlock (&acc_device_lock);
-  
+
   goacc_attach_host_thread_to_device (-1);
 }
 
@@ -519,6 +536,9 @@ ialias (acc_init)
 void
 acc_shutdown (acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
   gomp_init_targets_once ();
 
   gomp_mutex_lock (&acc_device_lock);
@@ -533,6 +553,9 @@ ialias (acc_shutdown)
 int
 acc_get_num_devices (acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
   int n = 0;
   struct gomp_device_descr *acc_dev;
 
@@ -564,6 +587,9 @@ ialias (acc_get_num_devices)
 void
 acc_set_device_type (acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
   struct gomp_device_descr *base_dev, *acc_dev;
   struct goacc_thread *thr = goacc_thread ();
 
@@ -637,7 +663,8 @@ acc_get_device_type (void)
     }
 
   assert (res != acc_device_default
-	  && res != acc_device_not_host);
+	  && res != acc_device_not_host
+	  && res != acc_device_current);
 
   return res;
 }
@@ -647,12 +674,12 @@ ialias (acc_get_device_type)
 int
 acc_get_device_num (acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
   const struct gomp_device_descr *dev;
   struct goacc_thread *thr = goacc_thread ();
 
-  if (d >= _ACC_device_hwm)
-    gomp_fatal ("unknown device type %u", (unsigned) d);
-
   acc_prof_info prof_info;
   acc_api_info api_info;
   bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
@@ -682,6 +709,9 @@ ialias (acc_get_device_num)
 void
 acc_set_device_num (int ord, acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
   struct gomp_device_descr *base_dev, *acc_dev;
   int num_devices;
 
@@ -723,6 +753,87 @@ acc_set_device_num (int ord, acc_device_t d)
 
 ialias (acc_set_device_num)
 
+static union gomp_device_property_value
+get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
+  union gomp_device_property_value propval;
+  struct gomp_device_descr *dev;
+  struct goacc_thread *thr;
+
+  if (d == acc_device_none)
+    return (union gomp_device_property_value) { .val = 0 };
+
+  goacc_lazy_initialize ();
+  thr = goacc_thread ();
+
+  if (d == acc_device_current && (!thr || !thr->dev))
+    return (union gomp_device_property_value) { .val = 0 };
+
+  if (d == acc_device_current)
+    {
+      dev = thr->dev;
+    }
+  else
+    {
+      int num_devices;
+
+      gomp_mutex_lock (&acc_device_lock);
+
+      dev = resolve_device (d, false);
+
+      num_devices = dev->get_num_devices_func ();
+
+      if (num_devices <= 0 || ord >= num_devices)
+        acc_dev_num_out_of_range (d, ord, num_devices);
+
+      dev += ord;
+
+      gomp_mutex_lock (&dev->lock);
+      if (dev->state == GOMP_DEVICE_UNINITIALIZED)
+        gomp_init_device (dev);
+      gomp_mutex_unlock (&dev->lock);
+
+      gomp_mutex_unlock (&acc_device_lock);
+    }
+
+  assert (dev);
+
+  propval = dev->get_property_func (dev->target_id, prop);
+
+  return propval;
+}
+
+size_t
+acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return 0;
+  else
+    return get_property_any (ord, d, prop).val;
+}
+
+ialias (acc_get_property)
+
+const char *
+acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return get_property_any (ord, d, prop).ptr;
+  else
+    return NULL;
+}
+
+ialias (acc_get_property_string)
+
 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
    if the user disables the builtin, or calls it via a pointer, we'll need this
    version.
@@ -733,6 +844,9 @@ ialias (acc_set_device_num)
 int __attribute__ ((__optimize__ ("O2")))
 acc_on_device (acc_device_t dev)
 {
+  if (!acc_known_device_type (dev))
+    unknown_device_type_error(dev);
+
   return __builtin_acc_on_device (dev);
 }
 
@@ -763,6 +877,9 @@ goacc_runtime_initialize (void)
 attribute_hidden void
 goacc_save_and_set_bind (acc_device_t d)
 {
+  if (!acc_known_device_type (d))
+    unknown_device_type_error (d);
+
   struct goacc_thread *thr = goacc_thread ();
 
   assert (!thr->saved_bound_dev);
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index 831a157e703d..f574c7e31a8c 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -28,7 +28,7 @@
 !  <http://www.gnu.org/licenses/>.
 
 module openacc_kinds
-  use iso_fortran_env, only: int32
+  use iso_fortran_env, only: int32, int64
   implicit none
 
   private :: int32
@@ -47,6 +47,21 @@ module openacc_kinds
   integer (acc_device_kind), parameter :: acc_device_not_host = 4
   integer (acc_device_kind), parameter :: acc_device_nvidia = 5
   integer (acc_device_kind), parameter :: acc_device_gcn = 8
+  integer (acc_device_kind), parameter :: acc_device_current = -3
+
+  public :: acc_device_property
+
+  integer, parameter :: acc_device_property = int64
+
+  public :: acc_property_memory, acc_property_free_memory
+  public :: acc_property_name, acc_property_vendor, acc_property_driver
+
+  ! Keep in sync with include/gomp-constants.h.
+  integer (acc_device_property), parameter :: acc_property_memory = 1
+  integer (acc_device_property), parameter :: acc_property_free_memory = 2
+  integer (acc_device_property), parameter :: acc_property_name = int(Z'10001')
+  integer (acc_device_property), parameter :: acc_property_vendor = int(Z'10002')
+  integer (acc_device_property), parameter :: acc_property_driver = int(Z'10003')
 
   public :: acc_handle_kind
 
@@ -87,6 +102,24 @@ module openacc_internal
       integer (acc_device_kind) d
     end subroutine
 
+    function acc_get_property_h (n, d, p)
+      import
+      implicit none (type, external)
+      integer (acc_device_property) :: acc_get_property_h
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+    end function
+
+    subroutine acc_get_property_string_h (n, d, p, s)
+      import
+      implicit none (type, external)
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+      character (*) :: s
+    end subroutine
+
     function acc_get_device_num_h (d)
       import
       integer acc_get_device_num_h
@@ -512,6 +545,26 @@ module openacc_internal
       integer (c_int), value :: d
     end function
 
+    function acc_get_property_l (n, d, p) &
+        bind (C, name = "acc_get_property")
+      use iso_c_binding, only: c_int, c_size_t
+      implicit none (type, external)
+      integer (c_size_t) :: acc_get_property_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
+    function acc_get_property_string_l (n, d, p) &
+        bind (C, name = "acc_get_property_string")
+      use iso_c_binding, only: c_int, c_ptr
+      implicit none (type, external)
+      type (c_ptr) :: acc_get_property_string_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
     function acc_async_test_l (a) &
         bind (C, name = "acc_async_test")
       use iso_c_binding, only: c_int
@@ -753,6 +806,14 @@ module openacc
     procedure :: acc_get_device_num_h
   end interface
 
+  interface acc_get_property
+    procedure :: acc_get_property_h
+  end interface
+
+  interface acc_get_property_string
+    procedure :: acc_get_property_string_h
+  end interface
+
   interface acc_async_test
     procedure :: acc_async_test_h
   end interface
@@ -971,6 +1032,59 @@ function acc_get_device_num_h (d)
   acc_get_device_num_h = acc_get_device_num_l (d)
 end function
 
+function acc_get_property_h (n, d, p)
+  use iso_c_binding, only: c_int
+  use openacc_internal, only: acc_get_property_l
+  use openacc_kinds
+  implicit none (type, external)
+  integer (acc_device_property) :: acc_get_property_h
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+
+  integer (c_int) :: pint
+
+  pint = int (p, c_int)
+  acc_get_property_h = acc_get_property_l (n, d, pint)
+end function
+
+subroutine acc_get_property_string_h (n, d, p, s)
+  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer
+  use openacc_internal, only: acc_get_property_string_l
+  use openacc_kinds
+  implicit none (type, external)
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+  character (*) :: s
+
+  integer (c_int) :: pint
+  type (c_ptr) :: cptr
+  integer :: clen
+  character (kind=c_char, len=1), pointer, contiguous :: sptr (:)
+  integer :: slen
+  integer :: i
+
+  interface
+     function strlen (s) bind (C, name = "strlen")
+       use iso_c_binding, only: c_ptr, c_size_t
+       type (c_ptr), intent(in), value :: s
+       integer (c_size_t) :: strlen
+     end function strlen
+  end interface
+
+  pint = int (p, c_int)
+  cptr = acc_get_property_string_l (n, d, pint)
+  clen = int (strlen (cptr))
+  call c_f_pointer (cptr, sptr, [clen])
+
+  s = ""
+  slen = min (clen, len (s))
+  do i = 1, slen
+    s (i:i) = sptr (i)
+  end do
+end subroutine
+
 function acc_async_test_h (a)
   use openacc_internal, only: acc_async_test_l
   logical acc_async_test_h
diff --git a/libgomp/openacc.h b/libgomp/openacc.h
index 42c861caabf7..49340b7fb6d4 100644
--- a/libgomp/openacc.h
+++ b/libgomp/openacc.h
@@ -59,9 +59,20 @@ typedef enum acc_device_t {
   _ACC_device_hwm,
   /* Ensure enumeration is layout compatible with int.  */
   _ACC_highest = __INT_MAX__,
-  _ACC_neg = -1
+  _ACC_neg = -1,
+  acc_device_current = -3
 } acc_device_t;
 
+typedef enum acc_device_property_t {
+  /* Keep in sync with include/gomp-constants.h.  */
+  /* Start from 1 to catch uninitialized use.  */
+  acc_property_memory = 1,
+  acc_property_free_memory = 2,
+  acc_property_name = 0x10001,
+  acc_property_vendor = 0x10002,
+  acc_property_driver = 0x10003
+} acc_device_property_t;
+
 typedef enum acc_async_t {
   /* Keep in sync with include/gomp-constants.h.  */
   acc_async_noval = -1,
@@ -73,6 +84,10 @@ void acc_set_device_type (acc_device_t) __GOACC_NOTHROW;
 acc_device_t acc_get_device_type (void) __GOACC_NOTHROW;
 void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW;
 int acc_get_device_num (acc_device_t) __GOACC_NOTHROW;
+size_t acc_get_property
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
+const char *acc_get_property_string
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
 int acc_async_test (int) __GOACC_NOTHROW;
 int acc_async_test_all (void) __GOACC_NOTHROW;
 void acc_wait (int) __GOACC_NOTHROW;
diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def
index a16badcfa9de..cd91b39b1d27 100644
--- a/libgomp/plugin/cuda-lib.def
+++ b/libgomp/plugin/cuda-lib.def
@@ -8,6 +8,9 @@ CUDA_ONE_CALL (cuCtxSynchronize)
 CUDA_ONE_CALL (cuDeviceGet)
 CUDA_ONE_CALL (cuDeviceGetAttribute)
 CUDA_ONE_CALL (cuDeviceGetCount)
+CUDA_ONE_CALL (cuDeviceGetName)
+CUDA_ONE_CALL (cuDeviceTotalMem)
+CUDA_ONE_CALL (cuDriverGetVersion)
 CUDA_ONE_CALL (cuEventCreate)
 CUDA_ONE_CALL (cuEventDestroy)
 CUDA_ONE_CALL (cuEventElapsedTime)
@@ -35,6 +38,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync)
 CUDA_ONE_CALL (cuMemFree)
 CUDA_ONE_CALL (cuMemFreeHost)
 CUDA_ONE_CALL (cuMemGetAddressRange)
+CUDA_ONE_CALL (cuMemGetInfo)
 CUDA_ONE_CALL (cuMemHostGetDevicePointer)
 CUDA_ONE_CALL (cuModuleGetFunction)
 CUDA_ONE_CALL (cuModuleGetGlobal)
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index 409e138aaca3..491ea5769b90 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
+/* Part of the libgomp plugin interface.  Return the value of property
+   PROP of agent number N.  */
+
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (!init_hsa_context ())
+    return nullval;
+  if (n >= hsa_context.agent_count)
+    {
+      GOMP_PLUGIN_error
+	("Request for a property of a non-existing HSA device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "AMD" };
+    default:
+      return nullval;
+    }
+}
+
 /* Part of the libgomp plugin interface.  Initialize agent number N so that it
    can be used for computation.  Return TRUE on success.  */
 
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index 911d0f66a6e4..0e9f9ff69ba8 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -284,7 +284,7 @@ struct ptx_device
   bool map;
   bool concur;
   bool mkern;
-  int  mode;
+  int mode;
   int clock_khz;
   int num_sms;
   int regs_per_block;
@@ -293,6 +293,7 @@ struct ptx_device
   int max_threads_per_block;
   int max_threads_per_multiprocessor;
   int default_dims[GOMP_DIM_MAX];
+  char* name;
 
   struct ptx_image_data *images;  /* Images loaded on device.  */
   pthread_mutex_t image_lock;     /* Lock for above list.  */
@@ -304,6 +305,7 @@ struct ptx_device
 };
 
 static struct ptx_device **ptx_devices;
+static char cuda_driver_version[30];
 
 static inline struct nvptx_thread *
 nvptx_thread (void)
@@ -330,6 +332,12 @@ nvptx_init (void)
   CUDA_CALL (cuDeviceGetCount, &ndevs);
   ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *)
 					    * ndevs);
+
+  int v;
+  CUDA_CALL_ERET (NULL, cuDriverGetVersion, &v);
+  snprintf (cuda_driver_version, sizeof (cuda_driver_version) - 1,
+	    "CUDA Driver %u.%u", v / 1000, v % 1000 / 10);
+
   return true;
 }
 
@@ -491,6 +499,10 @@ nvptx_open_device (int n)
   for (int i = 0; i != GOMP_DIM_MAX; i++)
     ptx_dev->default_dims[i] = 0;
 
+  const int max_name_len = 256;
+  ptx_dev->name = GOMP_PLUGIN_malloc(max_name_len);
+  CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, max_name_len, dev);
+
   ptx_dev->images = NULL;
   pthread_mutex_init (&ptx_dev->image_lock, NULL);
 
@@ -520,6 +532,7 @@ nvptx_close_device (struct ptx_device *ptx_dev)
   if (!ptx_dev->ctx_shared)
     CUDA_CALL (cuCtxDestroy, ptx_dev->ctx);
 
+  free (ptx_dev->name);
   free (ptx_dev);
   return true;
 }
@@ -1104,6 +1117,76 @@ GOMP_OFFLOAD_get_num_devices (void)
   return nvptx_get_num_devices ();
 }
 
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value propval = { .val = 0 };
+
+  pthread_mutex_lock (&ptx_dev_lock);
+
+  if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
+    {
+      pthread_mutex_unlock (&ptx_dev_lock);
+      return propval;
+    }
+
+  struct ptx_device *ptx_dev = ptx_devices[n];
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_MEMORY:
+      {
+	size_t total_mem;
+
+	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
+	propval.val = total_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
+      {
+	size_t total_mem;
+	size_t free_mem;
+	CUdevice ctxdev;
+
+	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
+	if (ptx_dev->dev == ctxdev)
+	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	else if (ptx_dev->ctx)
+	  {
+	    CUcontext old_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
+	  }
+	else
+	  {
+	    CUcontext new_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
+			    ptx_dev->dev);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
+	  }
+	propval.val = free_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_NAME:
+      propval.ptr = ptx_dev->name;
+      break;
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      propval.ptr = "Nvidia";
+      break;
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      propval.ptr = cuda_driver_version;
+      break;
+    default:
+      GOMP_PLUGIN_error("Unknown OpenACC device-property");
+    }
+
+  pthread_mutex_unlock (&ptx_dev_lock);
+  return propval;
+}
+
 bool
 GOMP_OFFLOAD_init_device (int n)
 {
diff --git a/libgomp/target.c b/libgomp/target.c
index 84d6daa76ca8..ffd689a9afe7 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -2752,6 +2752,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (get_caps);
   DLSYM (get_type);
   DLSYM (get_num_devices);
+  DLSYM (get_property);
   DLSYM (init_device);
   DLSYM (fini_device);
   DLSYM (load_image);
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
new file mode 100644
index 000000000000..b97eef7777ee
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
@@ -0,0 +1,68 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions on Nvidia devices by comparing property values with
+   those obtained through the CUDA API. */
+/* { dg-additional-sources acc-get-property-aux.c } */
+/* { dg-additional-options "-lcuda -lcudart" } */
+/* { dg-do run { target openacc_nvidia_accel_selected } } */
+
+#include <openacc.h>
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+#include <string.h>
+#include <stdio.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+int main ()
+{
+  int dev_count;
+  cudaGetDeviceCount (&dev_count);
+
+  for (int dev_num = 0; dev_num < dev_count; ++dev_num)
+    {
+      if (cudaSetDevice (dev_num) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaSetDevice failed.\n");
+	  abort ();
+	}
+
+      printf("Checking device %d\n", dev_num);
+
+      const char *vendor = "Nvidia";
+      size_t free_mem;
+      size_t total_mem;
+      if (cudaMemGetInfo(&free_mem, &total_mem) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaMemGetInfo failed.\n");
+	  abort ();
+	}
+
+      struct cudaDeviceProp p;
+      if (cudaGetDeviceProperties(&p, dev_num) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaGetDeviceProperties failed.\n");
+	  abort ();
+	}
+
+      int driver_version;
+      if (cudaDriverGetVersion(&driver_version) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaDriverGetVersion failed.\n");
+	  abort ();
+	}
+      /* The version string should contain the version of the CUDA Toolkit
+      	 in the same MAJOR.MINOR format that is used by Nvidia.
+      	 The format string below is the same that is used by the deviceQuery
+      	 program, which belongs to Nvidia's CUDA samples, to print the version. */
+      char *driver = malloc(sizeof(char) * 40);
+      snprintf (driver, 40, "CUDA Driver %u.%u", driver_version / 1000,
+		driver_version % 1000 / 10);
+
+      expect_device_properties(acc_device_nvidia, dev_num,
+			       total_mem, free_mem, vendor, p.name, driver);
+    }
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c
new file mode 100644
index 000000000000..1a8dca6193b7
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c
@@ -0,0 +1,19 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions for the host device. */
+/* { dg-additional-sources acc-get-property-aux.c } */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stdio.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+int main()
+{
+  printf ("Checking acc_device_host device properties\n");
+  expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0");
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c
new file mode 100644
index 000000000000..5540b91f8427
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c
@@ -0,0 +1,60 @@
+/* Auxiliary functions for acc_get_property tests */
+/* { dg-do compile  { target skip-all-targets } } */
+
+#include <openacc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver)
+{
+  const char *vendor = acc_get_property_string (dev_num, dev_type,
+						acc_property_vendor);
+  if (strcmp (vendor, expected_vendor))
+    {
+      fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
+	       "but was \"%s\".\n", expected_vendor, vendor);
+      abort ();
+    }
+
+  int total_mem = acc_get_property (dev_num, dev_type,
+				    acc_property_memory);
+  if (total_mem != expected_total_mem)
+    {
+      fprintf (stderr, "Expected acc_property_memory to equal %d, "
+	       "but was %d.\n", expected_total_mem, total_mem);
+      abort ();
+
+    }
+
+  int free_mem = acc_get_property (dev_num, dev_type,
+				   acc_property_free_memory);
+  if (free_mem != expected_free_mem)
+    {
+      fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
+	       "but was %d.\n", expected_free_mem, free_mem);
+      abort ();
+    }
+
+  const char *name = acc_get_property_string (dev_num, dev_type,
+					      acc_property_name);
+  if (strcmp (name, expected_name))
+    {
+      fprintf(stderr, "Expected acc_property_name to equal \"%s\", "
+	      "but was \"%s\".\n", expected_name, name);
+      abort ();
+    }
+
+  const char *driver = acc_get_property_string (dev_num, dev_type,
+						acc_property_driver);
+  if (strcmp (expected_driver, driver))
+    {
+      fprintf (stderr, "Expected acc_property_driver to equal %s, "
+	       "but was %s.\n", expected_driver, driver);
+      abort ();
+    }
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
new file mode 100644
index 000000000000..e9a86860f45d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
@@ -0,0 +1,75 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions by printing the results of those functions for all devices
+   of all device types mentioned in the OpenACC standard.
+
+   See also acc-get-property.f90. */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Print the values of the properties of all devices of the given type
+   and do basic device independent validation. */
+
+void
+print_device_properties(acc_device_t type)
+{
+  const char *s;
+  size_t v;
+
+  int dev_count = acc_get_num_devices(type);
+
+  for (int i = 0; i < dev_count; ++i)
+    {
+      printf("  Device %d:\n", i+1);
+
+      s = acc_get_property_string (i, type, acc_property_vendor);
+      printf ("    Vendor: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_vendor should not be null or empty.\n");
+	  abort ();
+	}
+
+      v = acc_get_property (i, type,  acc_property_memory);
+      printf ("    Total memory: %zd\n", v);
+
+      v = acc_get_property (i, type, acc_property_free_memory);
+      printf ("    Free memory: %zd\n", v);
+
+      s = acc_get_property_string (i, type, acc_property_name);
+      printf ("    Name: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_name should not be null or empty.\n");
+	  abort ();
+	}
+
+      s = acc_get_property_string (i, type, acc_property_driver);
+      printf ("    Driver: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_string should not be null or empty.\n");
+	  abort ();
+	}
+    }
+}
+
+int main ()
+{
+  printf("acc_device_none:\n");
+  /* For completness; not expected to print anything since there
+     should be no devices of this type. */
+  print_device_properties(acc_device_none);
+
+  printf("acc_device_default:\n");
+  print_device_properties(acc_device_default);
+
+  printf("acc_device_host:\n");
+  print_device_properties(acc_device_host);
+
+  printf("acc_device_not_host:\n");
+  print_device_properties(acc_device_not_host);
+}
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90
new file mode 100644
index 000000000000..71239cd0c7c2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90
@@ -0,0 +1,80 @@
+! Test the `acc_get_property' and '`acc_get_property_string' library
+! functions by printing the results of those functions for all devices
+! of all device types mentioned in the OpenACC standard.
+!
+! See also acc-get-property.c
+! { dg-do run }
+
+program test
+  use openacc
+  implicit none
+
+  print *, "acc_device_none:"
+  ! For completeness; not expected to print anything
+  call print_device_properties (acc_device_none)
+
+  print *, "acc_device_default:"
+  call print_device_properties (acc_device_default)
+
+  print *, "acc_device_host:"
+  call print_device_properties (acc_device_host)
+
+  print *, "acc_device_not_host:"
+  call print_device_properties (acc_device_not_host)
+end program test
+
+! Print the values of the properties of all devices of the given type
+! and do basic device independent validation.
+subroutine print_device_properties (device_type)
+  use openacc
+  implicit none
+
+  integer, intent(in) :: device_type
+
+  integer :: device_count
+  integer :: device
+  integer(acc_device_property) :: v
+  character*256 :: s
+
+  device_count = acc_get_num_devices(device_type)
+
+  do device = 0, device_count - 1
+     print "(a, i0)", "  Device ", device
+
+     call acc_get_property_string (device, device_type, acc_property_vendor, s)
+     print "(a, a)", "    Vendor: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_vendor should not be empty."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, acc_property_memory)
+     print "(a, i0)", "    Total memory: ", v
+     if (v < 0) then
+        print *, "acc_property_memory should not be negative."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, acc_property_free_memory)
+     print "(a, i0)", "    Free memory: ", v
+     if (v < 0) then
+        print *, "acc_property_free_memory should not to be negative."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, acc_property_name, s)
+     print "(a, a)", "    Name: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_name should not be empty."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, acc_property_driver, s)
+     print "(a, a)", "    Driver: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_driver should not be empty."
+        stop 1
+     end if
+
+  end do
+end subroutine print_device_properties
diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
index d1678d0514e9..e3c60ad7f1fe 100644
--- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
+++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
@@ -174,6 +174,28 @@ GOMP_OFFLOAD_get_num_devices (void)
   return num_devices;
 }
 
+extern "C" union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= num_devices)
+    {
+      GOMP_PLUGIN_error
+       ("Request for a property of a non-existing Intel MIC device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      /* TODO: "error: invalid conversion from 'const void*' to 'void*' [-fpermissive]" */
+      return (union gomp_device_property_value) { .ptr =  (char *) "Intel" };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 offload (const char *file, uint64_t line, int device, const char *name,
 	 int num_vars, VarDesc *vars, const void **async_data)
-- 
2.17.1

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-11-14 15:41   ` [PATCH] " Frederik Harwath
@ 2019-12-16 23:06     ` Thomas Schwinge
  2019-12-17  9:39       ` Martin Jambor
                         ` (3 more replies)
  0 siblings, 4 replies; 38+ messages in thread
From: Thomas Schwinge @ 2019-12-16 23:06 UTC (permalink / raw)
  To: Frederik Harwath
  Cc: gcc-patches, jakub, tdevries, mjambor, Andrew Stubbs,
	Julian Brown, Tobias Burnus


[-- Attachment #1.1: Type: text/plain, Size: 21448 bytes --]

Hi Frederik!

On 2019-11-14T16:35:31+0100, Frederik Harwath <frederik@codesourcery.com> wrote:
> this patch implements OpenACC 2.6 "acc_get_property" and related functions.

I'm attaching a version rebased on top of current GCC trunk, as well as
an incremental patch; please review these changes, and merge into yours.


> There is no AMD GCN support yet. This will be added later on.

ACK, just to note that there now is a 'libgomp/plugin/plugin-gcn.c' that
at least needs to get a stub implementation (can mostly copy from
'libgomp/plugin/plugin-hsa.c'?) as otherwise the build will fail.


Tobias has generally reviewed the Fortran bits, correct?


As I mentioned before ("thinking aloud"):

| Before Frederik starts working on integrating this into GCC trunk, do you
| (Jakub) agree with the libgomp plugin interface changes as implemented by
| Maciej?  For example, top-level 'GOMP_OFFLOAD_get_property' function in
| 'struct gomp_device_descr' instead of stuffing this into its
| 'acc_dispatch_t openacc'.  (I never understood why the OpenACC functions
| need to be segregated like they are.)

Jakub didn't answer, but I now myself decided that we should group this
with the other OpenACC libgomp-plugin functions, as this interface is
defined in terms of OpenACC-specific stuff such as 'acc_device_t'.
Frederik, please work on that, also try to move function definitions etc.
into appropriate places in case they aren't; ask if you need help.


> Add generic support for the OpenACC 2.6 `acc_get_property' and
> `acc_get_property_string' routines, as well as full handlers for the
> host and the NVPTX offload targets and minimal handlers for the HSA
> and Intel MIC offload targets.
>
> Included are C/C++ and Fortran tests that, in particular, print
> the property values for acc_property_vendor, acc_property_memory,
> acc_property_free_memory, acc_property_name, and acc_property_driver.
> The output looks as follows:
>
> Vendor: GNU
> Name: GOMP
> Total memory: 0
> Free memory: 0
> Driver: 1.0
>
> with the host driver (where the memory related properties are not
> supported for the host device and yield 0, conforming to the standard)
> and output like:
>
> OpenACC vendor: Nvidia
> OpenACC total memory: 12651462656
> OpenACC free memory: 12202737664
> OpenACC name: TITAN V
> OpenACC driver: CUDA Driver 9.1
>
> with the NVPTX driver.

That needs to be updated.


>  .../acc-get-property-2.c                      |  68 +++++++++
>  .../acc-get-property-3.c                      |  19 +++
>  .../acc-get-property-aux.c                    |  60 ++++++++
>  .../acc-get-property.c                        |  75 ++++++++++
>  .../libgomp.oacc-fortran/acc-get-property.f90 |  80 ++++++++++

Please name all these 'acc_get_property*', which is the name of the
interface tested.


> --- a/include/gomp-constants.h
> +++ b/include/gomp-constants.h
> @@ -178,6 +178,20 @@ enum gomp_map_kind
>  
>  #define GOMP_DEVICE_ICV			-1
>  #define GOMP_DEVICE_HOST_FALLBACK	-2
> +#define GOMP_DEVICE_CURRENT		-3

As I mentioned before ("thinking aloud"):

| This is used for 'acc_device_current', relevant only for
| 'acc_get_property', to return "the value of the property for the current
| device".  This [now has a] special (negative?) value
| [...], so that when additional real device types are added
| later on, we can just add them with increasing numbers, and keep the
| scanning code simple.

Not should if this should be grouped with 'GOMP_DEVICE_ICV',
'GOMP_DEVICE_HOST_FALLBACK', for it is not related to there.

Should this actually get value '-1' instead of '-3'?  Or, is the OpenACC
'acc_device_t' code already paying special attention to negative values
'-1', '-2'?  (I don't think so.)

| (Use of 'acc_device_current' as an argument to other functions taking an
| 'acc_device_t' is undefined, and should be rejected with 'gomp_fatal'?)

That should now be implemented; r278937 "Validate acc_device_t uses".

| Also, 'acc_device_current' is a libgomp-internal thing (doesn't interface
| with the compiler proper), so strictly speaking 'GOMP_DEVICE_CURRENT'
| isn't needed in 'include/gomp-constants.h'.  But probably still a good
| idea to list it there, in this canonical place, to keep the several lists
| of device types coherent.

I still wonder about that...  ;-)

| (I have not checked how 'acc_device_current' is actually implemented in
| the following.)

> +/* Device property codes.  Keep in sync with
> +   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t

| Same thing, libgomp-internal, not sure whether to list these here?

> +   as well as libgomp/libgomp-plugin.h.  */

(Not sure why 'libgomp/libgomp-plugin.h' is relevant here?)

> +/* Start from 1 to catch uninitialized use.  */

| Hmm, not sure about that either.  Don't think we're generally doing that?
|
| (But I see PGI have 'acc_property_none = 0', oh well.)

> +#define GOMP_DEVICE_PROPERTY_MEMORY		1
> +#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
> +#define GOMP_DEVICE_PROPERTY_NAME		0x10001
> +#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
> +#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
> +
> +/* Internal property mask to tell numeric and string values apart.  */
> +#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000

(Maybe should use an 'enum'?)

Maybe this stuff should move from 'include/gomp-constants.h' to
'libgomp/oacc-int.h'.  I'll think about that again, when I'm awake again
tomorrow.  ;-)


> --- a/libgomp/libgomp-plugin.h
> +++ b/libgomp/libgomp-plugin.h
> @@ -54,6 +54,13 @@ enum offload_target_type
>    OFFLOAD_TARGET_TYPE_GCN = 8
>  };
>  
> +/* Container type for passing device properties.  */
> +union gomp_device_property_value
> +{
> +  void *ptr;
> +  uintmax_t val;
> +};

Why wouldn't that be 'size_t', 'const char *', as the actual data types
used?  (Maybe I'm missing something.)


> --- a/libgomp/libgomp.map
> +++ b/libgomp/libgomp.map
> @@ -502,6 +502,14 @@ GOACC_2.0.1 {
>  	GOACC_parallel_keyed;
>  } GOACC_2.0;
>  
> +OACC_2.6 {
> +  global:
> +	acc_get_property;
> +	acc_get_property_h_;
> +	acc_get_property_string;
> +	acc_get_property_string_h_;
> +} OACC_2.5;
> +
>  GOMP_PLUGIN_1.0 {
>    global:
>  	GOMP_PLUGIN_malloc;

That's not correct: 'OACC_2.6' should come after 'OACC_2.5.1', and
also inherit from that one.


> --- a/libgomp/oacc-init.c
> +++ b/libgomp/oacc-init.c

> +static union gomp_device_property_value
> +get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
> +{
> +  if (!acc_known_device_type (d))
> +    unknown_device_type_error(d);

Checking isn't needed here for this is an internal interface?

> +
> +  union gomp_device_property_value propval;
> +  struct gomp_device_descr *dev;
> +  struct goacc_thread *thr;

Generally, in new code, we try to place these next to their first use.

> +
> +  if (d == acc_device_none)
> +    return (union gomp_device_property_value) { .val = 0 };
> +
> +  goacc_lazy_initialize ();
> +  thr = goacc_thread ();
> +
> +  if (d == acc_device_current && (!thr || !thr->dev))
> +    return (union gomp_device_property_value) { .val = 0 };

Should we use a 'nullval' here, as used elsewhere?

Also, this checking seems a bit convoluted; shouldn't this be integrated
into the following?  It's certainly not necessary to special-case
'acc_device_none' before 'goacc_lazy_initialize' etc.?

> +
> +  if (d == acc_device_current)
> +    {
> +      dev = thr->dev;
> +    }
> +  else
> +    {
> +      int num_devices;
> +
> +      gomp_mutex_lock (&acc_device_lock);
> +
> +      dev = resolve_device (d, false);

Why call this without 'fail_is_error' flag here?

> +
> +      num_devices = dev->get_num_devices_func ();
> +
> +      if (num_devices <= 0 || ord >= num_devices)
> +        acc_dev_num_out_of_range (d, ord, num_devices);
> +
> +      dev += ord;
> +
> +      gomp_mutex_lock (&dev->lock);
> +      if (dev->state == GOMP_DEVICE_UNINITIALIZED)
> +        gomp_init_device (dev);
> +      gomp_mutex_unlock (&dev->lock);
> +
> +      gomp_mutex_unlock (&acc_device_lock);
> +    }
> +
> +  assert (dev);
> +
> +  propval = dev->get_property_func (dev->target_id, prop);
> +
> +  return propval;
> +}

I'll have to look at this again, tomorrow.


> --- a/libgomp/openacc.f90
> +++ b/libgomp/openacc.f90
> @@ -28,7 +28,7 @@
>  !  <http://www.gnu.org/licenses/>.
>  
>  module openacc_kinds
> -  use iso_fortran_env, only: int32
> +  use iso_fortran_env, only: int32, int64
>    implicit none
>  
>    private :: int32
> @@ -47,6 +47,21 @@ module openacc_kinds
>    integer (acc_device_kind), parameter :: acc_device_not_host = 4
>    integer (acc_device_kind), parameter :: acc_device_nvidia = 5
>    integer (acc_device_kind), parameter :: acc_device_gcn = 8
> +  integer (acc_device_kind), parameter :: acc_device_current = -3
> +
> +  public :: acc_device_property
> +
> +  integer, parameter :: acc_device_property = int64

Why 'int64'?  I changed this to 'int32', but please tell if there's a
reason for 'int64'.

> +
> +  public :: acc_property_memory, acc_property_free_memory
> +  public :: acc_property_name, acc_property_vendor, acc_property_driver
> +
> +  ! Keep in sync with include/gomp-constants.h.
> +  integer (acc_device_property), parameter :: acc_property_memory = 1
> +  integer (acc_device_property), parameter :: acc_property_free_memory = 2
> +  integer (acc_device_property), parameter :: acc_property_name = int(Z'10001')
> +  integer (acc_device_property), parameter :: acc_property_vendor = int(Z'10002')
> +  integer (acc_device_property), parameter :: acc_property_driver = int(Z'10003')
>  
>    public :: acc_handle_kind
>  

Per Tobias' recent "libgomp/openacc.f90 – clean-up public/private
attributes" changes, some of this needs to move/change (done, I think).

> @@ -87,6 +102,24 @@ module openacc_internal
>        integer (acc_device_kind) d
>      end subroutine
>  
> +    function acc_get_property_h (n, d, p)
> +      import
> +      implicit none (type, external)
> +      integer (acc_device_property) :: acc_get_property_h
> +      integer, value :: n
> +      integer (acc_device_kind), value :: d
> +      integer (acc_device_property), value :: p
> +    end function
> +
> +    subroutine acc_get_property_string_h (n, d, p, s)
> +      import
> +      implicit none (type, external)
> +      integer, value :: n
> +      integer (acc_device_kind), value :: d
> +      integer (acc_device_property), value :: p
> +      character (*) :: s
> +    end subroutine
> +
>      function acc_get_device_num_h (d)
>        import
>        integer acc_get_device_num_h

No reason to place that between 'acc_set_device_num_h' and
'acc_get_device_num_h'?  I moved it after the latter, like done
elsewhere.


Is it a conscious decision that we're not supporting the new
'acc_get_property' interface via 'openacc_lib.h', which is (or, used to
be) an alternative to the Fortran 'openacc' module?

As of OpenACC 2.5, 'openacc_lib.h' has been deprecated ("no longer
supported"), but so far, we continued to support it, and it's (maybe?)
strange when that one now works for everything but the 'acc_get_property'
interface?  Or, is that a statement that users really should move to the
Fortran 'openacc' module?


> --- a/libgomp/openacc.h
> +++ b/libgomp/openacc.h
> @@ -59,9 +59,20 @@ typedef enum acc_device_t {
>    _ACC_device_hwm,
>    /* Ensure enumeration is layout compatible with int.  */
>    _ACC_highest = __INT_MAX__,
> -  _ACC_neg = -1
> +  _ACC_neg = -1,
> +  acc_device_current = -3
>  } acc_device_t;

(Update per final 'GOMP_DEVICE_CURRENT' value.  If settling on '-1',
'acc_device_current' may *replace* the placeholder '_ACC_neg'.)

> +typedef enum acc_device_property_t {
> +  /* Keep in sync with include/gomp-constants.h.  */
> +  /* Start from 1 to catch uninitialized use.  */
> +  acc_property_memory = 1,
> +  acc_property_free_memory = 2,
> +  acc_property_name = 0x10001,
> +  acc_property_vendor = 0x10002,
> +  acc_property_driver = 0x10003
> +} acc_device_property_t;

Do we also need the magic here so that "Ensure enumeration is layout
compatible with int"?  But I see that is not done for the 'typedef enum
acc_async_t' either.  I don't remember the history behind that.


> --- a/libgomp/plugin/plugin-hsa.c
> +++ b/libgomp/plugin/plugin-hsa.c
> @@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
>    return hsa_context.agent_count;
>  }
>  
> +/* Part of the libgomp plugin interface.  Return the value of property
> +   PROP of agent number N.  */
> +
> +union gomp_device_property_value
> +GOMP_OFFLOAD_get_property (int n, int prop)
> +{
> +  union gomp_device_property_value nullval = { .val = 0 };
> +
> +  if (!init_hsa_context ())
> +    return nullval;

I'm not familiar with that code, but similar to other plugins,
'init_hsa_context' already is called via 'GOMP_OFFLOAD_get_num_devices'
(and 'GOMP_OFFLOAD_init_device', hmm...), so probably don't need to call
it here?

> +  if (n >= hsa_context.agent_count)
> +    {
> +      GOMP_PLUGIN_error
> +	("Request for a property of a non-existing HSA device %i", n);
> +      return nullval;
> +    }

(Probably this would eventually call 'get_agent_info' to resolve 'n',
which then already does the checking done here.  No need to look into
that right now.)

> +
> +  switch (prop)
> +    {
> +    case GOMP_DEVICE_PROPERTY_VENDOR:
> +      return (union gomp_device_property_value) { .ptr = "AMD" };
> +    default:
> +      return nullval;
> +    }
> +}

Not sure if "AMD" is actually correct here -- isn't HSA a
vendor-independent standard?


> --- a/libgomp/plugin/plugin-nvptx.c
> +++ b/libgomp/plugin/plugin-nvptx.c

> @@ -304,6 +305,7 @@ struct ptx_device
>  };
>  
>  static struct ptx_device **ptx_devices;
> +static char cuda_driver_version[30];
>  
>  static inline struct nvptx_thread *
>  nvptx_thread (void)
> @@ -330,6 +332,12 @@ nvptx_init (void)
>    CUDA_CALL (cuDeviceGetCount, &ndevs);
>    ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *)
>  					    * ndevs);
> +
> +  int v;
> +  CUDA_CALL_ERET (NULL, cuDriverGetVersion, &v);
> +  snprintf (cuda_driver_version, sizeof (cuda_driver_version) - 1,
> +	    "CUDA Driver %u.%u", v / 1000, v % 1000 / 10);
> +
>    return true;
>  }

I moved these further up; this is relevant at the top-level, global in
this plugin.

Why the '- 1' in 'sizeof (cuda_driver_version) - 1'?  (I removed that.)

> @@ -293,6 +293,7 @@ struct ptx_device
>    int max_threads_per_block;
>    int max_threads_per_multiprocessor;
>    int default_dims[GOMP_DIM_MAX];
> +  char* name;
>  
>    struct ptx_image_data *images;  /* Images loaded on device.  */
>    pthread_mutex_t image_lock;     /* Lock for above list.  */

The number of 'struct ptx_device' instances will always be low, so let's
just embed 'name' into this (done), so that we can avoid the dynamic
allocation:

> @@ -491,6 +499,10 @@ nvptx_open_device (int n)
>    for (int i = 0; i != GOMP_DIM_MAX; i++)
>      ptx_dev->default_dims[i] = 0;
>  
> +  const int max_name_len = 256;
> +  ptx_dev->name = GOMP_PLUGIN_malloc(max_name_len);
> +  CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, max_name_len, dev);
> +
>    ptx_dev->images = NULL;
>    pthread_mutex_init (&ptx_dev->image_lock, NULL);
>  
> @@ -520,6 +532,7 @@ nvptx_close_device (struct ptx_device *ptx_dev)
>    if (!ptx_dev->ctx_shared)
>      CUDA_CALL (cuCtxDestroy, ptx_dev->ctx);
>  
> +  free (ptx_dev->name);
>    free (ptx_dev);
>    return true;
>  }

As 'acc_get_property' is not an interface commonly used, as an
alternative to "embed", we could also again make this a pointer, but
"allocated, initialized upon first use", but I'm not convinced it's worth
the effort.

> +union gomp_device_property_value
> +GOMP_OFFLOAD_get_property (int n, int prop)
> +{
> +  union gomp_device_property_value propval = { .val = 0 };
> +
> +  pthread_mutex_lock (&ptx_dev_lock);

Everything (?) else seems to be accessing 'ptx_devices' without locking?
(I don't quickly understand the locking protocol used there...  Will look
again tomorrow.)

> +
> +  if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
> +    {
> +      pthread_mutex_unlock (&ptx_dev_lock);
> +      return propval;
> +    }
> +
> +  struct ptx_device *ptx_dev = ptx_devices[n];
> +  switch (prop)
> +    {
> +    case GOMP_DEVICE_PROPERTY_MEMORY:
> +      {
> +	size_t total_mem;
> +
> +	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
> +	propval.val = total_mem;
> +      }
> +      break;
> +    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
> +      {
> +	size_t total_mem;
> +	size_t free_mem;
> +	CUdevice ctxdev;
> +
> +	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
> +	if (ptx_dev->dev == ctxdev)
> +	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> +	else if (ptx_dev->ctx)
> +	  {
> +	    CUcontext old_ctx;
> +
> +	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
> +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> +	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
> +	  }
> +	else
> +	  {
> +	    CUcontext new_ctx;
> +
> +	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
> +			    ptx_dev->dev);
> +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> +	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
> +	  }
> +	propval.val = free_mem;
> +      }
> +      break;

(Have not yet reviewed that CUDA magic.  Do you understand that?)

> +    case GOMP_DEVICE_PROPERTY_NAME:
> +      propval.ptr = ptx_dev->name;
> +      break;
> +    case GOMP_DEVICE_PROPERTY_VENDOR:
> +      propval.ptr = "Nvidia";
> +      break;
> +    case GOMP_DEVICE_PROPERTY_DRIVER:
> +      propval.ptr = cuda_driver_version;
> +      break;
> +    default:
> +      GOMP_PLUGIN_error("Unknown OpenACC device-property");
> +    }

I remember I asked: "Should this 'GOMP_PLUGIN_error' or even
'GOMP_PLUGIN_fatal'?  (Similar then elsewhere.)"  You only changed that
here, and I now see that OpenACC 2.6, 3.2.6. "acc_get_property" actually
states that "If the value of 'property' is not one of the known values
for that query routine, or that property has no value for the specified
device, 'acc_get_property' will return 0 and 'acc_get_property_string'
will return NULL (in C or C++) or an blank string (in Fortran)".  So this
means this should actually not call 'GOMP_PLUGIN_error' but instead
return zero etc.?  Please also make sure that we have testsuite coverage
for all the different cases possible.  (Especially different Fortran
interfaces.)

I see 'libgomp/oacc-host.c:host_get_property',
'libgomp/plugin/plugin-hsa.c:GOMP_OFFLOAD_get_property',
'liboffloadmic/plugin/libgomp-plugin-intelmic.cpp:GOMP_OFFLOAD_get_property'
do have a 'default: return nullval'; that's probably what we need to do
here, too?

> +
> +  pthread_mutex_unlock (&ptx_dev_lock);
> +  return propval;
> +}


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c

    FAIL: libgomp.oacc-c++/../libgomp.oacc-c-c++-common/acc-get-property-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0  (test for excess errors)
    UNRESOLVED: libgomp.oacc-c++/../libgomp.oacc-c-c++-common/acc-get-property-2.c -DACC_DEVICE_TYPE_nvidia=1 -DACC_MEM_SHARED=0 -foffload=nvptx-none  -O0  compilation failed to produce executable

    [...]/libgomp.oacc-c-c++-common/acc-get-property-2.c:61:28: error: invalid conversion from 'void*' to 'char*' [-fpermissive]
       61 |       char *driver = malloc(sizeof(char) * 40);
          |                      ~~~~~~^~~~~~~~~~~~~~~~~~~
          |                            |
          |                            void*

> +      char *driver = malloc(sizeof(char) * 40);
> +      snprintf (driver, 40, "CUDA Driver %u.%u", driver_version / 1000,
> +		driver_version % 1000 / 10);

Let's just use 'char driver[30]', and 'sizeof driver'?


> --- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
> +++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
> @@ -174,6 +174,28 @@ GOMP_OFFLOAD_get_num_devices (void)
>    return num_devices;
>  }
>  
> +extern "C" union gomp_device_property_value
> +GOMP_OFFLOAD_get_property (int n, int prop)
> +{
> +  union gomp_device_property_value nullval = { .val = 0 };
> +
> +  if (n >= num_devices)
> +    {
> +      GOMP_PLUGIN_error
> +       ("Request for a property of a non-existing Intel MIC device %i", n);
> +      return nullval;
> +    }
> +
> +  switch (prop)
> +    {
> +    case GOMP_DEVICE_PROPERTY_VENDOR:
> +      /* TODO: "error: invalid conversion from 'const void*' to 'void*' [-fpermissive]" */
> +      return (union gomp_device_property_value) { .ptr =  (char *) "Intel" };

Type cast maybe unnecessary per my 'libgomp/libgomp-plugin.h' comment above?

> +    default:
> +      return nullval;
> +    }
> +}


Grüße
 Thomas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-Add-OpenACC-2.6-acc_get_property-support.trunk.patch --]
[-- Type: text/x-diff, Size: 41236 bytes --]

From 51a21aab33902fbe85cb8bdc42ee07799e69051e Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Thu, 14 Nov 2019 16:35:31 +0100
Subject: [PATCH] Add OpenACC 2.6 `acc_get_property' support

Hi,
this patch implements OpenACC 2.6 "acc_get_property" and related functions.
I have tested the patch on x86_64-linux-gnu with nvptx-none offloading.
There is no AMD GCN support yet. This will be added later on.

Can this be committed to trunk?

Best regards,
Frederik

----------------------- 8< -------------------------------------------

Add generic support for the OpenACC 2.6 `acc_get_property' and
`acc_get_property_string' routines, as well as full handlers for the
host and the NVPTX offload targets and minimal handlers for the HSA
and Intel MIC offload targets.

Included are C/C++ and Fortran tests that, in particular, print
the property values for acc_property_vendor, acc_property_memory,
acc_property_free_memory, acc_property_name, and acc_property_driver.
The output looks as follows:

Vendor: GNU
Name: GOMP
Total memory: 0
Free memory: 0
Driver: 1.0

with the host driver (where the memory related properties are not
supported for the host device and yield 0, conforming to the standard)
and output like:

OpenACC vendor: Nvidia
OpenACC total memory: 12651462656
OpenACC free memory: 12202737664
OpenACC name: TITAN V
OpenACC driver: CUDA Driver 9.1

with the NVPTX driver.

2019-11-14  Maciej W. Rozycki  <macro@codesourcery.com>
	    Frederik Harwath  <frederik@codesourcery.com>
	    Thomas Schwinge  <tschwinge@codesourcery.com>

	include/
	* gomp-constants.h (GOMP_DEVICE_CURRENT,
	GOMP_DEVICE_PROPERTY_MEMORY, GOMP_DEVICE_PROPERTY_FREE_MEMORY,
	GOMP_DEVICE_PROPERTY_NAME, GOMP_DEVICE_PROPERTY_VENDOR,
	GOMP_DEVICE_PROPERTY_DRIVER, GOMP_DEVICE_PROPERTY_STRING_MASK):
	New Macros.

	libgomp/
	* libgomp.h (gomp_device_descr): Add `get_property_func' member.
	* libgomp-plugin.h (gomp_device_property_value): New union.
	(gomp_device_property_value): New prototype.
	* openacc.h (acc_device_t): Add `acc_device_current' enumeration
	constant.
	(acc_device_property_t): New enum.
	(acc_get_property, acc_get_property_string): New prototypes.
	* oacc-init.c (acc_get_device_type): Also assert on
	`!acc_device_current' result.
	(get_property_any, acc_get_property, acc_get_property_string):
	New functions.
	* openacc.f90 (openacc_kinds): From `iso_fortran_env' also
	import `int64'.  Add `acc_device_current' and
	`acc_property_memory', `acc_property_free_memory',
	`acc_property_name', `acc_property_vendor' and
	`acc_property_driver' constants.  Add `acc_device_property' data
	type.
	(openacc_internal): Add `acc_get_property' and
	`acc_get_property_string' interfaces.  Add `acc_get_property_h',
	`acc_get_property_string_h', `acc_get_property_l' and
	`acc_get_property_string_l'.
	(openacc_c_string): New module.
	* oacc-host.c (host_get_property): New function.
	(host_dispatch): Wire it.
	* target.c (gomp_load_plugin_for_device): Handle `get_property'.
	* libgomp.map (OACC_2.6): Add `acc_get_property',
	`acc_get_property_h_', `acc_get_property_string' and
	`acc_get_property_string_h_' symbols.
	* oacc-init.c (acc_known_device_type): Add function.
	(unknown_device_type_error): Add function.
	(name_of_acc_device_t): Change to call unknown_device_type_error
	on unknown type.
	(resolve_device): Use acc_known_device_type.
	(acc_init): Fail if acc_device_t argument is not valid.
	(acc_shutdown): Likewise.
	(acc_get_num_devices): Likewise.
	(acc_set_device_type): Likewise.
	(acc_get_device_num): Likewise.
	(acc_set_device_num): Likewise.
	(get_property_any): Likewise.
	(acc_get_property): Likewise.
	(acc_get_property_string): Likewise.
	(acc_on_device): Likewise.
	(goacc_save_and_set_bind): Likewise.

	* libgomp.texi (OpenACC Runtime Library Routines): Add
	`acc_get_property'.
	(acc_get_property): New node.

	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function.
	* plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName',
	`cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo'
	calls.
	(GOMP_OFFLOAD_get_property): New function.
	(struct ptx_device): Add new field "name" ...
	(nvptx_open_device): ... and alloc and init from here.
	(nvptx_close_device): ... and free from here.
	(cuda_driver_version): Add new static variable ...
	(nvptx_init): ... and init from here.

	* testsuite/libgomp.oacc-c-c++-common/acc-get-property.c: New
	test.
	* testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c: New
	test.
	 * testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c: New
	test.
	 * testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c: New
	file with test helper functions.

	* testsuite/libgomp.oacc-fortran/acc-get-property.f90: New test.

	liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
	New function.
---
 include/gomp-constants.h                      |  14 +++
 libgomp/libgomp-plugin.h                      |   8 ++
 libgomp/libgomp.h                             |   1 +
 libgomp/libgomp.map                           |   8 ++
 libgomp/libgomp.texi                          |  39 ++++++
 libgomp/oacc-host.c                           |  22 ++++
 libgomp/oacc-init.c                           |  84 ++++++++++++-
 libgomp/openacc.f90                           | 116 +++++++++++++++++-
 libgomp/openacc.h                             |  17 ++-
 libgomp/plugin/cuda-lib.def                   |   4 +
 libgomp/plugin/plugin-hsa.c                   |  26 ++++
 libgomp/plugin/plugin-nvptx.c                 |  85 ++++++++++++-
 libgomp/target.c                              |   1 +
 .../acc-get-property-2.c                      |  68 ++++++++++
 .../acc-get-property-3.c                      |  19 +++
 .../acc-get-property-aux.c                    |  60 +++++++++
 .../acc-get-property.c                        |  75 +++++++++++
 .../libgomp.oacc-fortran/acc-get-property.f90 |  80 ++++++++++++
 .../plugin/libgomp-plugin-intelmic.cpp        |  22 ++++
 19 files changed, 745 insertions(+), 4 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90

diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 9e356cdfeec..150b12d0d6f 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -178,6 +178,20 @@ enum gomp_map_kind
 
 #define GOMP_DEVICE_ICV			-1
 #define GOMP_DEVICE_HOST_FALLBACK	-2
+#define GOMP_DEVICE_CURRENT		-3
+
+/* Device property codes.  Keep in sync with
+   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t
+   as well as libgomp/libgomp-plugin.h.  */
+/* Start from 1 to catch uninitialized use.  */
+#define GOMP_DEVICE_PROPERTY_MEMORY		1
+#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
+#define GOMP_DEVICE_PROPERTY_NAME		0x10001
+#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
+#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
+
+/* Internal property mask to tell numeric and string values apart.  */
+#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
 
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED		(1 << 0)
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index 037558c43f5..5f968855f65 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -54,6 +54,13 @@ enum offload_target_type
   OFFLOAD_TARGET_TYPE_GCN = 8
 };
 
+/* Container type for passing device properties.  */
+union gomp_device_property_value
+{
+  void *ptr;
+  uintmax_t val;
+};
+
 /* Opaque type to represent plugin-dependent implementation of an
    OpenACC asynchronous queue.  */
 struct goacc_asyncqueue;
@@ -94,6 +101,7 @@ extern const char *GOMP_OFFLOAD_get_name (void);
 extern unsigned int GOMP_OFFLOAD_get_caps (void);
 extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
+extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
 extern unsigned GOMP_OFFLOAD_version (void);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index e55de96fb05..b2cd07dfa67 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1099,6 +1099,7 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
   __typeof (GOMP_OFFLOAD_get_type) *get_type_func;
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
+  __typeof (GOMP_OFFLOAD_get_property) *get_property_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index c79430f8d8d..fba4effbb3e 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -502,6 +502,14 @@ GOACC_2.0.1 {
 	GOACC_parallel_keyed;
 } GOACC_2.0;
 
+OACC_2.6 {
+  global:
+	acc_get_property;
+	acc_get_property_h_;
+	acc_get_property_string;
+	acc_get_property_string_h_;
+} OACC_2.5;
+
 GOMP_PLUGIN_1.0 {
   global:
 	GOMP_PLUGIN_malloc;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index ac9d38e01d7..5f8f1beedaf 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -1849,6 +1849,7 @@ acceleration device.
 * acc_get_device_type::         Get type of device accelerator to be used.
 * acc_set_device_num::          Set device number to use.
 * acc_get_device_num::          Get device number to be used.
+* acc_get_property::            Get device property.
 * acc_async_test::              Tests for completion of a specific asynchronous
                                 operation.
 * acc_async_test_all::          Tests for completion of all asychronous
@@ -2038,6 +2039,44 @@ region.
 
 
 
+@node acc_get_property
+@section @code{acc_get_property} -- Get device property.
+@cindex acc_get_property
+@cindex acc_get_property_string
+@table @asis
+@item @emph{Description}
+These routines return the value of the specified @var{property} for the
+device being queried according to @var{devicenum} and @var{devicetype}.
+Integer-valued and string-valued properties are returned by
+@code{acc_get_property} and @code{acc_get_property_string} respectively.
+The Fortran @code{acc_get_property_string} subroutine returns the string
+retrieved in its fourth argument while the remaining entry points are
+functions, which pass the return value as their result.
+
+@item @emph{C/C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
+@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
+@item                   @tab @code{integer devicenum}
+@item                   @tab @code{integer(kind=acc_device_kind) devicetype}
+@item                   @tab @code{integer(kind=acc_device_property) property}
+@item                   @tab @code{integer(kind=acc_device_property) acc_get_property}
+@item                   @tab @code{character(*) string}
+@end multitable
+
+@item @emph{Reference}:
+@uref{https://www.openacc.org, OpenACC specification v2.6}, section
+3.2.6.
+@end table
+
+
+
 @node acc_async_test
 @section @code{acc_async_test} -- Test for completion of a specific asynchronous operation.
 @table @asis
diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c
index 845140f04f5..ec9e3247a1a 100644
--- a/libgomp/oacc-host.c
+++ b/libgomp/oacc-host.c
@@ -59,6 +59,27 @@ host_get_num_devices (void)
   return 1;
 }
 
+static union gomp_device_property_value
+host_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= host_get_num_devices ())
+    return nullval;
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_NAME:
+      return (union gomp_device_property_value) { .ptr = "GOMP" };
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "GNU" };
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      return (union gomp_device_property_value) { .ptr = VERSION };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 host_init_device (int n __attribute__ ((unused)))
 {
@@ -248,6 +269,7 @@ static struct gomp_device_descr host_dispatch =
     .get_caps_func = host_get_caps,
     .get_type_func = host_get_type,
     .get_num_devices_func = host_get_num_devices,
+    .get_property_func = host_get_property,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
     .version_func = host_version,
diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index d7bdeda3f47..03148cc67d0 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -695,7 +695,8 @@ acc_get_device_type (void)
     }
 
   assert (res != acc_device_default
-	  && res != acc_device_not_host);
+	  && res != acc_device_not_host
+	  && res != acc_device_current);
 
   return res;
 }
@@ -784,6 +785,87 @@ acc_set_device_num (int ord, acc_device_t d)
 
 ialias (acc_set_device_num)
 
+static union gomp_device_property_value
+get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
+  union gomp_device_property_value propval;
+  struct gomp_device_descr *dev;
+  struct goacc_thread *thr;
+
+  if (d == acc_device_none)
+    return (union gomp_device_property_value) { .val = 0 };
+
+  goacc_lazy_initialize ();
+  thr = goacc_thread ();
+
+  if (d == acc_device_current && (!thr || !thr->dev))
+    return (union gomp_device_property_value) { .val = 0 };
+
+  if (d == acc_device_current)
+    {
+      dev = thr->dev;
+    }
+  else
+    {
+      int num_devices;
+
+      gomp_mutex_lock (&acc_device_lock);
+
+      dev = resolve_device (d, false);
+
+      num_devices = dev->get_num_devices_func ();
+
+      if (num_devices <= 0 || ord >= num_devices)
+        acc_dev_num_out_of_range (d, ord, num_devices);
+
+      dev += ord;
+
+      gomp_mutex_lock (&dev->lock);
+      if (dev->state == GOMP_DEVICE_UNINITIALIZED)
+        gomp_init_device (dev);
+      gomp_mutex_unlock (&dev->lock);
+
+      gomp_mutex_unlock (&acc_device_lock);
+    }
+
+  assert (dev);
+
+  propval = dev->get_property_func (dev->target_id, prop);
+
+  return propval;
+}
+
+size_t
+acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return 0;
+  else
+    return get_property_any (ord, d, prop).val;
+}
+
+ialias (acc_get_property)
+
+const char *
+acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!acc_known_device_type (d))
+    unknown_device_type_error(d);
+
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return get_property_any (ord, d, prop).ptr;
+  else
+    return NULL;
+}
+
+ialias (acc_get_property_string)
+
 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
    if the user disables the builtin, or calls it via a pointer, we'll need this
    version.
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index b37f1872d50..d009321551f 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -28,7 +28,7 @@
 !  <http://www.gnu.org/licenses/>.
 
 module openacc_kinds
-  use iso_fortran_env, only: int32
+  use iso_fortran_env, only: int32, int64
   implicit none
 
   public
@@ -46,6 +46,21 @@ module openacc_kinds
   integer (acc_device_kind), parameter :: acc_device_not_host = 4
   integer (acc_device_kind), parameter :: acc_device_nvidia = 5
   integer (acc_device_kind), parameter :: acc_device_gcn = 8
+  integer (acc_device_kind), parameter :: acc_device_current = -3
+
+  public :: acc_device_property
+
+  integer, parameter :: acc_device_property = int64
+
+  public :: acc_property_memory, acc_property_free_memory
+  public :: acc_property_name, acc_property_vendor, acc_property_driver
+
+  ! Keep in sync with include/gomp-constants.h.
+  integer (acc_device_property), parameter :: acc_property_memory = 1
+  integer (acc_device_property), parameter :: acc_property_free_memory = 2
+  integer (acc_device_property), parameter :: acc_property_name = int(Z'10001')
+  integer (acc_device_property), parameter :: acc_property_vendor = int(Z'10002')
+  integer (acc_device_property), parameter :: acc_property_driver = int(Z'10003')
 
   integer, parameter :: acc_handle_kind = int32
 
@@ -81,6 +96,24 @@ module openacc_internal
       integer (acc_device_kind) d
     end subroutine
 
+    function acc_get_property_h (n, d, p)
+      import
+      implicit none (type, external)
+      integer (acc_device_property) :: acc_get_property_h
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+    end function
+
+    subroutine acc_get_property_string_h (n, d, p, s)
+      import
+      implicit none (type, external)
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+      character (*) :: s
+    end subroutine
+
     function acc_get_device_num_h (d)
       import
       integer acc_get_device_num_h
@@ -506,6 +539,26 @@ module openacc_internal
       integer (c_int), value :: d
     end function
 
+    function acc_get_property_l (n, d, p) &
+        bind (C, name = "acc_get_property")
+      use iso_c_binding, only: c_int, c_size_t
+      implicit none (type, external)
+      integer (c_size_t) :: acc_get_property_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
+    function acc_get_property_string_l (n, d, p) &
+        bind (C, name = "acc_get_property_string")
+      use iso_c_binding, only: c_int, c_ptr
+      implicit none (type, external)
+      type (c_ptr) :: acc_get_property_string_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
     function acc_async_test_l (a) &
         bind (C, name = "acc_async_test")
       use iso_c_binding, only: c_int
@@ -755,6 +808,14 @@ module openacc
     procedure :: acc_get_device_num_h
   end interface
 
+  interface acc_get_property
+    procedure :: acc_get_property_h
+  end interface
+
+  interface acc_get_property_string
+    procedure :: acc_get_property_string_h
+  end interface
+
   interface acc_async_test
     procedure :: acc_async_test_h
   end interface
@@ -973,6 +1034,59 @@ function acc_get_device_num_h (d)
   acc_get_device_num_h = acc_get_device_num_l (d)
 end function
 
+function acc_get_property_h (n, d, p)
+  use iso_c_binding, only: c_int
+  use openacc_internal, only: acc_get_property_l
+  use openacc_kinds
+  implicit none (type, external)
+  integer (acc_device_property) :: acc_get_property_h
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+
+  integer (c_int) :: pint
+
+  pint = int (p, c_int)
+  acc_get_property_h = acc_get_property_l (n, d, pint)
+end function
+
+subroutine acc_get_property_string_h (n, d, p, s)
+  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer
+  use openacc_internal, only: acc_get_property_string_l
+  use openacc_kinds
+  implicit none (type, external)
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+  character (*) :: s
+
+  integer (c_int) :: pint
+  type (c_ptr) :: cptr
+  integer :: clen
+  character (kind=c_char, len=1), pointer, contiguous :: sptr (:)
+  integer :: slen
+  integer :: i
+
+  interface
+     function strlen (s) bind (C, name = "strlen")
+       use iso_c_binding, only: c_ptr, c_size_t
+       type (c_ptr), intent(in), value :: s
+       integer (c_size_t) :: strlen
+     end function strlen
+  end interface
+
+  pint = int (p, c_int)
+  cptr = acc_get_property_string_l (n, d, pint)
+  clen = int (strlen (cptr))
+  call c_f_pointer (cptr, sptr, [clen])
+
+  s = ""
+  slen = min (clen, len (s))
+  do i = 1, slen
+    s (i:i) = sptr (i)
+  end do
+end subroutine
+
 function acc_async_test_h (a)
   use openacc_internal, only: acc_async_test_l
   logical acc_async_test_h
diff --git a/libgomp/openacc.h b/libgomp/openacc.h
index 42c861caabf..49340b7fb6d 100644
--- a/libgomp/openacc.h
+++ b/libgomp/openacc.h
@@ -59,9 +59,20 @@ typedef enum acc_device_t {
   _ACC_device_hwm,
   /* Ensure enumeration is layout compatible with int.  */
   _ACC_highest = __INT_MAX__,
-  _ACC_neg = -1
+  _ACC_neg = -1,
+  acc_device_current = -3
 } acc_device_t;
 
+typedef enum acc_device_property_t {
+  /* Keep in sync with include/gomp-constants.h.  */
+  /* Start from 1 to catch uninitialized use.  */
+  acc_property_memory = 1,
+  acc_property_free_memory = 2,
+  acc_property_name = 0x10001,
+  acc_property_vendor = 0x10002,
+  acc_property_driver = 0x10003
+} acc_device_property_t;
+
 typedef enum acc_async_t {
   /* Keep in sync with include/gomp-constants.h.  */
   acc_async_noval = -1,
@@ -73,6 +84,10 @@ void acc_set_device_type (acc_device_t) __GOACC_NOTHROW;
 acc_device_t acc_get_device_type (void) __GOACC_NOTHROW;
 void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW;
 int acc_get_device_num (acc_device_t) __GOACC_NOTHROW;
+size_t acc_get_property
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
+const char *acc_get_property_string
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
 int acc_async_test (int) __GOACC_NOTHROW;
 int acc_async_test_all (void) __GOACC_NOTHROW;
 void acc_wait (int) __GOACC_NOTHROW;
diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def
index a16badcfa9d..cd91b39b1d2 100644
--- a/libgomp/plugin/cuda-lib.def
+++ b/libgomp/plugin/cuda-lib.def
@@ -8,6 +8,9 @@ CUDA_ONE_CALL (cuCtxSynchronize)
 CUDA_ONE_CALL (cuDeviceGet)
 CUDA_ONE_CALL (cuDeviceGetAttribute)
 CUDA_ONE_CALL (cuDeviceGetCount)
+CUDA_ONE_CALL (cuDeviceGetName)
+CUDA_ONE_CALL (cuDeviceTotalMem)
+CUDA_ONE_CALL (cuDriverGetVersion)
 CUDA_ONE_CALL (cuEventCreate)
 CUDA_ONE_CALL (cuEventDestroy)
 CUDA_ONE_CALL (cuEventElapsedTime)
@@ -35,6 +38,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync)
 CUDA_ONE_CALL (cuMemFree)
 CUDA_ONE_CALL (cuMemFreeHost)
 CUDA_ONE_CALL (cuMemGetAddressRange)
+CUDA_ONE_CALL (cuMemGetInfo)
 CUDA_ONE_CALL (cuMemHostGetDevicePointer)
 CUDA_ONE_CALL (cuModuleGetFunction)
 CUDA_ONE_CALL (cuModuleGetGlobal)
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index 409e138aaca..491ea5769b9 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
+/* Part of the libgomp plugin interface.  Return the value of property
+   PROP of agent number N.  */
+
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (!init_hsa_context ())
+    return nullval;
+  if (n >= hsa_context.agent_count)
+    {
+      GOMP_PLUGIN_error
+	("Request for a property of a non-existing HSA device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "AMD" };
+    default:
+      return nullval;
+    }
+}
+
 /* Part of the libgomp plugin interface.  Initialize agent number N so that it
    can be used for computation.  Return TRUE on success.  */
 
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index 911d0f66a6e..0e9f9ff69ba 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -284,7 +284,7 @@ struct ptx_device
   bool map;
   bool concur;
   bool mkern;
-  int  mode;
+  int mode;
   int clock_khz;
   int num_sms;
   int regs_per_block;
@@ -293,6 +293,7 @@ struct ptx_device
   int max_threads_per_block;
   int max_threads_per_multiprocessor;
   int default_dims[GOMP_DIM_MAX];
+  char* name;
 
   struct ptx_image_data *images;  /* Images loaded on device.  */
   pthread_mutex_t image_lock;     /* Lock for above list.  */
@@ -304,6 +305,7 @@ struct ptx_device
 };
 
 static struct ptx_device **ptx_devices;
+static char cuda_driver_version[30];
 
 static inline struct nvptx_thread *
 nvptx_thread (void)
@@ -330,6 +332,12 @@ nvptx_init (void)
   CUDA_CALL (cuDeviceGetCount, &ndevs);
   ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *)
 					    * ndevs);
+
+  int v;
+  CUDA_CALL_ERET (NULL, cuDriverGetVersion, &v);
+  snprintf (cuda_driver_version, sizeof (cuda_driver_version) - 1,
+	    "CUDA Driver %u.%u", v / 1000, v % 1000 / 10);
+
   return true;
 }
 
@@ -491,6 +499,10 @@ nvptx_open_device (int n)
   for (int i = 0; i != GOMP_DIM_MAX; i++)
     ptx_dev->default_dims[i] = 0;
 
+  const int max_name_len = 256;
+  ptx_dev->name = GOMP_PLUGIN_malloc(max_name_len);
+  CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, max_name_len, dev);
+
   ptx_dev->images = NULL;
   pthread_mutex_init (&ptx_dev->image_lock, NULL);
 
@@ -520,6 +532,7 @@ nvptx_close_device (struct ptx_device *ptx_dev)
   if (!ptx_dev->ctx_shared)
     CUDA_CALL (cuCtxDestroy, ptx_dev->ctx);
 
+  free (ptx_dev->name);
   free (ptx_dev);
   return true;
 }
@@ -1104,6 +1117,76 @@ GOMP_OFFLOAD_get_num_devices (void)
   return nvptx_get_num_devices ();
 }
 
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value propval = { .val = 0 };
+
+  pthread_mutex_lock (&ptx_dev_lock);
+
+  if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
+    {
+      pthread_mutex_unlock (&ptx_dev_lock);
+      return propval;
+    }
+
+  struct ptx_device *ptx_dev = ptx_devices[n];
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_MEMORY:
+      {
+	size_t total_mem;
+
+	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
+	propval.val = total_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
+      {
+	size_t total_mem;
+	size_t free_mem;
+	CUdevice ctxdev;
+
+	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
+	if (ptx_dev->dev == ctxdev)
+	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	else if (ptx_dev->ctx)
+	  {
+	    CUcontext old_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
+	  }
+	else
+	  {
+	    CUcontext new_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
+			    ptx_dev->dev);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
+	  }
+	propval.val = free_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_NAME:
+      propval.ptr = ptx_dev->name;
+      break;
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      propval.ptr = "Nvidia";
+      break;
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      propval.ptr = cuda_driver_version;
+      break;
+    default:
+      GOMP_PLUGIN_error("Unknown OpenACC device-property");
+    }
+
+  pthread_mutex_unlock (&ptx_dev_lock);
+  return propval;
+}
+
 bool
 GOMP_OFFLOAD_init_device (int n)
 {
diff --git a/libgomp/target.c b/libgomp/target.c
index 7a55f63efdd..1bb490fbb8f 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -2786,6 +2786,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (get_caps);
   DLSYM (get_type);
   DLSYM (get_num_devices);
+  DLSYM (get_property);
   DLSYM (init_device);
   DLSYM (fini_device);
   DLSYM (load_image);
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
new file mode 100644
index 00000000000..b97eef7777e
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
@@ -0,0 +1,68 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions on Nvidia devices by comparing property values with
+   those obtained through the CUDA API. */
+/* { dg-additional-sources acc-get-property-aux.c } */
+/* { dg-additional-options "-lcuda -lcudart" } */
+/* { dg-do run { target openacc_nvidia_accel_selected } } */
+
+#include <openacc.h>
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+#include <string.h>
+#include <stdio.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+int main ()
+{
+  int dev_count;
+  cudaGetDeviceCount (&dev_count);
+
+  for (int dev_num = 0; dev_num < dev_count; ++dev_num)
+    {
+      if (cudaSetDevice (dev_num) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaSetDevice failed.\n");
+	  abort ();
+	}
+
+      printf("Checking device %d\n", dev_num);
+
+      const char *vendor = "Nvidia";
+      size_t free_mem;
+      size_t total_mem;
+      if (cudaMemGetInfo(&free_mem, &total_mem) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaMemGetInfo failed.\n");
+	  abort ();
+	}
+
+      struct cudaDeviceProp p;
+      if (cudaGetDeviceProperties(&p, dev_num) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaGetDeviceProperties failed.\n");
+	  abort ();
+	}
+
+      int driver_version;
+      if (cudaDriverGetVersion(&driver_version) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaDriverGetVersion failed.\n");
+	  abort ();
+	}
+      /* The version string should contain the version of the CUDA Toolkit
+      	 in the same MAJOR.MINOR format that is used by Nvidia.
+      	 The format string below is the same that is used by the deviceQuery
+      	 program, which belongs to Nvidia's CUDA samples, to print the version. */
+      char *driver = malloc(sizeof(char) * 40);
+      snprintf (driver, 40, "CUDA Driver %u.%u", driver_version / 1000,
+		driver_version % 1000 / 10);
+
+      expect_device_properties(acc_device_nvidia, dev_num,
+			       total_mem, free_mem, vendor, p.name, driver);
+    }
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c
new file mode 100644
index 00000000000..1a8dca6193b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c
@@ -0,0 +1,19 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions for the host device. */
+/* { dg-additional-sources acc-get-property-aux.c } */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stdio.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+int main()
+{
+  printf ("Checking acc_device_host device properties\n");
+  expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0");
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c
new file mode 100644
index 00000000000..5540b91f842
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c
@@ -0,0 +1,60 @@
+/* Auxiliary functions for acc_get_property tests */
+/* { dg-do compile  { target skip-all-targets } } */
+
+#include <openacc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver)
+{
+  const char *vendor = acc_get_property_string (dev_num, dev_type,
+						acc_property_vendor);
+  if (strcmp (vendor, expected_vendor))
+    {
+      fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
+	       "but was \"%s\".\n", expected_vendor, vendor);
+      abort ();
+    }
+
+  int total_mem = acc_get_property (dev_num, dev_type,
+				    acc_property_memory);
+  if (total_mem != expected_total_mem)
+    {
+      fprintf (stderr, "Expected acc_property_memory to equal %d, "
+	       "but was %d.\n", expected_total_mem, total_mem);
+      abort ();
+
+    }
+
+  int free_mem = acc_get_property (dev_num, dev_type,
+				   acc_property_free_memory);
+  if (free_mem != expected_free_mem)
+    {
+      fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
+	       "but was %d.\n", expected_free_mem, free_mem);
+      abort ();
+    }
+
+  const char *name = acc_get_property_string (dev_num, dev_type,
+					      acc_property_name);
+  if (strcmp (name, expected_name))
+    {
+      fprintf(stderr, "Expected acc_property_name to equal \"%s\", "
+	      "but was \"%s\".\n", expected_name, name);
+      abort ();
+    }
+
+  const char *driver = acc_get_property_string (dev_num, dev_type,
+						acc_property_driver);
+  if (strcmp (expected_driver, driver))
+    {
+      fprintf (stderr, "Expected acc_property_driver to equal %s, "
+	       "but was %s.\n", expected_driver, driver);
+      abort ();
+    }
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
new file mode 100644
index 00000000000..e9a86860f45
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c
@@ -0,0 +1,75 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions by printing the results of those functions for all devices
+   of all device types mentioned in the OpenACC standard.
+
+   See also acc-get-property.f90. */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Print the values of the properties of all devices of the given type
+   and do basic device independent validation. */
+
+void
+print_device_properties(acc_device_t type)
+{
+  const char *s;
+  size_t v;
+
+  int dev_count = acc_get_num_devices(type);
+
+  for (int i = 0; i < dev_count; ++i)
+    {
+      printf("  Device %d:\n", i+1);
+
+      s = acc_get_property_string (i, type, acc_property_vendor);
+      printf ("    Vendor: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_vendor should not be null or empty.\n");
+	  abort ();
+	}
+
+      v = acc_get_property (i, type,  acc_property_memory);
+      printf ("    Total memory: %zd\n", v);
+
+      v = acc_get_property (i, type, acc_property_free_memory);
+      printf ("    Free memory: %zd\n", v);
+
+      s = acc_get_property_string (i, type, acc_property_name);
+      printf ("    Name: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_name should not be null or empty.\n");
+	  abort ();
+	}
+
+      s = acc_get_property_string (i, type, acc_property_driver);
+      printf ("    Driver: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_string should not be null or empty.\n");
+	  abort ();
+	}
+    }
+}
+
+int main ()
+{
+  printf("acc_device_none:\n");
+  /* For completness; not expected to print anything since there
+     should be no devices of this type. */
+  print_device_properties(acc_device_none);
+
+  printf("acc_device_default:\n");
+  print_device_properties(acc_device_default);
+
+  printf("acc_device_host:\n");
+  print_device_properties(acc_device_host);
+
+  printf("acc_device_not_host:\n");
+  print_device_properties(acc_device_not_host);
+}
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90
new file mode 100644
index 00000000000..71239cd0c7c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90
@@ -0,0 +1,80 @@
+! Test the `acc_get_property' and '`acc_get_property_string' library
+! functions by printing the results of those functions for all devices
+! of all device types mentioned in the OpenACC standard.
+!
+! See also acc-get-property.c
+! { dg-do run }
+
+program test
+  use openacc
+  implicit none
+
+  print *, "acc_device_none:"
+  ! For completeness; not expected to print anything
+  call print_device_properties (acc_device_none)
+
+  print *, "acc_device_default:"
+  call print_device_properties (acc_device_default)
+
+  print *, "acc_device_host:"
+  call print_device_properties (acc_device_host)
+
+  print *, "acc_device_not_host:"
+  call print_device_properties (acc_device_not_host)
+end program test
+
+! Print the values of the properties of all devices of the given type
+! and do basic device independent validation.
+subroutine print_device_properties (device_type)
+  use openacc
+  implicit none
+
+  integer, intent(in) :: device_type
+
+  integer :: device_count
+  integer :: device
+  integer(acc_device_property) :: v
+  character*256 :: s
+
+  device_count = acc_get_num_devices(device_type)
+
+  do device = 0, device_count - 1
+     print "(a, i0)", "  Device ", device
+
+     call acc_get_property_string (device, device_type, acc_property_vendor, s)
+     print "(a, a)", "    Vendor: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_vendor should not be empty."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, acc_property_memory)
+     print "(a, i0)", "    Total memory: ", v
+     if (v < 0) then
+        print *, "acc_property_memory should not be negative."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, acc_property_free_memory)
+     print "(a, i0)", "    Free memory: ", v
+     if (v < 0) then
+        print *, "acc_property_free_memory should not to be negative."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, acc_property_name, s)
+     print "(a, a)", "    Name: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_name should not be empty."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, acc_property_driver, s)
+     print "(a, a)", "    Driver: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_driver should not be empty."
+        stop 1
+     end if
+
+  end do
+end subroutine print_device_properties
diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
index d1678d0514e..e3c60ad7f1f 100644
--- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
+++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
@@ -174,6 +174,28 @@ GOMP_OFFLOAD_get_num_devices (void)
   return num_devices;
 }
 
+extern "C" union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= num_devices)
+    {
+      GOMP_PLUGIN_error
+       ("Request for a property of a non-existing Intel MIC device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      /* TODO: "error: invalid conversion from 'const void*' to 'void*' [-fpermissive]" */
+      return (union gomp_device_property_value) { .ptr =  (char *) "Intel" };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 offload (const char *file, uint64_t line, int device, const char *name,
 	 int num_vars, VarDesc *vars, const void **async_data)
-- 
2.17.1


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: 0001-WIP-acc_get_property.trunk.patch --]
[-- Type: text/x-diff, Size: 8273 bytes --]

From c352a83b80e3d23119672f2077a90eee4f9bac8c Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Mon, 16 Dec 2019 23:52:05 +0100
Subject: [PATCH] [WIP] 'acc_get_property'

---
 libgomp/oacc-init.c                           |  7 ++--
 libgomp/openacc.f90                           | 34 ++++++++++---------
 libgomp/plugin/plugin-nvptx.c                 | 28 ++++++++-------
 .../acc-get-property-2.c                      |  6 ++--
 4 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index 269582e3a51..13e415ed1c0 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -790,9 +790,6 @@ ialias (acc_set_device_num)
 static union gomp_device_property_value
 get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
 {
-  if (!acc_known_device_type (d))
-    unknown_device_type_error(d);
-
   union gomp_device_property_value propval;
   struct gomp_device_descr *dev;
   struct goacc_thread *thr;
@@ -843,7 +840,7 @@ get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
 size_t
 acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
 {
-  if (!acc_known_device_type (d))
+  if (!known_device_type_p (d))
     unknown_device_type_error(d);
 
   if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
@@ -857,7 +854,7 @@ ialias (acc_get_property)
 const char *
 acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
 {
-  if (!acc_known_device_type (d))
+  if (!known_device_type_p (d))
     unknown_device_type_error(d);
 
   if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index d009321551f..36e93945383 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -28,7 +28,7 @@
 !  <http://www.gnu.org/licenses/>.
 
 module openacc_kinds
-  use iso_fortran_env, only: int32, int64
+  use iso_fortran_env, only: int32
   implicit none
 
   public
@@ -48,12 +48,7 @@ module openacc_kinds
   integer (acc_device_kind), parameter :: acc_device_gcn = 8
   integer (acc_device_kind), parameter :: acc_device_current = -3
 
-  public :: acc_device_property
-
-  integer, parameter :: acc_device_property = int64
-
-  public :: acc_property_memory, acc_property_free_memory
-  public :: acc_property_name, acc_property_vendor, acc_property_driver
+  integer, parameter :: acc_device_property = int32
 
   ! Keep in sync with include/gomp-constants.h.
   integer (acc_device_property), parameter :: acc_property_memory = 1
@@ -96,6 +91,12 @@ module openacc_internal
       integer (acc_device_kind) d
     end subroutine
 
+    function acc_get_device_num_h (d)
+      import
+      integer acc_get_device_num_h
+      integer (acc_device_kind) d
+    end function
+
     function acc_get_property_h (n, d, p)
       import
       implicit none (type, external)
@@ -114,12 +115,6 @@ module openacc_internal
       character (*) :: s
     end subroutine
 
-    function acc_get_device_num_h (d)
-      import
-      integer acc_get_device_num_h
-      integer (acc_device_kind) d
-    end function
-
     function acc_async_test_h (a)
       logical acc_async_test_h
       integer a
@@ -766,16 +761,23 @@ module openacc
 
   private
   ! From openacc_kinds
-  public :: acc_device_kind, acc_handle_kind
+  public :: acc_device_kind
   public :: acc_device_none, acc_device_default, acc_device_host
   public :: acc_device_not_host, acc_device_nvidia, acc_device_gcn
+
+  public :: acc_device_property
+  public :: acc_property_memory, acc_property_free_memory
+  public :: acc_property_name, acc_property_vendor, acc_property_driver
+
+  public :: acc_handle_kind
   public :: acc_async_noval, acc_async_sync
 
   public :: openacc_version
 
   public :: acc_get_num_devices, acc_set_device_type, acc_get_device_type
-  public :: acc_set_device_num, acc_get_device_num, acc_async_test
-  public :: acc_async_test_all
+  public :: acc_set_device_num, acc_get_device_num
+  public :: acc_get_property, acc_get_property_string
+  public :: acc_async_test, acc_async_test_all
   public :: acc_wait, acc_async_wait, acc_wait_async
   public :: acc_wait_all, acc_async_wait_all, acc_wait_all_async
   public :: acc_init, acc_shutdown, acc_on_device
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index 6c57da2e737..5ab163cf762 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -189,6 +189,10 @@ cuda_error (CUresult r)
   return fallback;
 }
 
+/* Version of the CUDA Toolkit in the same MAJOR.MINOR format that is used by
+   Nvidia, such as in the 'deviceQuery' program (Nvidia's CUDA samples). */
+static char cuda_driver_version_s[30];
+
 static unsigned int instantiated_devices = 0;
 static pthread_mutex_t ptx_dev_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -293,7 +297,9 @@ struct ptx_device
   int max_threads_per_block;
   int max_threads_per_multiprocessor;
   int default_dims[GOMP_DIM_MAX];
-  char* name;
+
+  /* Length as used by the CUDA Runtime API ('struct cudaDeviceProp').  */
+  char name[256];
 
   struct ptx_image_data *images;  /* Images loaded on device.  */
   pthread_mutex_t image_lock;     /* Lock for above list.  */
@@ -305,7 +311,6 @@ struct ptx_device
 };
 
 static struct ptx_device **ptx_devices;
-static char cuda_driver_version[30];
 
 static inline struct nvptx_thread *
 nvptx_thread (void)
@@ -329,15 +334,16 @@ nvptx_init (void)
 
   CUDA_CALL (cuInit, 0);
 
+  int cuda_driver_version;
+  CUDA_CALL_ERET (NULL, cuDriverGetVersion, &cuda_driver_version);
+  snprintf (cuda_driver_version_s, sizeof cuda_driver_version_s,
+	    "CUDA Driver %u.%u",
+	    cuda_driver_version / 1000, cuda_driver_version % 1000 / 10);
+
   CUDA_CALL (cuDeviceGetCount, &ndevs);
   ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *)
 					    * ndevs);
 
-  int v;
-  CUDA_CALL_ERET (NULL, cuDriverGetVersion, &v);
-  snprintf (cuda_driver_version, sizeof (cuda_driver_version) - 1,
-	    "CUDA Driver %u.%u", v / 1000, v % 1000 / 10);
-
   return true;
 }
 
@@ -499,9 +505,8 @@ nvptx_open_device (int n)
   for (int i = 0; i != GOMP_DIM_MAX; i++)
     ptx_dev->default_dims[i] = 0;
 
-  const int max_name_len = 256;
-  ptx_dev->name = GOMP_PLUGIN_malloc(max_name_len);
-  CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, max_name_len, dev);
+  CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, sizeof ptx_dev->name,
+		  dev);
 
   ptx_dev->images = NULL;
   pthread_mutex_init (&ptx_dev->image_lock, NULL);
@@ -532,7 +537,6 @@ nvptx_close_device (struct ptx_device *ptx_dev)
   if (!ptx_dev->ctx_shared)
     CUDA_CALL (cuCtxDestroy, ptx_dev->ctx);
 
-  free (ptx_dev->name);
   free (ptx_dev);
   return true;
 }
@@ -1177,7 +1181,7 @@ GOMP_OFFLOAD_get_property (int n, int prop)
       propval.ptr = "Nvidia";
       break;
     case GOMP_DEVICE_PROPERTY_DRIVER:
-      propval.ptr = cuda_driver_version;
+      propval.ptr = cuda_driver_version_s;
       break;
     default:
       GOMP_PLUGIN_error("Unknown OpenACC device-property");
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
index b97eef7777e..06a5b40af58 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c
@@ -58,9 +58,9 @@ int main ()
       	 in the same MAJOR.MINOR format that is used by Nvidia.
       	 The format string below is the same that is used by the deviceQuery
       	 program, which belongs to Nvidia's CUDA samples, to print the version. */
-      char *driver = malloc(sizeof(char) * 40);
-      snprintf (driver, 40, "CUDA Driver %u.%u", driver_version / 1000,
-		driver_version % 1000 / 10);
+      char driver[30];
+      snprintf (driver, sizeof driver, "CUDA Driver %u.%u",
+		driver_version / 1000, driver_version % 1000 / 10);
 
       expect_device_properties(acc_device_nvidia, dev_num,
 			       total_mem, free_mem, vendor, p.name, driver);
-- 
2.17.1


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-16 23:06     ` Thomas Schwinge
@ 2019-12-17  9:39       ` Martin Jambor
  2019-12-17  9:47       ` Andrew Stubbs
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 38+ messages in thread
From: Martin Jambor @ 2019-12-17  9:39 UTC (permalink / raw)
  To: Thomas Schwinge, Frederik Harwath
  Cc: gcc-patches, jakub, tdevries, Andrew Stubbs, Julian Brown, Tobias Burnus

Hi,

On Tue, Dec 17 2019, Thomas Schwinge wrote:
> On 2019-11-14T16:35:31+0100, Frederik Harwath <frederik@codesourcery.com> wrote:
>> this patch implements OpenACC 2.6 "acc_get_property" and related functions.
>
> [...]
>
>> --- a/libgomp/plugin/plugin-hsa.c
>> +++ b/libgomp/plugin/plugin-hsa.c
>> @@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
>>    return hsa_context.agent_count;
>>  }
>>  
>> +/* Part of the libgomp plugin interface.  Return the value of property
>> +   PROP of agent number N.  */
>> +
>> +union gomp_device_property_value
>> +GOMP_OFFLOAD_get_property (int n, int prop)
>> +{
>> +  union gomp_device_property_value nullval = { .val = 0 };
>> +
>> +  if (!init_hsa_context ())
>> +    return nullval;
>
> I'm not familiar with that code, but similar to other plugins,
> 'init_hsa_context' already is called via 'GOMP_OFFLOAD_get_num_devices'
> (and 'GOMP_OFFLOAD_init_device', hmm...), so probably don't need to call
> it here?

I assume you always want to get the number of devices before querying
their properties but OTOH there is no harm in calling the initialization
function.

>> +
>> +  switch (prop)
>> +    {
>> +    case GOMP_DEVICE_PROPERTY_VENDOR:
>> +      return (union gomp_device_property_value) { .ptr = "AMD" };
>> +    default:
>> +      return nullval;
>> +    }
>> +}
>
> Not sure if "AMD" is actually correct here -- isn't HSA a
> vendor-independent standard?
>

Yes, it is supposed to be.  I think HSA is the correct "vendor" too,
essentially an abbreviation for HSA Foundation.

Thanks,

Martin

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-16 23:06     ` Thomas Schwinge
  2019-12-17  9:39       ` Martin Jambor
@ 2019-12-17  9:47       ` Andrew Stubbs
  2019-12-20 17:11       ` Harwath, Frederik
  2020-04-29  9:19       ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge
  3 siblings, 0 replies; 38+ messages in thread
From: Andrew Stubbs @ 2019-12-17  9:47 UTC (permalink / raw)
  To: Thomas Schwinge, Frederik Harwath
  Cc: gcc-patches, jakub, tdevries, mjambor, Julian Brown, Tobias Burnus

On 16/12/2019 23:00, Thomas Schwinge wrote:
>> There is no AMD GCN support yet. This will be added later on.
> 
> ACK, just to note that there now is a 'libgomp/plugin/plugin-gcn.c' that
> at least needs to get a stub implementation (can mostly copy from
> 'libgomp/plugin/plugin-hsa.c'?) as otherwise the build will fail.

The code exists on the OG9 branch. It was omitted from the trunk 
submission because the other half of the properties support wasn't there 
yet.

Andrew

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-16 23:06     ` Thomas Schwinge
  2019-12-17  9:39       ` Martin Jambor
  2019-12-17  9:47       ` Andrew Stubbs
@ 2019-12-20 17:11       ` Harwath, Frederik
  2019-12-21 23:01         ` Thomas Schwinge
                           ` (3 more replies)
  2020-04-29  9:19       ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge
  3 siblings, 4 replies; 38+ messages in thread
From: Harwath, Frederik @ 2019-12-20 17:11 UTC (permalink / raw)
  To: frederik, GCC Patches, Thomas Schwinge
  Cc: tdevries, mjambor, Andrew Stubbs, Julian Brown, Tobias Burnus,
	Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 14978 bytes --]

Hi Thomas,
thanks for the review! I have attached a revised patch.

> > There is no AMD GCN support yet. This will be added later on.
>
> ACK, just to note that there now is a 'libgomp/plugin/plugin-gcn.c' that
> at least needs to get a stub implementation (can mostly copy from
> 'libgomp/plugin/plugin-hsa.c'?) as otherwise the build will fail.

Yes, I have added a stub. A full implementation will follow soon.
The implementation in the OG9 branch that Andrew mentioned will need a
bit of polishing.

> Tobias has generally reviewed the Fortran bits, correct?

Yes, he has done that internally.

> | Before Frederik starts working on integrating this into GCC trunk, do you
> | (Jakub) agree with the libgomp plugin interface changes as implemented by
> | Maciej?  For example, top-level 'GOMP_OFFLOAD_get_property' function in
> | 'struct gomp_device_descr' instead of stuffing this into its
> | 'acc_dispatch_t openacc'.  (I never understood why the OpenACC functions
> | need to be segregated like they are.)
>
> Jakub didn't answer, but I now myself decided that we should group this
> with the other OpenACC libgomp-plugin functions, as this interface is
> defined in terms of OpenACC-specific stuff such as 'acc_device_t'.
> Frederik, please work on that, also try to move function definitions etc.
> into appropriate places in case they aren't; ask if you need help.
> That needs to be updated.

Is it ok to do this in a separate follow-up patch?


> >  .../acc-get-property-2.c                      |  68 +++++++++
> >  .../acc-get-property-3.c                      |  19 +++
> >  .../acc-get-property-aux.c                    |  60 ++++++++
> >  .../acc-get-property.c                        |  75 ++++++++++
> >  .../libgomp.oacc-fortran/acc-get-property.f90 |  80 ++++++++++
>
> Please name all these 'acc_get_property*', which is the name of the
> interface tested.

Ok.


> > --- a/include/gomp-constants.h
> > +++ b/include/gomp-constants.h
> > @@ -178,6 +178,20 @@ enum gomp_map_kind
> >=20=20
> >  #define GOMP_DEVICE_ICV			-1
> >  #define GOMP_DEVICE_HOST_FALLBACK	-2
> > +#define GOMP_DEVICE_CURRENT		-3
> [...]
>
> Not should if this should be grouped with 'GOMP_DEVICE_ICV',
> 'GOMP_DEVICE_HOST_FALLBACK', for it is not related to there.
>
> [...]
>
> Should this actually get value '-1' instead of '-3'?  Or, is the OpenACC
> 'acc_device_t' code already paying special attention to negative values
> '-1', '-2'?  (I don't think so.)
> | Also, 'acc_device_current' is a libgomp-internal thing (doesn't interface
> | with the compiler proper), so strictly speaking 'GOMP_DEVICE_CURRENT'
> | isn't needed in 'include/gomp-constants.h'.  But probably still a good
> | idea to list it there, in this canonical place, to keep the several lists
> | of device types coherent.
> still wonder about that...  ;-)

I have removed GOMP_DEVICE_CURRENT from gomp-constants.h.
Changing the value of GOMP_DEVICE_ICV violates the following static asserts in oacc-parallel.c:

 /* In the ABI, the GOACC_FLAGs are encoded as an inverted bitmask, so that we
   continue to support the following two legacy values.  */
_Static_assert (GOACC_FLAGS_UNMARSHAL (GOMP_DEVICE_ICV) == 0,
		"legacy GOMP_DEVICE_ICV broken");
_Static_assert (GOACC_FLAGS_UNMARSHAL (GOMP_DEVICE_HOST_FALLBACK)
		== GOACC_FLAG_HOST_FALLBACK,
		"legacy GOMP_DEVICE_HOST_FALLBACK broken");

> > +/* Device property codes.  Keep in sync with
> > +   libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t
>
> | Same thing, libgomp-internal, not sure whether to list these here?
>
> > +   as well as libgomp/libgomp-plugin.h.  */
>
> (Not sure why 'libgomp/libgomp-plugin.h' is relevant here?)

It does not seem to be relevant. Right now, openacc_lib.h is also not relevant.
I have removed both file names from the comment.

> > +#define GOMP_DEVICE_PROPERTY_MEMORY		1
> > +#define GOMP_DEVICE_PROPERTY_FREE_MEMORY	2
> > +#define GOMP_DEVICE_PROPERTY_NAME		0x10001
> > +#define GOMP_DEVICE_PROPERTY_VENDOR		0x10002
> > +#define GOMP_DEVICE_PROPERTY_DRIVER		0x10003
> > +
> > +/* Internal property mask to tell numeric and string values apart.  */
> > +#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
>
> (Maybe should use an 'enum'?)

I have changed this to an enum. However, this does not improve the code much,
since we cannot use the enum for the function arguments in the plugins
because gomp-constants.h is not included from there.

> Maybe this stuff should move from 'include/gomp-constants.h' to
> 'libgomp/oacc-int.h'.  I'll think about that again, when I'm awake again
> tomorrow.  ;-)

Have you made up your mind yet? :-)


> > --- a/libgomp/libgomp-plugin.h
> > +++ b/libgomp/libgomp-plugin.h
> > @@ -54,6 +54,13 @@ enum offload_target_type
> >    OFFLOAD_TARGET_TYPE_GCN =3D 8
> >  };
> >=20=20
> > +/* Container type for passing device properties.  */
> > +union gomp_device_property_value
> > +{
> > +  void *ptr;
> > +  uintmax_t val;
> > +};
>
> Why wouldn't that be 'size_t', 'const char *', as the actual data types
> used?  (Maybe I'm missing something.)

I do not see a reason for this either. Changed.


> > --- a/libgomp/libgomp.map
> > +++ b/libgomp/libgomp.map
> > @@ -502,6 +502,14 @@ GOACC_2.0.1 {
> >  	GOACC_parallel_keyed;
> >  } GOACC_2.0;
> >=20=20
> > +OACC_2.6 {
> > +  global:
> > +	acc_get_property;
> > +	acc_get_property_h_;
> > +	acc_get_property_string;
> > +	acc_get_property_string_h_;
> > +} OACC_2.5;
> > +
> >  GOMP_PLUGIN_1.0 {
> >    global:
> >  	GOMP_PLUGIN_malloc;
>
> That's not correct: 'OACC_2.6' should come after 'OACC_2.5.1', and
> also inherit from that one.

Fixed.


> > --- a/libgomp/oacc-init.c
> > +++ b/libgomp/oacc-init.c
>
> > +static union gomp_device_property_value
> > +get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
> > +{
> > +  if (!acc_known_device_type (d))
> > +    unknown_device_type_error(d);
>
> Checking isn't needed here for this is an internal interface?

Right.

> > +
> > +  union gomp_device_property_value propval;
> > +  struct gomp_device_descr *dev;
> > +  struct goacc_thread *thr;
>
> Generally, in new code, we try to place these next to their first use.

Very reasonable. Adapted.

> > +
> > +  if (d =3D=3D acc_device_none)
> > +    return (union gomp_device_property_value) { .val =3D 0 };
> > +
> > +  goacc_lazy_initialize ();
> > +  thr =3D goacc_thread ();
> > +
> > +  if (d =3D=3D acc_device_current && (!thr || !thr->dev))
> > +    return (union gomp_device_property_value) { .val =3D 0 };
>
> Should we use a 'nullval' here, as used elsewhere?

We could, but we can also remove those checks completely.

> Also, this checking seems a bit convoluted; shouldn't this be integrated
> into the following?  It's certainly not necessary to special-case
> 'acc_device_none' before 'goacc_lazy_initialize' etc.?

Yes, I suppose that the original implementer wanted to handle those
boundary cases as efficiently as possible. But it is not strictly necessary
to do this and I agree that the code becomes more readable without those
checks.

> > +
> > +  if (d =3D=3D acc_device_current)
> > +    {
> > +      dev =3D thr->dev;
> > +    }
> > +  else
> > +    {
> > +      int num_devices;
> > +
> > +      gomp_mutex_lock (&acc_device_lock);
> > +
> > +      dev =3D resolve_device (d, false);
>
> Why call this without 'fail_is_error' flag here?

Good question. I have set it to true to ensure that we get
the device type checking that resolve_device performs.


> > --- a/libgomp/openacc.f90
> > +++ b/libgomp/openacc.f90
> > @@ -28,7 +28,7 @@
> >  !  <http://www.gnu.org/licenses/>.
> >=20=20
> >  module openacc_kinds
> > -  use iso_fortran_env, only: int32
> > +  use iso_fortran_env, only: int32, int64
> >    implicit none
> >=20=20
> >    private :: int32
> > @@ -47,6 +47,21 @@ module openacc_kinds
> >    integer (acc_device_kind), parameter :: acc_device_not_host =3D 4
> >    integer (acc_device_kind), parameter :: acc_device_nvidia =3D 5
> >    integer (acc_device_kind), parameter :: acc_device_gcn =3D 8
> > +  integer (acc_device_kind), parameter :: acc_device_current =3D -3
> > +
> > +  public :: acc_device_property
> > +
> > +  integer, parameter :: acc_device_property =3D int64
>
> Why 'int64'?  I changed this to 'int32', but please tell if there's a
> reason for 'int64'.


int32 is too narrow as - conforming to the OpenACC spec - acc_device_property
is also used for the return type of acc_get_property (a bit strang, isn't it?).
int64 also did not seem quite right. I have changed the type of acc_device_property
to c_size_t to match the type that is used internally and as the return type of the
corresponding C function.

> Is it a conscious decision that we're not supporting the new
> 'acc_get_property' interface via 'openacc_lib.h', which is (or, used to
> be) an alternative to the Fortran 'openacc' module?

It was not my decision to leave it out. I have to admit that I did not notice the omission.

> As of OpenACC 2.5, 'openacc_lib.h' has been deprecated ("no longer
> supported"), but so far, we continued to support it, and it's (maybe?)
> strange when that one now works for everything but the 'acc_get_property'
> interface?  Or, is that a statement that users really should move to the
> Fortran 'openacc' module?

Should they? You are probably best qualified to answer this :-).

> > +typedef enum acc_device_property_t {
> > +  /* Keep in sync with include/gomp-constants.h.  */
> > +  /* Start from 1 to catch uninitialized use.  */
> > +  acc_property_memory =3D 1,
> > +  acc_property_free_memory =3D 2,
> > +  acc_property_name =3D 0x10001,
> > +  acc_property_vendor =3D 0x10002,
> > +  acc_property_driver =3D 0x10003
> > +} acc_device_property_t;
>
> Do we also need the magic here so that "Ensure enumeration is layout
> compatible with int"?  But I see that is not done for the 'typedef enum
> acc_async_t' either.  I don't remember the history behind that.

I understand the "Ensure enumeration is layout compatible with int" comment for
acc_device_t, but I fail to see how those values achieve this.
If you do not see a good reason to keep those magic values, I would change them
to 3, 4, 5 and if we need the "layout compatibility", I would rather do this as
it is done for acc_device_t.


> > --- a/libgomp/plugin/plugin-hsa.c
> > +++ b/libgomp/plugin/plugin-hsa.c
> > @@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
> >    return hsa_context.agent_count;
> >  }
> >=20=20
> > +/* Part of the libgomp plugin interface.  Return the value of property
> > +   PROP of agent number N.  */
> > +
> > +union gomp_device_property_value
> > +GOMP_OFFLOAD_get_property (int n, int prop)
> > +{
> > +  union gomp_device_property_value nullval =3D { .val =3D 0 };
> > +
> > +  if (!init_hsa_context ())
> > +    return nullval;
>
> I'm not familiar with that code, but similar to other plugins,
> 'init_hsa_context' already is called via 'GOMP_OFFLOAD_get_num_devices'
> (and 'GOMP_OFFLOAD_init_device', hmm...), so probably don't need to call
> it here?

Since Martin Jambor wrote that the call does no harm, I would just keep it.

> > +
> > +  switch (prop)
> > +    {
> > +    case GOMP_DEVICE_PROPERTY_VENDOR:
> > +      return (union gomp_device_property_value) { .ptr =3D "AMD" };
> > +    default:
> > +      return nullval;
> > +    }
> > +}
>
> Not sure if "AMD" is actually correct here -- isn't HSA a
> vendor-independent standard?

I have changed "AMD" to "HSA".

> > +union gomp_device_property_value
> > +GOMP_OFFLOAD_get_property (int n, int prop)
> > +{
> > +  union gomp_device_property_value propval =3D { .val =3D 0 };
> > +
> > +  pthread_mutex_lock (&ptx_dev_lock);
>
> Everything (?) else seems to be accessing 'ptx_devices' without locking?
> (I don't quickly understand the locking protocol used there...  Will look
> again tomorrow.)

GOMP_OFFLOAD_init_device, GOMP_OFFLOAD_fini_device take the lock
before accessing ptx_devices. I kept it.

> > +	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
> > +	if (ptx_dev->dev =3D=3D ctxdev)
> > +	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> > +	else if (ptx_dev->ctx)
> > +	  {
> > +	    CUcontext old_ctx;
> > +
> > +	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
> > +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> > +	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
> > +	  }
> > +	else
> > +	  {
> > +	    CUcontext new_ctx;
> > +
> > +	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
> > +			    ptx_dev->dev);
> > +	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
> > +	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
> > +	  }

>
>
> (Have not yet reviewed that CUDA magic.  Do you understand that?)

Yes, sort of. If the current thread's CUDA context is the a context for the device, perform the query (cuMemGetInfo) right away.
Otherwise, we have to set the context first to ensure that we query the right device. Note that this is not necessary
for the functions that are used to retrieve the values of the other properties because they use CUDA functions that take a
device argument. If the ptx_dev already contains a context for the device, set it temporarily for the duration of the query.
Otherwise, do the same with a newly created context for the device and dispose of the new context afterwards.
The last case might arise only if the device has not been initialized, as GOMP_OFFLOAD_init_device
calls nvptx_open_device which creates the context ptx_dev->ctx for ptx_dev->dev.


> > +    case GOMP_DEVICE_PROPERTY_DRIVER:
> > +      propval.ptr =3D cuda_driver_version;
> > +      break;
> > +    default:
> > +      GOMP_PLUGIN_error("Unknown OpenACC device-property");
> > +    }
>
> [...]
>
> I see 'libgomp/oacc-host.c:host_get_property',
> 'libgomp/plugin/plugin-hsa.c:GOMP_OFFLOAD_get_property',
> 'liboffloadmic/plugin/libgomp-plugin-intelmic.cpp:GOMP_OFFLOAD_get_property'
> do have a 'default: return nullval'; that's probably what we need to do
> here, too?

Yes, I have changed this and added test cases that check the return value for invalid properties.

> > --- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
> [...]
> > +    case GOMP_DEVICE_PROPERTY_VENDOR:
> > +      /* TODO: "error: invalid conversion from 'const void*' to 'void*' =
> [-fpermissive]" */
> > +      return (union gomp_device_property_value) { .ptr =3D  (char *) "In=
> tel" };
>
> Type cast maybe unnecessary per my 'libgomp/libgomp-plugin.h' comment above?

Correct.

Is it ok to commit the patch to trunk?

Best regards,
Frederik

[-- Attachment #2: 0001-Add-OpenACC-2.6-acc_get_property-support.patch --]
[-- Type: text/x-patch, Size: 42655 bytes --]

From c0849361fb847d5ffac47e48203e4377488305de Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Fri, 20 Dec 2019 17:24:36 +0100
Subject: [PATCH] Add OpenACC 2.6 `acc_get_property' support

Add generic support for the OpenACC 2.6 `acc_get_property' and
`acc_get_property_string' routines, as well as full handlers for the
host and the NVPTX offload targets and minimal handlers for the HSA,
Intel MIC, and AMD GCN offload targets.

Included are C/C++ and Fortran tests that, in particular, print
the property values for acc_property_vendor, acc_property_memory,
acc_property_free_memory, acc_property_name, and acc_property_driver.
The output looks as follows:

Vendor: GNU
Name: GOMP
Total memory: 0
Free memory: 0
Driver: 1.0

with the host driver (where the memory related properties are not
supported for the host device and yield 0, conforming to the standard)
and output like:

Vendor: Nvidia
Total memory: 12651462656
Free memory: 12202737664
Name: TITAN V
Driver: CUDA Driver 9.1

with the NVPTX driver.

2019-12-20  Maciej W. Rozycki  <macro@codesourcery.com>
	    Frederik Harwath  <frederik@codesourcery.com>
	    Thomas Schwinge  <tschwinge@codesourcery.com>

	include/
	* gomp-constants.h (gomp_device_property): New enum.

	libgomp/
	* libgomp.h (gomp_device_descr): Add `get_property_func' member.
	* libgomp-plugin.h (gomp_device_property_value): New union.
	(gomp_device_property_value): New prototype.
	* openacc.h (acc_device_t): Add `acc_device_current' enumeration
	constant.
	(acc_device_property_t): New enum.
	(acc_get_property, acc_get_property_string): New prototypes.
	* oacc-init.c (acc_get_device_type): Also assert that result
	is not `acc_device_current'.
	(get_property_any, acc_get_property, acc_get_property_string):
	New functions.
	* openacc.f90 (openacc_kinds): Add `acc_device_current' and
	`acc_property_memory', `acc_property_free_memory',
	`acc_property_name', `acc_property_vendor' and
	`acc_property_driver' constants.  Add `acc_device_property' data
	type.
	(openacc_internal): Add `acc_get_property' and
	`acc_get_property_string' interfaces.  Add `acc_get_property_h',
	`acc_get_property_string_h', `acc_get_property_l' and
	`acc_get_property_string_l'.
	* oacc-host.c (host_get_property): New function.
	(host_dispatch): Wire it.
	* target.c (gomp_load_plugin_for_device): Handle `get_property'.
	* libgomp.map (OACC_2.6): Add `acc_get_property', `acc_get_property_h_',
	`acc_get_property_string' and `acc_get_property_string_h_' symbols.
	* libgomp.texi (OpenACC Runtime Library Routines): Add
	`acc_get_property'.
	(acc_get_property): New node.
	* plugin/plugin-gcn.c (GOMP_OFFLOAD_get_property): New
	function (stub).
	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function.
	* plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName',
	`cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo'
	calls.
	(GOMP_OFFLOAD_get_property): New function.
	(struct ptx_device): Add new field "name".
	(cuda_driver_version_s): Add new static variable ...
	(nvptx_init): ... and init from here.

	* testsuite/libgomp.oacc-c-c++-common/acc_get_property.c: New test.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c: New test.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c: New test.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c: New file
	with test helper functions.

	* testsuite/libgomp.oacc-fortran/acc_get_property.f90: New test.

	liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
	New function.

Reviewed-by: Thomas Schwinge <thomas@codesourcery.com>
---
 include/gomp-constants.h                      |  15 ++
 libgomp/libgomp-plugin.h                      |   8 ++
 libgomp/libgomp.h                             |   1 +
 libgomp/libgomp.map                           |   4 +
 libgomp/libgomp.texi                          |  39 ++++++
 libgomp/oacc-host.c                           |  22 +++
 libgomp/oacc-init.c                           |  63 ++++++++-
 libgomp/openacc.f90                           | 129 +++++++++++++++++-
 libgomp/openacc.h                             |  15 ++
 libgomp/plugin/cuda-lib.def                   |   4 +
 libgomp/plugin/plugin-gcn.c                   |  11 ++
 libgomp/plugin/plugin-hsa.c                   |  26 ++++
 libgomp/plugin/plugin-nvptx.c                 |  87 +++++++++++-
 libgomp/target.c                              |   1 +
 .../acc_get_property-2.c                      |  68 +++++++++
 .../acc_get_property-3.c                      |  19 +++
 .../acc_get_property-aux.c                    |  80 +++++++++++
 .../acc_get_property.c                        |  75 ++++++++++
 .../libgomp.oacc-fortran/acc_get_property.f90 |  92 +++++++++++++
 .../plugin/libgomp-plugin-intelmic.cpp        |  21 +++
 20 files changed, 774 insertions(+), 6 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90

diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index fdae6ccc870..d14e8b0394a 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -195,6 +195,21 @@ enum gomp_map_kind
 #define GOMP_DEVICE_ICV			-1
 #define GOMP_DEVICE_HOST_FALLBACK	-2
 
+/* Device property codes.  Keep in sync with
+   libgomp/{openacc.h,openacc.f90}:acc_device_property_t */
+/* Start from 1 to catch uninitialized use.  */
+enum gomp_device_property
+  {
+   GOMP_DEVICE_PROPERTY_MEMORY =	1,
+   GOMP_DEVICE_PROPERTY_FREE_MEMORY = 	2,
+   GOMP_DEVICE_PROPERTY_NAME =		0x10001,
+   GOMP_DEVICE_PROPERTY_VENDOR =	0x10002,
+   GOMP_DEVICE_PROPERTY_DRIVER =	0x10003
+  };
+
+/* Internal property mask to tell numeric and string values apart.  */
+#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
+
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED		(1 << 0)
 #define GOMP_TASK_FLAG_FINAL		(1 << 1)
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index 037558c43f5..d3c6dc36276 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -54,6 +54,13 @@ enum offload_target_type
   OFFLOAD_TARGET_TYPE_GCN = 8
 };
 
+/* Container type for passing device properties.  */
+union gomp_device_property_value
+{
+  const char *ptr;
+  size_t val;
+};
+
 /* Opaque type to represent plugin-dependent implementation of an
    OpenACC asynchronous queue.  */
 struct goacc_asyncqueue;
@@ -94,6 +101,7 @@ extern const char *GOMP_OFFLOAD_get_name (void);
 extern unsigned int GOMP_OFFLOAD_get_caps (void);
 extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
+extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
 extern unsigned GOMP_OFFLOAD_version (void);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index c9653575208..24c76698c4e 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1113,6 +1113,7 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
   __typeof (GOMP_OFFLOAD_get_type) *get_type_func;
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
+  __typeof (GOMP_OFFLOAD_get_property) *get_property_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index 63276f7d29b..c7268bfc8e7 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -492,6 +492,10 @@ OACC_2.6 {
 	acc_detach_async;
 	acc_detach_finalize;
 	acc_detach_finalize_async;
+	acc_get_property;
+	acc_get_property_h_;
+	acc_get_property_string;
+	acc_get_property_string_h_;
 } OACC_2.5.1;
 
 GOACC_2.0 {
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index ac9d38e01d7..5f8f1beedaf 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -1849,6 +1849,7 @@ acceleration device.
 * acc_get_device_type::         Get type of device accelerator to be used.
 * acc_set_device_num::          Set device number to use.
 * acc_get_device_num::          Get device number to be used.
+* acc_get_property::            Get device property.
 * acc_async_test::              Tests for completion of a specific asynchronous
                                 operation.
 * acc_async_test_all::          Tests for completion of all asychronous
@@ -2038,6 +2039,44 @@ region.
 
 
 
+@node acc_get_property
+@section @code{acc_get_property} -- Get device property.
+@cindex acc_get_property
+@cindex acc_get_property_string
+@table @asis
+@item @emph{Description}
+These routines return the value of the specified @var{property} for the
+device being queried according to @var{devicenum} and @var{devicetype}.
+Integer-valued and string-valued properties are returned by
+@code{acc_get_property} and @code{acc_get_property_string} respectively.
+The Fortran @code{acc_get_property_string} subroutine returns the string
+retrieved in its fourth argument while the remaining entry points are
+functions, which pass the return value as their result.
+
+@item @emph{C/C++}:
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
+@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
+@item                   @tab @code{integer devicenum}
+@item                   @tab @code{integer(kind=acc_device_kind) devicetype}
+@item                   @tab @code{integer(kind=acc_device_property) property}
+@item                   @tab @code{integer(kind=acc_device_property) acc_get_property}
+@item                   @tab @code{character(*) string}
+@end multitable
+
+@item @emph{Reference}:
+@uref{https://www.openacc.org, OpenACC specification v2.6}, section
+3.2.6.
+@end table
+
+
+
 @node acc_async_test
 @section @code{acc_async_test} -- Test for completion of a specific asynchronous operation.
 @table @asis
diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c
index 845140f04f5..ec9e3247a1a 100644
--- a/libgomp/oacc-host.c
+++ b/libgomp/oacc-host.c
@@ -59,6 +59,27 @@ host_get_num_devices (void)
   return 1;
 }
 
+static union gomp_device_property_value
+host_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= host_get_num_devices ())
+    return nullval;
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_NAME:
+      return (union gomp_device_property_value) { .ptr = "GOMP" };
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "GNU" };
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      return (union gomp_device_property_value) { .ptr = VERSION };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 host_init_device (int n __attribute__ ((unused)))
 {
@@ -248,6 +269,7 @@ static struct gomp_device_descr host_dispatch =
     .get_caps_func = host_get_caps,
     .get_type_func = host_get_type,
     .get_num_devices_func = host_get_num_devices,
+    .get_property_func = host_get_property,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
     .version_func = host_version,
diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index dd88b58a379..487a2cca61f 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -670,7 +670,8 @@ acc_get_device_type (void)
     }
 
   assert (res != acc_device_default
-	  && res != acc_device_not_host);
+	  && res != acc_device_not_host
+	  && res != acc_device_current);
 
   return res;
 }
@@ -759,6 +760,66 @@ acc_set_device_num (int ord, acc_device_t d)
 
 ialias (acc_set_device_num)
 
+static union gomp_device_property_value
+get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  goacc_lazy_initialize ();
+  struct goacc_thread *thr = goacc_thread ();
+
+  if (d == acc_device_current && thr && thr->dev)
+    return thr->dev->get_property_func (thr->dev->target_id, prop);
+
+  gomp_mutex_lock (&acc_device_lock);
+
+  struct gomp_device_descr *dev = resolve_device (d, true);
+
+  int num_devices = dev->get_num_devices_func ();
+
+  if (num_devices <= 0 || ord >= num_devices)
+    acc_dev_num_out_of_range (d, ord, num_devices);
+
+  dev += ord;
+
+  gomp_mutex_lock (&dev->lock);
+  if (dev->state == GOMP_DEVICE_UNINITIALIZED)
+    gomp_init_device (dev);
+  gomp_mutex_unlock (&dev->lock);
+
+  gomp_mutex_unlock (&acc_device_lock);
+
+  assert (dev);
+
+  return dev->get_property_func (dev->target_id, prop);
+}
+
+size_t
+acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!known_device_type_p (d))
+    unknown_device_type_error(d);
+
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return 0;
+  else
+    return get_property_any (ord, d, prop).val;
+}
+
+ialias (acc_get_property)
+
+const char *
+acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
+{
+  if (!known_device_type_p (d))
+    unknown_device_type_error(d);
+
+  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+    return get_property_any (ord, d, prop).ptr;
+  else
+    return NULL;
+}
+
+ialias (acc_get_property_string)
+
 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
    if the user disables the builtin, or calls it via a pointer, we'll need this
    version.
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index fb7fc6e6d77..e5b4b40c3cc 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -31,16 +31,18 @@
 
 module openacc_kinds
   use iso_fortran_env, only: int32
+  use iso_c_binding, only: c_size_t
   implicit none
 
   public
-  private :: int32
+  private :: int32, c_size_t
 
   ! When adding items, also update 'public' setting in 'module openacc' below.
 
   integer, parameter :: acc_device_kind = int32
 
   ! Keep in sync with include/gomp-constants.h.
+  integer (acc_device_kind), parameter :: acc_device_current = -3
   integer (acc_device_kind), parameter :: acc_device_none = 0
   integer (acc_device_kind), parameter :: acc_device_default = 1
   integer (acc_device_kind), parameter :: acc_device_host = 2
@@ -49,6 +51,15 @@ module openacc_kinds
   integer (acc_device_kind), parameter :: acc_device_nvidia = 5
   integer (acc_device_kind), parameter :: acc_device_gcn = 8
 
+  integer, parameter :: acc_device_property = c_size_t
+
+  ! Keep in sync with include/gomp-constants.h.
+  integer (acc_device_property), parameter :: acc_property_memory = 1
+  integer (acc_device_property), parameter :: acc_property_free_memory = 2
+  integer (acc_device_property), parameter :: acc_property_name = int(Z'10001')
+  integer (acc_device_property), parameter :: acc_property_vendor = int(Z'10002')
+  integer (acc_device_property), parameter :: acc_property_driver = int(Z'10003')
+
   integer, parameter :: acc_handle_kind = int32
 
   ! Keep in sync with include/gomp-constants.h.
@@ -89,6 +100,24 @@ module openacc_internal
       integer (acc_device_kind) d
     end function
 
+    function acc_get_property_h (n, d, p)
+      import
+      implicit none (type, external)
+      integer (acc_device_property) :: acc_get_property_h
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+    end function
+
+    subroutine acc_get_property_string_h (n, d, p, s)
+      import
+      implicit none (type, external)
+      integer, value :: n
+      integer (acc_device_kind), value :: d
+      integer (acc_device_property), value :: p
+      character (*) :: s
+    end subroutine
+
     function acc_async_test_h (a)
       logical acc_async_test_h
       integer a
@@ -508,6 +537,26 @@ module openacc_internal
       integer (c_int), value :: d
     end function
 
+    function acc_get_property_l (n, d, p) &
+        bind (C, name = "acc_get_property")
+      use iso_c_binding, only: c_int, c_size_t
+      implicit none (type, external)
+      integer (c_size_t) :: acc_get_property_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
+    function acc_get_property_string_l (n, d, p) &
+        bind (C, name = "acc_get_property_string")
+      use iso_c_binding, only: c_int, c_ptr
+      implicit none (type, external)
+      type (c_ptr) :: acc_get_property_string_l
+      integer (c_int), value :: n
+      integer (c_int), value :: d
+      integer (c_int), value :: p
+    end function
+
     function acc_async_test_l (a) &
         bind (C, name = "acc_async_test")
       use iso_c_binding, only: c_int
@@ -716,16 +765,23 @@ module openacc
   private
 
   ! From openacc_kinds
-  public :: acc_device_kind, acc_handle_kind
+  public :: acc_device_kind
   public :: acc_device_none, acc_device_default, acc_device_host
   public :: acc_device_not_host, acc_device_nvidia, acc_device_gcn
+
+  public :: acc_device_property
+  public :: acc_property_memory, acc_property_free_memory
+  public :: acc_property_name, acc_property_vendor, acc_property_driver
+
+  public :: acc_handle_kind
   public :: acc_async_noval, acc_async_sync
 
   public :: openacc_version
 
   public :: acc_get_num_devices, acc_set_device_type, acc_get_device_type
-  public :: acc_set_device_num, acc_get_device_num, acc_async_test
-  public :: acc_async_test_all
+  public :: acc_set_device_num, acc_get_device_num
+  public :: acc_get_property, acc_get_property_string
+  public :: acc_async_test, acc_async_test_all
   public :: acc_wait, acc_async_wait, acc_wait_async
   public :: acc_wait_all, acc_async_wait_all, acc_wait_all_async
   public :: acc_init, acc_shutdown, acc_on_device
@@ -758,6 +814,14 @@ module openacc
     procedure :: acc_get_device_num_h
   end interface
 
+  interface acc_get_property
+    procedure :: acc_get_property_h
+  end interface
+
+  interface acc_get_property_string
+    procedure :: acc_get_property_string_h
+  end interface
+
   interface acc_async_test
     procedure :: acc_async_test_h
   end interface
@@ -976,6 +1040,63 @@ function acc_get_device_num_h (d)
   acc_get_device_num_h = acc_get_device_num_l (d)
 end function
 
+function acc_get_property_h (n, d, p)
+  use iso_c_binding, only: c_int, c_size_t
+  use openacc_internal, only: acc_get_property_l
+  use openacc_kinds
+  implicit none (type, external)
+  integer (acc_device_property) :: acc_get_property_h
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+
+  integer (c_int) :: pint
+
+  pint = int (p, c_int)
+  acc_get_property_h = acc_get_property_l (n, d, pint)
+end function
+
+subroutine acc_get_property_string_h (n, d, p, s)
+  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer, c_associated
+  use openacc_internal, only: acc_get_property_string_l
+  use openacc_kinds
+  implicit none (type, external)
+  integer, value :: n
+  integer (acc_device_kind), value :: d
+  integer (acc_device_property), value :: p
+  character (*) :: s
+
+  integer (c_int) :: pint
+  type (c_ptr) :: cptr
+  integer :: clen
+  character (kind=c_char, len=1), pointer, contiguous :: sptr (:)
+  integer :: slen
+  integer :: i
+
+  interface
+     function strlen (s) bind (C, name = "strlen")
+       use iso_c_binding, only: c_ptr, c_size_t
+       type (c_ptr), intent(in), value :: s
+       integer (c_size_t) :: strlen
+     end function strlen
+  end interface
+
+  pint = int (p, c_int)
+  cptr = acc_get_property_string_l (n, d, pint)
+  s = ""
+  if (.not. c_associated (cptr)) then
+     return
+  end if
+
+  clen = int (strlen (cptr))
+  call c_f_pointer (cptr, sptr, [clen])
+
+  slen = min (clen, len (s))
+  do i = 1, slen
+    s (i:i) = sptr (i)
+  end do
+end subroutine
+
 function acc_async_test_h (a)
   use openacc_internal, only: acc_async_test_l
   logical acc_async_test_h
diff --git a/libgomp/openacc.h b/libgomp/openacc.h
index d2e5c101f7f..9b143064b7d 100644
--- a/libgomp/openacc.h
+++ b/libgomp/openacc.h
@@ -49,6 +49,7 @@ extern "C" {
 /* Types */
 typedef enum acc_device_t {
   /* Keep in sync with include/gomp-constants.h.  */
+  acc_device_current = -3,
   acc_device_none = 0,
   acc_device_default = 1,
   acc_device_host = 2,
@@ -62,6 +63,16 @@ typedef enum acc_device_t {
   _ACC_neg = -1
 } acc_device_t;
 
+typedef enum acc_device_property_t {
+  /* Keep in sync with include/gomp-constants.h.  */
+  /* Start from 1 to catch uninitialized use.  */
+  acc_property_memory = 1,
+  acc_property_free_memory = 2,
+  acc_property_name = 0x10001,
+  acc_property_vendor = 0x10002,
+  acc_property_driver = 0x10003
+} acc_device_property_t;
+
 typedef enum acc_async_t {
   /* Keep in sync with include/gomp-constants.h.  */
   acc_async_noval = -1,
@@ -73,6 +84,10 @@ void acc_set_device_type (acc_device_t) __GOACC_NOTHROW;
 acc_device_t acc_get_device_type (void) __GOACC_NOTHROW;
 void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW;
 int acc_get_device_num (acc_device_t) __GOACC_NOTHROW;
+size_t acc_get_property
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
+const char *acc_get_property_string
+  (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
 int acc_async_test (int) __GOACC_NOTHROW;
 int acc_async_test_all (void) __GOACC_NOTHROW;
 void acc_wait (int) __GOACC_NOTHROW;
diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def
index a16badcfa9d..cd91b39b1d2 100644
--- a/libgomp/plugin/cuda-lib.def
+++ b/libgomp/plugin/cuda-lib.def
@@ -8,6 +8,9 @@ CUDA_ONE_CALL (cuCtxSynchronize)
 CUDA_ONE_CALL (cuDeviceGet)
 CUDA_ONE_CALL (cuDeviceGetAttribute)
 CUDA_ONE_CALL (cuDeviceGetCount)
+CUDA_ONE_CALL (cuDeviceGetName)
+CUDA_ONE_CALL (cuDeviceTotalMem)
+CUDA_ONE_CALL (cuDriverGetVersion)
 CUDA_ONE_CALL (cuEventCreate)
 CUDA_ONE_CALL (cuEventDestroy)
 CUDA_ONE_CALL (cuEventElapsedTime)
@@ -35,6 +38,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync)
 CUDA_ONE_CALL (cuMemFree)
 CUDA_ONE_CALL (cuMemFreeHost)
 CUDA_ONE_CALL (cuMemGetAddressRange)
+CUDA_ONE_CALL (cuMemGetInfo)
 CUDA_ONE_CALL (cuMemHostGetDevicePointer)
 CUDA_ONE_CALL (cuModuleGetFunction)
 CUDA_ONE_CALL (cuModuleGetGlobal)
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 04fe472a70d..32239c71c61 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -3236,6 +3236,17 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int device, int prop)
+{
+  /* Stub. Check device and return default value for unsupported properties. */
+  /* TODO: Implement this function. */
+  get_agent_info (device);
+
+  union gomp_device_property_value nullval = { .val = 0 };
+  return nullval;
+}
+
 /* Initialize device (agent) number N so that it can be used for computation.
    Return TRUE on success.  */
 
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index 409e138aaca..259f704b2e9 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
+/* Part of the libgomp plugin interface.  Return the value of property
+   PROP of agent number N.  */
+
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (!init_hsa_context ())
+    return nullval;
+  if (n >= hsa_context.agent_count)
+    {
+      GOMP_PLUGIN_error
+	("Request for a property of a non-existing HSA device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr = "HSA" };
+    default:
+      return nullval;
+    }
+}
+
 /* Part of the libgomp plugin interface.  Initialize agent number N so that it
    can be used for computation.  Return TRUE on success.  */
 
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index 911d0f66a6e..80e547541e3 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -189,6 +189,10 @@ cuda_error (CUresult r)
   return fallback;
 }
 
+/* Version of the CUDA Toolkit in the same MAJOR.MINOR format that is used by
+   Nvidia, such as in the 'deviceQuery' program (Nvidia's CUDA samples). */
+static char cuda_driver_version_s[30];
+
 static unsigned int instantiated_devices = 0;
 static pthread_mutex_t ptx_dev_lock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -284,7 +288,7 @@ struct ptx_device
   bool map;
   bool concur;
   bool mkern;
-  int  mode;
+  int mode;
   int clock_khz;
   int num_sms;
   int regs_per_block;
@@ -294,6 +298,9 @@ struct ptx_device
   int max_threads_per_multiprocessor;
   int default_dims[GOMP_DIM_MAX];
 
+  /* Length as used by the CUDA Runtime API ('struct cudaDeviceProp').  */
+  char name[256];
+
   struct ptx_image_data *images;  /* Images loaded on device.  */
   pthread_mutex_t image_lock;     /* Lock for above list.  */
 
@@ -327,9 +334,16 @@ nvptx_init (void)
 
   CUDA_CALL (cuInit, 0);
 
+  int cuda_driver_version;
+  CUDA_CALL_ERET (NULL, cuDriverGetVersion, &cuda_driver_version);
+  snprintf (cuda_driver_version_s, sizeof cuda_driver_version_s,
+	    "CUDA Driver %u.%u",
+	    cuda_driver_version / 1000, cuda_driver_version % 1000 / 10);
+
   CUDA_CALL (cuDeviceGetCount, &ndevs);
   ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *)
 					    * ndevs);
+
   return true;
 }
 
@@ -491,6 +505,9 @@ nvptx_open_device (int n)
   for (int i = 0; i != GOMP_DIM_MAX; i++)
     ptx_dev->default_dims[i] = 0;
 
+  CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, sizeof ptx_dev->name,
+		  dev);
+
   ptx_dev->images = NULL;
   pthread_mutex_init (&ptx_dev->image_lock, NULL);
 
@@ -1104,6 +1121,74 @@ GOMP_OFFLOAD_get_num_devices (void)
   return nvptx_get_num_devices ();
 }
 
+union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value propval = { .val = 0 };
+
+  pthread_mutex_lock (&ptx_dev_lock);
+
+  if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
+    {
+      pthread_mutex_unlock (&ptx_dev_lock);
+      return propval;
+    }
+
+  struct ptx_device *ptx_dev = ptx_devices[n];
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_MEMORY:
+      {
+	size_t total_mem;
+
+	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
+	propval.val = total_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
+      {
+	size_t total_mem;
+	size_t free_mem;
+	CUdevice ctxdev;
+
+	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
+	if (ptx_dev->dev == ctxdev)
+	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	else if (ptx_dev->ctx)
+	  {
+	    CUcontext old_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
+	  }
+	else
+	  {
+	    CUcontext new_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
+			    ptx_dev->dev);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
+	  }
+	propval.val = free_mem;
+      }
+      break;
+    case GOMP_DEVICE_PROPERTY_NAME:
+      propval.ptr = ptx_dev->name;
+      break;
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      propval.ptr = "Nvidia";
+      break;
+    case GOMP_DEVICE_PROPERTY_DRIVER:
+      propval.ptr = cuda_driver_version_s;
+      break;
+    }
+
+  pthread_mutex_unlock (&ptx_dev_lock);
+  return propval;
+}
+
 bool
 GOMP_OFFLOAD_init_device (int n)
 {
diff --git a/libgomp/target.c b/libgomp/target.c
index 50a9c2b1df3..a1f80169f49 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -3002,6 +3002,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (get_caps);
   DLSYM (get_type);
   DLSYM (get_num_devices);
+  DLSYM (get_property);
   DLSYM (init_device);
   DLSYM (fini_device);
   DLSYM (load_image);
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
new file mode 100644
index 00000000000..4dd13c401d3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
@@ -0,0 +1,68 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions on Nvidia devices by comparing property values with
+   those obtained through the CUDA API. */
+/* { dg-additional-sources acc_get_property-aux.c } */
+/* { dg-additional-options "-lcuda -lcudart" } */
+/* { dg-do run { target openacc_nvidia_accel_selected } } */
+
+#include <openacc.h>
+#include <cuda.h>
+#include <cuda_runtime_api.h>
+#include <string.h>
+#include <stdio.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+int main ()
+{
+  int dev_count;
+  cudaGetDeviceCount (&dev_count);
+
+  for (int dev_num = 0; dev_num < dev_count; ++dev_num)
+    {
+      if (cudaSetDevice (dev_num) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaSetDevice failed.\n");
+	  abort ();
+	}
+
+      printf("Checking device %d\n", dev_num);
+
+      const char *vendor = "Nvidia";
+      size_t free_mem;
+      size_t total_mem;
+      if (cudaMemGetInfo(&free_mem, &total_mem) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaMemGetInfo failed.\n");
+	  abort ();
+	}
+
+      struct cudaDeviceProp p;
+      if (cudaGetDeviceProperties(&p, dev_num) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaGetDeviceProperties failed.\n");
+	  abort ();
+	}
+
+      int driver_version;
+      if (cudaDriverGetVersion(&driver_version) != cudaSuccess)
+	{
+	  fprintf (stderr, "cudaDriverGetVersion failed.\n");
+	  abort ();
+	}
+      /* The version string should contain the version of the CUDA Toolkit
+	 in the same MAJOR.MINOR format that is used by Nvidia.
+	 The format string below is the same that is used by the deviceQuery
+	 program, which belongs to Nvidia's CUDA samples, to print the version. */
+      char driver[30];
+      snprintf (driver, sizeof driver, "CUDA Driver %u.%u",
+		driver_version / 1000, driver_version % 1000 / 10);
+
+      expect_device_properties(acc_device_nvidia, dev_num,
+			       total_mem, free_mem, vendor, p.name, driver);
+    }
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
new file mode 100644
index 00000000000..92565000e49
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
@@ -0,0 +1,19 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions for the host device. */
+/* { dg-additional-sources acc_get_property-aux.c } */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stdio.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+int main()
+{
+  printf ("Checking acc_device_host device properties\n");
+  expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0");
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
new file mode 100644
index 00000000000..952bdbf6aea
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
@@ -0,0 +1,80 @@
+/* Auxiliary functions for acc_get_property tests */
+/* { dg-do compile  { target skip-all-targets } } */
+
+#include <openacc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ int expected_total_mem, int expected_free_mem,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver)
+{
+  const char *vendor = acc_get_property_string (dev_num, dev_type,
+						acc_property_vendor);
+  if (strcmp (vendor, expected_vendor))
+    {
+      fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
+	       "but was \"%s\".\n", expected_vendor, vendor);
+      abort ();
+    }
+
+  int total_mem = acc_get_property (dev_num, dev_type,
+				    acc_property_memory);
+  if (total_mem != expected_total_mem)
+    {
+      fprintf (stderr, "Expected acc_property_memory to equal %d, "
+	       "but was %d.\n", expected_total_mem, total_mem);
+      abort ();
+
+    }
+
+  int free_mem = acc_get_property (dev_num, dev_type,
+				   acc_property_free_memory);
+  if (free_mem != expected_free_mem)
+    {
+      fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
+	       "but was %d.\n", expected_free_mem, free_mem);
+      abort ();
+    }
+
+  const char *name = acc_get_property_string (dev_num, dev_type,
+					      acc_property_name);
+  if (strcmp (name, expected_name))
+    {
+      fprintf(stderr, "Expected acc_property_name to equal \"%s\", "
+	      "but was \"%s\".\n", expected_name, name);
+      abort ();
+    }
+
+  const char *driver = acc_get_property_string (dev_num, dev_type,
+						acc_property_driver);
+  if (strcmp (expected_driver, driver))
+    {
+      fprintf (stderr, "Expected acc_property_driver to equal %s, "
+	       "but was %s.\n", expected_driver, driver);
+      abort ();
+    }
+
+  int unknown_property = 16058;
+  int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
+  if (v != 0)
+    {
+      fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
+	       "but was %d.\n", v);
+      abort ();
+    }
+
+  int unknown_property2 = -16058;
+  const char *s = acc_get_property_string (dev_num, dev_type, (acc_device_property_t)unknown_property2);
+  if (s != NULL)
+    {
+      fprintf (stderr, "Expected value of unknown string property to be NULL, "
+	       "but was %d.\n", s);
+      abort ();
+    }
+
+
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
new file mode 100644
index 00000000000..ac523898c60
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
@@ -0,0 +1,75 @@
+/* Test the `acc_get_property' and '`acc_get_property_string' library
+   functions by printing the results of those functions for all devices
+   of all device types mentioned in the OpenACC standard.
+
+   See also acc_get_property.f90. */
+/* { dg-do run } */
+
+#include <openacc.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Print the values of the properties of all devices of the given type
+   and do basic device independent validation. */
+
+void
+print_device_properties(acc_device_t type)
+{
+  const char *s;
+  size_t v;
+
+  int dev_count = acc_get_num_devices(type);
+
+  for (int i = 0; i < dev_count; ++i)
+    {
+      printf("  Device %d:\n", i+1);
+
+      s = acc_get_property_string (i, type, acc_property_vendor);
+      printf ("    Vendor: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_vendor should not be null or empty.\n");
+	  abort ();
+	}
+
+      v = acc_get_property (i, type,  acc_property_memory);
+      printf ("    Total memory: %zd\n", v);
+
+      v = acc_get_property (i, type, acc_property_free_memory);
+      printf ("    Free memory: %zd\n", v);
+
+      s = acc_get_property_string (i, type, acc_property_name);
+      printf ("    Name: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_name should not be null or empty.\n");
+	  abort ();
+	}
+
+      s = acc_get_property_string (i, type, acc_property_driver);
+      printf ("    Driver: %s\n", s);
+      if (s == NULL || *s == 0)
+	{
+	  fprintf (stderr, "acc_property_string should not be null or empty.\n");
+	  abort ();
+	}
+    }
+}
+
+int main ()
+{
+  printf("acc_device_none:\n");
+  /* For completness; not expected to print anything since there
+     should be no devices of this type. */
+  print_device_properties(acc_device_none);
+
+  printf("acc_device_default:\n");
+  print_device_properties(acc_device_default);
+
+  printf("acc_device_host:\n");
+  print_device_properties(acc_device_host);
+
+  printf("acc_device_not_host:\n");
+  print_device_properties(acc_device_not_host);
+}
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
new file mode 100644
index 00000000000..cb68d386c8d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
@@ -0,0 +1,92 @@
+! Test the `acc_get_property' and '`acc_get_property_string' library
+! functions by printing the results of those functions for all devices
+! of all device types mentioned in the OpenACC standard.
+!
+! See also acc_get_property.c
+! { dg-do run }
+
+program test
+  use openacc
+  implicit none
+
+  print *, "acc_device_none:"
+  ! For completeness; not expected to print anything
+  call print_device_properties (acc_device_none)
+
+  print *, "acc_device_default:"
+  call print_device_properties (acc_device_default)
+
+  print *, "acc_device_host:"
+  call print_device_properties (acc_device_host)
+
+  print *, "acc_device_not_host:"
+  call print_device_properties (acc_device_not_host)
+end program test
+
+! Print the values of the properties of all devices of the given type
+! and do basic device independent validation.
+subroutine print_device_properties (device_type)
+  use openacc
+  implicit none
+
+  integer, intent(in) :: device_type
+
+  integer :: device_count
+  integer :: device
+  integer(acc_device_property) :: v
+  character*256 :: s
+
+  device_count = acc_get_num_devices(device_type)
+
+  do device = 0, device_count - 1
+     print "(a, i0)", "  Device ", device
+
+     call acc_get_property_string (device, device_type, acc_property_vendor, s)
+     print "(a, a)", "    Vendor: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_vendor should not be empty."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, acc_property_memory)
+     print "(a, i0)", "    Total memory: ", v
+     if (v < 0) then
+        print *, "acc_property_memory should not be negative."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, acc_property_free_memory)
+     print "(a, i0)", "    Free memory: ", v
+     if (v < 0) then
+        print *, "acc_property_free_memory should not to be negative."
+        stop 1
+     end if
+
+     v = acc_get_property (device, device_type, int(2360, kind = acc_device_property))
+     if (v /= 0) then
+        print *, "Value of unknown numeric property should be 0."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, acc_property_name, s)
+     print "(a, a)", "    Name: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_name should not be empty."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, acc_property_driver, s)
+     print "(a, a)", "    Driver: ", trim (s)
+     if (s == "") then
+        print *, "acc_property_driver should not be empty."
+        stop 1
+     end if
+
+     call acc_get_property_string (device, device_type, int(4060, kind = acc_device_property), s)
+     if (s /= "") then
+        print *, "Value of unknown string property should be empty string."
+        stop 1
+     end if
+
+  end do
+end subroutine print_device_properties
diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
index d1678d0514e..40d97702b87 100644
--- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
+++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
@@ -174,6 +174,27 @@ GOMP_OFFLOAD_get_num_devices (void)
   return num_devices;
 }
 
+extern "C" union gomp_device_property_value
+GOMP_OFFLOAD_get_property (int n, int prop)
+{
+  union gomp_device_property_value nullval = { .val = 0 };
+
+  if (n >= num_devices)
+    {
+      GOMP_PLUGIN_error
+       ("Request for a property of a non-existing Intel MIC device %i", n);
+      return nullval;
+    }
+
+  switch (prop)
+    {
+    case GOMP_DEVICE_PROPERTY_VENDOR:
+      return (union gomp_device_property_value) { .ptr =  "Intel" };
+    default:
+      return nullval;
+    }
+}
+
 static bool
 offload (const char *file, uint64_t line, int device, const char *name,
 	 int num_vars, VarDesc *vars, const void **async_data)
-- 
2.17.1


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-20 17:11       ` Harwath, Frederik
@ 2019-12-21 23:01         ` Thomas Schwinge
  2019-12-22 22:20           ` Harwath, Frederik
  2020-01-10 23:44           ` Thomas Schwinge
  2020-01-16 16:03         ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge
                           ` (2 subsequent siblings)
  3 siblings, 2 replies; 38+ messages in thread
From: Thomas Schwinge @ 2019-12-21 23:01 UTC (permalink / raw)
  To: Frederik Harwath, frederik
  Cc: gcc-patches, tdevries, mjambor, Andrew Stubbs, Julian Brown,
	Tobias Burnus, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 3014 bytes --]

Hi Frederik!

On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>> | Before Frederik starts working on integrating this into GCC trunk, do you
>> | (Jakub) agree with the libgomp plugin interface changes as implemented by
>> | Maciej?  For example, top-level 'GOMP_OFFLOAD_get_property' function in
>> | 'struct gomp_device_descr' instead of stuffing this into its
>> | 'acc_dispatch_t openacc'.  (I never understood why the OpenACC functions
>> | need to be segregated like they are.)
>>
>> Jakub didn't answer, but I now myself decided that we should group this
>> with the other OpenACC libgomp-plugin functions, as this interface is
>> defined in terms of OpenACC-specific stuff such as 'acc_device_t'.
>> Frederik, please work on that, also try to move function definitions etc.
>> into appropriate places in case they aren't; ask if you need help.
>> That needs to be updated.
>
> Is it ok to do this in a separate follow-up patch?

Yes.  This doesn't affect anything but the libgomp-plugin interface.


>> > --- a/include/gomp-constants.h
>> > +++ b/include/gomp-constants.h
>> > @@ -178,6 +178,20 @@ enum gomp_map_kind
>> >=20=20
>> >  #define GOMP_DEVICE_ICV			-1
>> >  #define GOMP_DEVICE_HOST_FALLBACK	-2
>> > +#define GOMP_DEVICE_CURRENT		-3
>> [...]
>>
>> Not should if this should be grouped with 'GOMP_DEVICE_ICV',
>> 'GOMP_DEVICE_HOST_FALLBACK', for it is not related to there.
>>
>> [...]
>>
>> Should this actually get value '-1' instead of '-3'?  Or, is the OpenACC
>> 'acc_device_t' code already paying special attention to negative values
>> '-1', '-2'?  (I don't think so.)
>> | Also, 'acc_device_current' is a libgomp-internal thing (doesn't interface
>> | with the compiler proper), so strictly speaking 'GOMP_DEVICE_CURRENT'
>> | isn't needed in 'include/gomp-constants.h'.  But probably still a good
>> | idea to list it there, in this canonical place, to keep the several lists
>> | of device types coherent.
>> still wonder about that...  ;-)

> Changing the value of GOMP_DEVICE_ICV violates the following static asserts in oacc-parallel.c: [...]

Hmm, I didn't intend to suggest changing the 'GOMP_DEVICE_ICV' value,
which indeed can't/shouldn't be done.

I still think that 'GOMP_DEVICE_CURENT' should get value '-1' (and
probably be rename 'GOACC_DEVICE_CURRENT' to make more obvious that it's
not related to the 'GOMP_DEVICE_*' ones), but we shall have a look at
that later (before GCC 10 release); that's libgomp/OpenACC-internal,
doesn't affect anything else.

>> Maybe this stuff should move from 'include/gomp-constants.h' to
>> 'libgomp/oacc-int.h'.  I'll think about that again, when I'm awake again
>> tomorrow.  ;-)
>
> Have you made up your mind yet? :-)

Still sleepy.  ;-)


> Is it ok to commit the patch to trunk?

OK, thanks.  And then some follow-up/clean-up next year, also including
some of the open questions that I've snipped off here.


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-21 23:01         ` Thomas Schwinge
@ 2019-12-22 22:20           ` Harwath, Frederik
  2020-01-10 23:44           ` Thomas Schwinge
  1 sibling, 0 replies; 38+ messages in thread
From: Harwath, Frederik @ 2019-12-22 22:20 UTC (permalink / raw)
  To: Thomas Schwinge, frederik
  Cc: gcc-patches, tdevries, mjambor, Andrew Stubbs, Julian Brown,
	Tobias Burnus, Jakub Jelinek

Hi Thomas,

>> Is it ok to commit the patch to trunk?
> 
> OK, thanks.  And then some follow-up/clean-up next year, also including
> some of the open questions that I've snipped off here.

Right, thanks for the review! I have committed the patch as r279710 with a
minor change: I have disabled the new acc_get_property.{c,f90} tests for
the amdgcn offload target for now.

Best regards,
Frederik

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-21 23:01         ` Thomas Schwinge
  2019-12-22 22:20           ` Harwath, Frederik
@ 2020-01-10 23:44           ` Thomas Schwinge
  2020-01-30 16:14             ` Make OpenACC 'acc_get_property' with 'acc_device_current' work (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support) Thomas Schwinge
  1 sibling, 1 reply; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-10 23:44 UTC (permalink / raw)
  To: Frederik Harwath, gcc-patches
  Cc: tdevries, mjambor, Andrew Stubbs, Julian Brown, Tobias Burnus,
	Jakub Jelinek


[-- Attachment #1.1: Type: text/plain, Size: 2826 bytes --]

Hi!

On 2019-12-21T23:02:38+0100, I wrote:
> On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>>> > --- a/include/gomp-constants.h
>>> > +++ b/include/gomp-constants.h

>>> > +#define GOMP_DEVICE_CURRENT		-3

>>> Should this actually get value '-1' instead of '-3'?  Or, is the OpenACC
>>> 'acc_device_t' code already paying special attention to negative values
>>> '-1', '-2'?  (I don't think so.)

>>> | Also, 'acc_device_current' is a libgomp-internal thing (doesn't interface
>>> | with the compiler proper), so strictly speaking 'GOMP_DEVICE_CURRENT'
>>> | isn't needed in 'include/gomp-constants.h'.  But probably still a good
>>> | idea to list it there, in this canonical place, to keep the several lists
>>> | of device types coherent.

>>> I still wonder about that...  ;-)

> I still think that 'GOMP_DEVICE_CURENT' should get value '-1' (and
> probably be rename 'GOACC_DEVICE_CURRENT' to make more obvious that it's
> not related to the 'GOMP_DEVICE_*' ones), but we shall have a look at
> that later (before GCC 10 release); that's libgomp/OpenACC-internal,
> doesn't affect anything else.

That's still pending.  Recently,
<https://github.com/OpenACC/openacc-spec/issues/256> "Missing definition
for acc_device_current" got filed; let's (also/first) watch/wait what
comes out of that.


Also pending is the 'libgomp/plugin/plugin-gcn.c' update; Frederik is
working on that.


A few other (minor) open issue we shall discuss at some later point in
time.


>>> | Before Frederik starts working on integrating this into GCC trunk, do you
>>> | (Jakub) agree with the libgomp plugin interface changes as implemented by
>>> | Maciej?  For example, top-level 'GOMP_OFFLOAD_get_property' function in
>>> | 'struct gomp_device_descr' instead of stuffing this into its
>>> | 'acc_dispatch_t openacc'.  (I never understood why the OpenACC functions
>>> | need to be segregated like they are.)
>>>
>>> Jakub didn't answer, but I now myself decided that we should group this
>>> with the other OpenACC libgomp-plugin functions, as this interface is
>>> defined in terms of OpenACC-specific stuff such as 'acc_device_t'.

Done.  This also means that we don't anymore need (stub) implementations
in the libgomp plugins that don't implement OpenACC support.


>>> Maybe [stuff] should move from 'include/gomp-constants.h' to
>>> 'libgomp/oacc-int.h'.  I'll think about that again, when I'm awake again
>>> tomorrow.  ;-)
>>
>> Have you made up your mind yet? :-)
>
> Still sleepy.  ;-)

Done.  In the end, 'libgomp/libgomp-plugin.h' is the place to be, as that
defines, well, the libgomp plugin interface.  ;-)


See attached "OpenACC 'acc_get_property' cleanup"; committed to trunk in
r280150.


Grüße
 Thomas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-OpenACC-acc_get_property-cleanup.trunk.patch --]
[-- Type: text/x-diff, Size: 21654 bytes --]

From f98381a87233ddef09bf7d3a0d47807215930063 Mon Sep 17 00:00:00 2001
From: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Fri, 10 Jan 2020 22:24:36 +0000
Subject: [PATCH] OpenACC 'acc_get_property' cleanup

	include/
	* gomp-constants.h (enum gomp_device_property): Remove.
	libgomp/
	* libgomp-plugin.h (enum goacc_property): New.  Adjust all users
	to use this instead of 'enum gomp_device_property'.
	(GOMP_OFFLOAD_get_property): Rename to...
	(GOMP_OFFLOAD_openacc_get_property): ... this.  Adjust all users.
	* libgomp.h (struct gomp_device_descr): Move
	'GOMP_OFFLOAD_openacc_get_property'...
	(struct acc_dispatch_t): ... here.  Adjust all users.
	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): Remove.
	liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
	Remove.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@280150 138bc75d-0d04-0410-961f-82ee72b054a4
---
 include/ChangeLog                             |   4 +
 include/gomp-constants.h                      |  15 --
 libgomp/ChangeLog                             |   9 ++
 libgomp/libgomp-plugin.h                      |  36 ++++-
 libgomp/libgomp.h                             |   3 +-
 libgomp/oacc-host.c                           |  47 +++---
 libgomp/oacc-init.c                           |  10 +-
 libgomp/openacc.f90                           |   2 +-
 libgomp/openacc.h                             |   3 +-
 libgomp/plugin/plugin-gcn.c                   |  22 +--
 libgomp/plugin/plugin-hsa.c                   |  26 ----
 libgomp/plugin/plugin-nvptx.c                 | 138 +++++++++---------
 libgomp/target.c                              |   4 +-
 liboffloadmic/ChangeLog                       |   5 +
 .../plugin/libgomp-plugin-intelmic.cpp        |  21 ---
 15 files changed, 163 insertions(+), 182 deletions(-)

diff --git a/include/ChangeLog b/include/ChangeLog
index 0069df3c5c6..8a2feb911cb 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2020-01-10  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* gomp-constants.h (enum gomp_device_property): Remove.
+
 2020-01-01  Jakub Jelinek  <jakub@redhat.com>
 
 	Update copyright years.
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 5a7cc2c3f01..1587e4d2ba2 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -199,21 +199,6 @@ enum gomp_map_kind
 #define GOMP_DEVICE_ICV			-1
 #define GOMP_DEVICE_HOST_FALLBACK	-2
 
-/* Device property codes.  Keep in sync with
-   libgomp/{openacc.h,openacc.f90}:acc_device_property_t */
-/* Start from 1 to catch uninitialized use.  */
-enum gomp_device_property
-  {
-   GOMP_DEVICE_PROPERTY_MEMORY =	1,
-   GOMP_DEVICE_PROPERTY_FREE_MEMORY = 	2,
-   GOMP_DEVICE_PROPERTY_NAME =		0x10001,
-   GOMP_DEVICE_PROPERTY_VENDOR =	0x10002,
-   GOMP_DEVICE_PROPERTY_DRIVER =	0x10003
-  };
-
-/* Internal property mask to tell numeric and string values apart.  */
-#define GOMP_DEVICE_PROPERTY_STRING_MASK	0x10000
-
 /* GOMP_task/GOMP_taskloop* flags argument.  */
 #define GOMP_TASK_FLAG_UNTIED		(1 << 0)
 #define GOMP_TASK_FLAG_FINAL		(1 << 1)
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 81d0c164a3a..de286ddac7c 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,5 +1,14 @@
 2020-01-10  Thomas Schwinge  <thomas@codesourcery.com>
 
+	* libgomp-plugin.h (enum goacc_property): New.  Adjust all users
+	to use this instead of 'enum gomp_device_property'.
+	(GOMP_OFFLOAD_get_property): Rename to...
+	(GOMP_OFFLOAD_openacc_get_property): ... this.  Adjust all users.
+	* libgomp.h (struct gomp_device_descr): Move
+	'GOMP_OFFLOAD_openacc_get_property'...
+	(struct acc_dispatch_t): ... here.  Adjust all users.
+	* plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): Remove.
+
 	* target.c (gomp_map_vars_internal)
 	<GOMP_MAP_USE_DEVICE_PTR_IF_PRESENT>: Clean up/elaborate code
 	paths.
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index 2559ce0ea3a..64f138d3821 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -54,13 +54,6 @@ enum offload_target_type
   OFFLOAD_TARGET_TYPE_GCN = 8
 };
 
-/* Container type for passing device properties.  */
-union gomp_device_property_value
-{
-  const char *ptr;
-  size_t val;
-};
-
 /* Opaque type to represent plugin-dependent implementation of an
    OpenACC asynchronous queue.  */
 struct goacc_asyncqueue;
@@ -75,6 +68,32 @@ struct goacc_asyncqueue_list
 typedef struct goacc_asyncqueue *goacc_aq;
 typedef struct goacc_asyncqueue_list *goacc_aq_list;
 
+
+/* OpenACC 'acc_get_property' support.  */
+
+/* Device property values.  Keep in sync with
+   'libgomp/{openacc.h,openacc.f90}:acc_device_property_t'.  */
+enum goacc_property
+  {
+   /* Mask to tell numeric and string values apart.  */
+#define GOACC_PROPERTY_STRING_MASK 0x10000
+
+   /* Start from 1 to catch uninitialized use.  */
+   GOACC_PROPERTY_MEMORY =		1,
+   GOACC_PROPERTY_FREE_MEMORY =		2,
+   GOACC_PROPERTY_NAME =		GOACC_PROPERTY_STRING_MASK | 1,
+   GOACC_PROPERTY_VENDOR =		GOACC_PROPERTY_STRING_MASK | 2,
+   GOACC_PROPERTY_DRIVER =		GOACC_PROPERTY_STRING_MASK | 3
+  };
+
+/* Container type for passing device properties.  */
+union goacc_property_value
+{
+  const char *ptr;
+  size_t val;
+};
+
+
 /* Auxiliary struct, used for transferring pairs of addresses from plugin
    to libgomp.  */
 struct addr_pair
@@ -101,7 +120,6 @@ extern const char *GOMP_OFFLOAD_get_name (void);
 extern unsigned int GOMP_OFFLOAD_get_caps (void);
 extern int GOMP_OFFLOAD_get_type (void);
 extern int GOMP_OFFLOAD_get_num_devices (void);
-extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
 extern bool GOMP_OFFLOAD_init_device (int);
 extern bool GOMP_OFFLOAD_fini_device (int);
 extern unsigned GOMP_OFFLOAD_version (void);
@@ -141,6 +159,8 @@ extern void *GOMP_OFFLOAD_openacc_cuda_get_current_context (void);
 extern void *GOMP_OFFLOAD_openacc_cuda_get_stream (struct goacc_asyncqueue *);
 extern int GOMP_OFFLOAD_openacc_cuda_set_stream (struct goacc_asyncqueue *,
 						 void *);
+extern union goacc_property_value
+  GOMP_OFFLOAD_openacc_get_property (int, enum goacc_property);
 
 #ifdef __cplusplus
 }
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index 44703aaae6a..f5415bb156c 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1068,6 +1068,8 @@ typedef struct acc_dispatch_t
     __typeof (GOMP_OFFLOAD_openacc_async_host2dev) *host2dev_func;
   } async;
 
+  __typeof (GOMP_OFFLOAD_openacc_get_property) *get_property_func;
+
   /* NVIDIA target specific routines.  */
   struct {
     __typeof (GOMP_OFFLOAD_openacc_cuda_get_current_device)
@@ -1113,7 +1115,6 @@ struct gomp_device_descr
   __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
   __typeof (GOMP_OFFLOAD_get_type) *get_type_func;
   __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
-  __typeof (GOMP_OFFLOAD_get_property) *get_property_func;
   __typeof (GOMP_OFFLOAD_init_device) *init_device_func;
   __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
   __typeof (GOMP_OFFLOAD_version) *version_func;
diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c
index 22c18942752..46387897b13 100644
--- a/libgomp/oacc-host.c
+++ b/libgomp/oacc-host.c
@@ -59,27 +59,6 @@ host_get_num_devices (void)
   return 1;
 }
 
-static union gomp_device_property_value
-host_get_property (int n, int prop)
-{
-  union gomp_device_property_value nullval = { .val = 0 };
-
-  if (n >= host_get_num_devices ())
-    return nullval;
-
-  switch (prop)
-    {
-    case GOMP_DEVICE_PROPERTY_NAME:
-      return (union gomp_device_property_value) { .ptr = "GOMP" };
-    case GOMP_DEVICE_PROPERTY_VENDOR:
-      return (union gomp_device_property_value) { .ptr = "GNU" };
-    case GOMP_DEVICE_PROPERTY_DRIVER:
-      return (union gomp_device_property_value) { .ptr = VERSION };
-    default:
-      return nullval;
-    }
-}
-
 static bool
 host_init_device (int n __attribute__ ((unused)))
 {
@@ -245,6 +224,29 @@ host_openacc_async_destruct (struct goacc_asyncqueue *aq
   return true;
 }
 
+static union goacc_property_value
+host_openacc_get_property (int n, enum goacc_property prop)
+{
+  union goacc_property_value nullval = { .val = 0 };
+
+  if (n >= host_get_num_devices ())
+    return nullval;
+
+  switch (prop)
+    {
+    case GOACC_PROPERTY_NAME:
+      return (union goacc_property_value) { .ptr = "GOMP" };
+    case GOACC_PROPERTY_VENDOR:
+      return (union goacc_property_value) { .ptr = "GNU" };
+    case GOACC_PROPERTY_DRIVER:
+      return (union goacc_property_value) { .ptr = VERSION };
+    case GOACC_PROPERTY_MEMORY:
+    case GOACC_PROPERTY_FREE_MEMORY:
+    default:
+      return nullval;
+    }
+}
+
 static void *
 host_openacc_create_thread_data (int ord __attribute__ ((unused)))
 {
@@ -269,7 +271,6 @@ static struct gomp_device_descr host_dispatch =
     .get_caps_func = host_get_caps,
     .get_type_func = host_get_type,
     .get_num_devices_func = host_get_num_devices,
-    .get_property_func = host_get_property,
     .init_device_func = host_init_device,
     .fini_device_func = host_fini_device,
     .version_func = host_version,
@@ -303,6 +304,8 @@ static struct gomp_device_descr host_dispatch =
 	.host2dev_func = host_openacc_async_host2dev,
       },
 
+      .get_property_func = host_openacc_get_property,
+
       .cuda = {
 	.get_current_device_func = NULL,
 	.get_current_context_func = NULL,
diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index d15f08f7e18..89a30b3e716 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -760,14 +760,14 @@ acc_set_device_num (int ord, acc_device_t d)
 
 ialias (acc_set_device_num)
 
-static union gomp_device_property_value
+static union goacc_property_value
 get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
 {
   goacc_lazy_initialize ();
   struct goacc_thread *thr = goacc_thread ();
 
   if (d == acc_device_current && thr && thr->dev)
-    return thr->dev->get_property_func (thr->dev->target_id, prop);
+    return thr->dev->openacc.get_property_func (thr->dev->target_id, prop);
 
   gomp_mutex_lock (&acc_device_lock);
 
@@ -789,7 +789,7 @@ get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
 
   assert (dev);
 
-  return dev->get_property_func (dev->target_id, prop);
+  return dev->openacc.get_property_func (dev->target_id, prop);
 }
 
 size_t
@@ -798,7 +798,7 @@ acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
   if (!known_device_type_p (d))
     unknown_device_type_error(d);
 
-  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+  if (prop & GOACC_PROPERTY_STRING_MASK)
     return 0;
   else
     return get_property_any (ord, d, prop).val;
@@ -812,7 +812,7 @@ acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
   if (!known_device_type_p (d))
     unknown_device_type_error(d);
 
-  if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
+  if (prop & GOACC_PROPERTY_STRING_MASK)
     return get_property_any (ord, d, prop).ptr;
   else
     return NULL;
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index a3083168a3a..6c92c7c12c9 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -53,7 +53,7 @@ module openacc_kinds
 
   integer, parameter :: acc_device_property = c_size_t
 
-  ! Keep in sync with include/gomp-constants.h.
+  ! Keep in sync with 'libgomp/libgomp-plugin.h:goacc_property'.
   integer (acc_device_property), parameter :: acc_property_memory = 1
   integer (acc_device_property), parameter :: acc_property_free_memory = 2
   integer (acc_device_property), parameter :: acc_property_name = int(Z'10001')
diff --git a/libgomp/openacc.h b/libgomp/openacc.h
index 66786d7521f..62b2b0ea559 100644
--- a/libgomp/openacc.h
+++ b/libgomp/openacc.h
@@ -64,8 +64,7 @@ typedef enum acc_device_t {
 } acc_device_t;
 
 typedef enum acc_device_property_t {
-  /* Keep in sync with include/gomp-constants.h.  */
-  /* Start from 1 to catch uninitialized use.  */
+  /* Keep in sync with 'libgomp/libgomp-plugin.h:goacc_property'.  */
   acc_property_memory = 1,
   acc_property_free_memory = 2,
   acc_property_name = 0x10001,
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index b5ca7c1b4bd..16ce251f3a5 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -3236,17 +3236,6 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
-union gomp_device_property_value
-GOMP_OFFLOAD_get_property (int device, int prop)
-{
-  /* Stub. Check device and return default value for unsupported properties. */
-  /* TODO: Implement this function. */
-  get_agent_info (device);
-
-  union gomp_device_property_value nullval = { .val = 0 };
-  return nullval;
-}
-
 /* Initialize device (agent) number N so that it can be used for computation.
    Return TRUE on success.  */
 
@@ -3999,6 +3988,17 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src,
   return true;
 }
 
+union goacc_property_value
+GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop)
+{
+  /* Stub. Check device and return default value for unsupported properties. */
+  /* TODO: Implement this function. */
+  get_agent_info (device);
+
+  union goacc_property_value nullval = { .val = 0 };
+  return nullval;
+}
+
 /* Set up plugin-specific thread-local-data (host-side).  */
 
 void *
diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c
index b04923b1920..abd3bc64163 100644
--- a/libgomp/plugin/plugin-hsa.c
+++ b/libgomp/plugin/plugin-hsa.c
@@ -699,32 +699,6 @@ GOMP_OFFLOAD_get_num_devices (void)
   return hsa_context.agent_count;
 }
 
-/* Part of the libgomp plugin interface.  Return the value of property
-   PROP of agent number N.  */
-
-union gomp_device_property_value
-GOMP_OFFLOAD_get_property (int n, int prop)
-{
-  union gomp_device_property_value nullval = { .val = 0 };
-
-  if (!init_hsa_context ())
-    return nullval;
-  if (n >= hsa_context.agent_count)
-    {
-      GOMP_PLUGIN_error
-	("Request for a property of a non-existing HSA device %i", n);
-      return nullval;
-    }
-
-  switch (prop)
-    {
-    case GOMP_DEVICE_PROPERTY_VENDOR:
-      return (union gomp_device_property_value) { .ptr = "HSA" };
-    default:
-      return nullval;
-    }
-}
-
 /* Part of the libgomp plugin interface.  Initialize agent number N so that it
    can be used for computation.  Return TRUE on success.  */
 
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index e867b4cdedb..6033c71a9db 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -1121,74 +1121,6 @@ GOMP_OFFLOAD_get_num_devices (void)
   return nvptx_get_num_devices ();
 }
 
-union gomp_device_property_value
-GOMP_OFFLOAD_get_property (int n, int prop)
-{
-  union gomp_device_property_value propval = { .val = 0 };
-
-  pthread_mutex_lock (&ptx_dev_lock);
-
-  if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
-    {
-      pthread_mutex_unlock (&ptx_dev_lock);
-      return propval;
-    }
-
-  struct ptx_device *ptx_dev = ptx_devices[n];
-  switch (prop)
-    {
-    case GOMP_DEVICE_PROPERTY_MEMORY:
-      {
-	size_t total_mem;
-
-	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
-	propval.val = total_mem;
-      }
-      break;
-    case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
-      {
-	size_t total_mem;
-	size_t free_mem;
-	CUdevice ctxdev;
-
-	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
-	if (ptx_dev->dev == ctxdev)
-	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
-	else if (ptx_dev->ctx)
-	  {
-	    CUcontext old_ctx;
-
-	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
-	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
-	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
-	  }
-	else
-	  {
-	    CUcontext new_ctx;
-
-	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
-			    ptx_dev->dev);
-	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
-	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
-	  }
-	propval.val = free_mem;
-      }
-      break;
-    case GOMP_DEVICE_PROPERTY_NAME:
-      propval.ptr = ptx_dev->name;
-      break;
-    case GOMP_DEVICE_PROPERTY_VENDOR:
-      propval.ptr = "Nvidia";
-      break;
-    case GOMP_DEVICE_PROPERTY_DRIVER:
-      propval.ptr = cuda_driver_version_s;
-      break;
-    }
-
-  pthread_mutex_unlock (&ptx_dev_lock);
-  return propval;
-}
-
 bool
 GOMP_OFFLOAD_init_device (int n)
 {
@@ -1818,6 +1750,76 @@ GOMP_OFFLOAD_openacc_async_dev2host (int ord, void *dst, const void *src,
   return true;
 }
 
+union goacc_property_value
+GOMP_OFFLOAD_openacc_get_property (int n, enum goacc_property prop)
+{
+  union goacc_property_value propval = { .val = 0 };
+
+  pthread_mutex_lock (&ptx_dev_lock);
+
+  if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
+    {
+      pthread_mutex_unlock (&ptx_dev_lock);
+      return propval;
+    }
+
+  struct ptx_device *ptx_dev = ptx_devices[n];
+  switch (prop)
+    {
+    case GOACC_PROPERTY_MEMORY:
+      {
+	size_t total_mem;
+
+	CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
+	propval.val = total_mem;
+      }
+      break;
+    case GOACC_PROPERTY_FREE_MEMORY:
+      {
+	size_t total_mem;
+	size_t free_mem;
+	CUdevice ctxdev;
+
+	CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
+	if (ptx_dev->dev == ctxdev)
+	  CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	else if (ptx_dev->ctx)
+	  {
+	    CUcontext old_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
+	  }
+	else
+	  {
+	    CUcontext new_ctx;
+
+	    CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
+			    ptx_dev->dev);
+	    CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
+	    CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
+	  }
+	propval.val = free_mem;
+      }
+      break;
+    case GOACC_PROPERTY_NAME:
+      propval.ptr = ptx_dev->name;
+      break;
+    case GOACC_PROPERTY_VENDOR:
+      propval.ptr = "Nvidia";
+      break;
+    case GOACC_PROPERTY_DRIVER:
+      propval.ptr = cuda_driver_version_s;
+      break;
+    default:
+      break;
+    }
+
+  pthread_mutex_unlock (&ptx_dev_lock);
+  return propval;
+}
+
 /* Adjust launch dimensions: pick good values for number of blocks and warps
    and ensure that number of warps does not exceed CUDA limits as well as GCC's
    own limits.  */
diff --git a/libgomp/target.c b/libgomp/target.c
index 38de1c0cf92..3df007283f4 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -3028,7 +3028,6 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
   DLSYM (get_caps);
   DLSYM (get_type);
   DLSYM (get_num_devices);
-  DLSYM (get_property);
   DLSYM (init_device);
   DLSYM (fini_device);
   DLSYM (load_image);
@@ -3061,7 +3060,8 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
 			 openacc_async_queue_callback)
 	  || !DLSYM_OPT (openacc.async.exec, openacc_async_exec)
 	  || !DLSYM_OPT (openacc.async.dev2host, openacc_async_dev2host)
-	  || !DLSYM_OPT (openacc.async.host2dev, openacc_async_host2dev))
+	  || !DLSYM_OPT (openacc.async.host2dev, openacc_async_host2dev)
+	  || !DLSYM_OPT (openacc.get_property, openacc_get_property))
 	{
 	  /* Require all the OpenACC handlers if we have
 	     GOMP_OFFLOAD_CAP_OPENACC_200.  */
diff --git a/liboffloadmic/ChangeLog b/liboffloadmic/ChangeLog
index b5fae878e9d..eba51003627 100644
--- a/liboffloadmic/ChangeLog
+++ b/liboffloadmic/ChangeLog
@@ -1,3 +1,8 @@
+2020-01-10  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
+	Remove.
+
 2019-12-22  Maciej W. Rozycki  <macro@codesourcery.com>
 	    Frederik Harwath  <frederik@codesourcery.com>
 	    Thomas Schwinge  <tschwinge@codesourcery.com>
diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
index 40d97702b87..d1678d0514e 100644
--- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
+++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
@@ -174,27 +174,6 @@ GOMP_OFFLOAD_get_num_devices (void)
   return num_devices;
 }
 
-extern "C" union gomp_device_property_value
-GOMP_OFFLOAD_get_property (int n, int prop)
-{
-  union gomp_device_property_value nullval = { .val = 0 };
-
-  if (n >= num_devices)
-    {
-      GOMP_PLUGIN_error
-       ("Request for a property of a non-existing Intel MIC device %i", n);
-      return nullval;
-    }
-
-  switch (prop)
-    {
-    case GOMP_DEVICE_PROPERTY_VENDOR:
-      return (union gomp_device_property_value) { .ptr =  "Intel" };
-    default:
-      return nullval;
-    }
-}
-
 static bool
 offload (const char *file, uint64_t line, int device, const char *name,
 	 int num_vars, VarDesc *vars, const void **async_data)
-- 
2.17.1


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-20 17:11       ` Harwath, Frederik
  2019-12-21 23:01         ` Thomas Schwinge
@ 2020-01-16 16:03         ` Thomas Schwinge
  2020-01-20 14:20           ` Harwath, Frederik
  2020-01-27 14:57         ` Fortran 'acc_get_property' return type (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support) Thomas Schwinge
  2020-01-28 15:31         ` [PATCH] Add OpenACC acc_get_property support for AMD GCN Harwath, Frederik
  3 siblings, 1 reply; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-16 16:03 UTC (permalink / raw)
  To: Frederik Harwath; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 7097 bytes --]

Hi Frederik!

On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c

I suggest to rename this one to 'acc_get_property-nvptx.c'.

> @@ -0,0 +1,68 @@
> +/* Test the `acc_get_property' and '`acc_get_property_string' library
> +   functions on Nvidia devices by comparing property values with
> +   those obtained through the CUDA API. */
> +/* { dg-additional-sources acc_get_property-aux.c } */
> +/* { dg-additional-options "-lcuda -lcudart" } */
> +/* { dg-do run { target openacc_nvidia_accel_selected } } */
> +
> +#include <openacc.h>
> +#include <cuda.h>
> +#include <cuda_runtime_api.h>
> +#include <string.h>
> +#include <stdio.h>
> +
> +void expect_device_properties
> +(acc_device_t dev_type, int dev_num,
> + int expected_total_mem, int expected_free_mem,
> + const char* expected_vendor, const char* expected_name,
> + const char* expected_driver);
> +
> +int main ()
> +{
> +  int dev_count;
> +  cudaGetDeviceCount (&dev_count);
> +
> +  for (int dev_num = 0; dev_num < dev_count; ++dev_num)
> +    {
> +      if (cudaSetDevice (dev_num) != cudaSuccess)
> +	{
> +	  fprintf (stderr, "cudaSetDevice failed.\n");
> +	  abort ();
> +	}
> +
> +      printf("Checking device %d\n", dev_num);
> +
> +      const char *vendor = "Nvidia";
> +      size_t free_mem;
> +      size_t total_mem;
> +      if (cudaMemGetInfo(&free_mem, &total_mem) != cudaSuccess)
> +	{
> +	  fprintf (stderr, "cudaMemGetInfo failed.\n");
> +	  abort ();
> +	}
> +
> +      struct cudaDeviceProp p;
> +      if (cudaGetDeviceProperties(&p, dev_num) != cudaSuccess)
> +	{
> +	  fprintf (stderr, "cudaGetDeviceProperties failed.\n");
> +	  abort ();
> +	}
> +
> +      int driver_version;
> +      if (cudaDriverGetVersion(&driver_version) != cudaSuccess)
> +	{
> +	  fprintf (stderr, "cudaDriverGetVersion failed.\n");
> +	  abort ();
> +	}
> +      /* The version string should contain the version of the CUDA Toolkit
> +	 in the same MAJOR.MINOR format that is used by Nvidia.
> +	 The format string below is the same that is used by the deviceQuery
> +	 program, which belongs to Nvidia's CUDA samples, to print the version. */
> +      char driver[30];
> +      snprintf (driver, sizeof driver, "CUDA Driver %u.%u",
> +		driver_version / 1000, driver_version % 1000 / 10);
> +
> +      expect_device_properties(acc_device_nvidia, dev_num,

This assumes that the 'cuda*' interfaces and OpenACC/libgomp interfaces
handle/order device numbers in the same way -- which it seems they do,
but just noting this in case this becomes an issue at some point.

> +			       total_mem, free_mem, vendor, p.name, driver);
> +    }
> +}

So I just witnessed a FAIL here, because:

    Expected acc_property_free_memory to equal -929226752, but was -928956416.

Aside from improper data types being used for storing/printing the memory
information, we have to expect 'acc_property_free_memory' to change
between two invocations.  ;-)

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c

I suggest to rename this one to 'acc_get_property-host.c'.

> @@ -0,0 +1,19 @@
> +/* Test the `acc_get_property' and '`acc_get_property_string' library
> +   functions for the host device. */
> +/* { dg-additional-sources acc_get_property-aux.c } */
> +/* { dg-do run } */
> +
> +#include <openacc.h>
> +#include <stdio.h>
> +
> +void expect_device_properties
> +(acc_device_t dev_type, int dev_num,
> + int expected_total_mem, int expected_free_mem,
> + const char* expected_vendor, const char* expected_name,
> + const char* expected_driver);
> +
> +int main()
> +{
> +  printf ("Checking acc_device_host device properties\n");
> +  expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0");
> +}

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
> @@ -0,0 +1,80 @@
> +/* Auxiliary functions for acc_get_property tests */
> +/* { dg-do compile  { target skip-all-targets } } */
> +
> +#include <openacc.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +
> +void expect_device_properties
> +(acc_device_t dev_type, int dev_num,
> + int expected_total_mem, int expected_free_mem,
> + const char* expected_vendor, const char* expected_name,
> + const char* expected_driver)
> +{
> +  const char *vendor = acc_get_property_string (dev_num, dev_type,
> +						acc_property_vendor);
> +  if (strcmp (vendor, expected_vendor))
> +    {
> +      fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
> +	       "but was \"%s\".\n", expected_vendor, vendor);
> +      abort ();
> +    }
> +
> +  int total_mem = acc_get_property (dev_num, dev_type,
> +				    acc_property_memory);
> +  if (total_mem != expected_total_mem)
> +    {
> +      fprintf (stderr, "Expected acc_property_memory to equal %d, "
> +	       "but was %d.\n", expected_total_mem, total_mem);
> +      abort ();
> +
> +    }
> +
> +  int free_mem = acc_get_property (dev_num, dev_type,
> +				   acc_property_free_memory);
> +  if (free_mem != expected_free_mem)
> +    {
> +      fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
> +	       "but was %d.\n", expected_free_mem, free_mem);
> +      abort ();
> +    }

Better to just verify that 'free_mem >= 0' (by means of 'size_t' data
type, I suppose), and 'free_mem <= total_mem'?

(..., and for avoidance of doubt: I think there's no point in
special-casing this one for 'acc_device_host' where we know that
'free_mem' is always zero -- this may change in the future.)

> +
> +  const char *name = acc_get_property_string (dev_num, dev_type,
> +					      acc_property_name);
> +  if (strcmp (name, expected_name))
> +    {
> +      fprintf(stderr, "Expected acc_property_name to equal \"%s\", "
> +	      "but was \"%s\".\n", expected_name, name);
> +      abort ();
> +    }
> +
> +  const char *driver = acc_get_property_string (dev_num, dev_type,
> +						acc_property_driver);
> +  if (strcmp (expected_driver, driver))
> +    {
> +      fprintf (stderr, "Expected acc_property_driver to equal %s, "
> +	       "but was %s.\n", expected_driver, driver);
> +      abort ();
> +    }
> +
> +  int unknown_property = 16058;
> +  int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
> +  if (v != 0)
> +    {
> +      fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
> +	       "but was %d.\n", v);
> +      abort ();
> +    }
> +
> +  int unknown_property2 = -16058;
> +  const char *s = acc_get_property_string (dev_num, dev_type, (acc_device_property_t)unknown_property2);
> +  if (s != NULL)
> +    {
> +      fprintf (stderr, "Expected value of unknown string property to be NULL, "
> +	       "but was %d.\n", s);
> +      abort ();
> +    }
> +
> +
> +}


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2020-01-16 16:03         ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge
@ 2020-01-20 14:20           ` Harwath, Frederik
  2020-01-23 15:08             ` Thomas Schwinge
  0 siblings, 1 reply; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-20 14:20 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1689 bytes --]

Hi Thomas,
I have attached a patch containing the changes that you suggested.

On 16.01.20 17:00, Thomas Schwinge wrote:

> On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>> --- /dev/null
>> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
> 
> I suggest to rename this one to 'acc_get_property-nvptx.c'> [...]
>> --- /dev/null
>> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c

> I suggest to rename this one to 'acc_get_property-host.c'.

I renamed both.

> This assumes that the 'cuda*' interfaces and OpenACC/libgomp interfaces
> handle/order device numbers in the same way -- which it seems they do,
> but just noting this in case this becomes an issue at some point.

Correct, I have added a corresponding comment to acc_get_property-nvptx.c.

> Aside from improper data types being used for storing/printing the memory
> information, we have to expect 'acc_property_free_memory' to change
> between two invocations.  ;-)

Right! I have removed the assertion and changed it into ...
> 
> Better to just verify that 'free_mem >= 0' (by means of 'size_t' data
> type, I suppose), and 'free_mem <= total_mem'?

... this.

> 
> (..., and for avoidance of doubt: I think there's no point in
> special-casing this one for 'acc_device_host' where we know that
> 'free_mem' is always zero -- this may change in the future.)

Sure! But with the new "free_mem <= total_mem" assertion and since we assert
total_mem == 0 and since free_mem >= 0, we effectively also assert that in the
test right now ;-).


Ok to push the commit to master?

Best regards,
Frederik

[-- Attachment #2: 0001-Fix-expectation-and-types-in-acc_get_property-tests.patch --]
[-- Type: text/x-patch, Size: 6543 bytes --]

From ef5a959bedc3214e86d6a683a02b693d82847ecd Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Mon, 20 Jan 2020 14:07:03 +0100
Subject: [PATCH] Fix expectation and types in acc_get_property tests

* Weaken expectation concerning acc_property_free_memory.
  Do not expect the value returned by CUDA since that value might have
  changed in the meantime.
* Use correct type for the results of calls to acc_get_property in tests.

libgomp/
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
	(expect_device_properties): Remove "expected_free_mem" argument,
	change "expected_total_mem" argument type to size_t;
	change types of acc_get_property results to size_t.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c: Adapt and
	rename to ...
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c: ... this.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c: Adapt and
	rename to ...
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c: ... this.

Reviewed-by: Thomas Schwinge  <thomas@codesourcery.com>
---
 .../acc_get_property-aux.c                    | 28 +++++++++----------
 ...t_property-3.c => acc_get_property-host.c} |  7 ++---
 ..._property-2.c => acc_get_property-nvptx.c} |  9 +++---
 3 files changed, 22 insertions(+), 22 deletions(-)
 rename libgomp/testsuite/libgomp.oacc-c-c++-common/{acc_get_property-3.c => acc_get_property-host.c} (63%)
 rename libgomp/testsuite/libgomp.oacc-c-c++-common/{acc_get_property-2.c => acc_get_property-nvptx.c} (86%)

diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
index 952bdbf6aea..76c29501839 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
@@ -8,9 +8,8 @@
 
 void expect_device_properties
 (acc_device_t dev_type, int dev_num,
- int expected_total_mem, int expected_free_mem,
- const char* expected_vendor, const char* expected_name,
- const char* expected_driver)
+ size_t expected_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver)
 {
   const char *vendor = acc_get_property_string (dev_num, dev_type,
 						acc_property_vendor);
@@ -21,22 +20,23 @@ void expect_device_properties
       abort ();
     }
 
-  int total_mem = acc_get_property (dev_num, dev_type,
-				    acc_property_memory);
-  if (total_mem != expected_total_mem)
+  size_t total_mem = acc_get_property (dev_num, dev_type,
+				       acc_property_memory);
+  if (total_mem != expected_memory)
     {
-      fprintf (stderr, "Expected acc_property_memory to equal %d, "
-	       "but was %d.\n", expected_total_mem, total_mem);
+      fprintf (stderr, "Expected acc_property_memory to equal %zd, "
+	       "but was %zd.\n", expected_memory, total_mem);
       abort ();
 
     }
 
-  int free_mem = acc_get_property (dev_num, dev_type,
+  size_t free_mem = acc_get_property (dev_num, dev_type,
 				   acc_property_free_memory);
-  if (free_mem != expected_free_mem)
+  if (free_mem > total_mem)
     {
-      fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
-	       "but was %d.\n", expected_free_mem, free_mem);
+      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
+	       ", but free memory was %zd and total memory was %zd.\n",
+	       free_mem, total_mem);
       abort ();
     }
 
@@ -59,11 +59,11 @@ void expect_device_properties
     }
 
   int unknown_property = 16058;
-  int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
+  size_t v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
   if (v != 0)
     {
       fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
-	       "but was %d.\n", v);
+	       "but was %zd.\n", v);
       abort ();
     }
 
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
similarity index 63%
rename from libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
rename to libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
index 92565000e49..f1cd7cfef39 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
@@ -8,12 +8,11 @@
 
 void expect_device_properties
 (acc_device_t dev_type, int dev_num,
- int expected_total_mem, int expected_free_mem,
- const char* expected_vendor, const char* expected_name,
- const char* expected_driver);
+ size_t expected_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver);
 
 int main()
 {
   printf ("Checking acc_device_host device properties\n");
-  expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0");
+  expect_device_properties (acc_device_host, 0, 0, "GNU", "GOMP", "1.0");
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
similarity index 86%
rename from libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
rename to libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
index 4dd13c401d3..0dcaea7c3e8 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
@@ -13,9 +13,8 @@
 
 void expect_device_properties
 (acc_device_t dev_type, int dev_num,
- int expected_total_mem, int expected_free_mem,
- const char* expected_vendor, const char* expected_name,
- const char* expected_driver);
+ size_t expected_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver);
 
 int main ()
 {
@@ -62,7 +61,9 @@ int main ()
       snprintf (driver, sizeof driver, "CUDA Driver %u.%u",
 		driver_version / 1000, driver_version % 1000 / 10);
 
+      /* Note that this check relies on the fact that the device numbering
+	 used by the nvptx plugin agrees with the CUDA device ordering. */
       expect_device_properties(acc_device_nvidia, dev_num,
-			       total_mem, free_mem, vendor, p.name, driver);
+			       total_mem, vendor, p.name, driver);
     }
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2020-01-20 14:20           ` Harwath, Frederik
@ 2020-01-23 15:08             ` Thomas Schwinge
  2020-01-24  9:36               ` Harwath, Frederik
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-23 15:08 UTC (permalink / raw)
  To: Frederik Harwath; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2640 bytes --]

Hi Frederik!

On 2020-01-20T15:01:01+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
> I have attached a patch containing the changes that you suggested.

> On 16.01.20 17:00, Thomas Schwinge wrote:
>> On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
> Ok to push the commit to master?

Thanks, OK.  Reviewed-by: Thomas Schwinge <thomas@codesourcery.com>


As a low-priority follow-up, please look into:

    source-gcc/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c: In function 'expect_device_properties':
    source-gcc/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c:74:24: warning: format '%d' expects argument of type 'int', but argument 3 has type 'const char *' [-Wformat=]
       74 |       fprintf (stderr, "Expected value of unknown string property to be NULL, "
          |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       75 |         "but was %d.\n", s);
          |                          ~
          |                          |
          |                          const char *
    source-gcc/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c:75:19: note: format string is defined here
       75 |         "but was %d.\n", s);
          |                  ~^
          |                   |
          |                   int
          |                  %s

..., and (random example):

>    int unknown_property = 16058;
> -  int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
> +  size_t v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
>    if (v != 0)
>      {
>        fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
> -	       "but was %d.\n", v);
> +	       "but was %zd.\n", v);
>        abort ();
>      }

..., shouldn't that be '%zu' given that 'size_t' is 'unsigned'?

    libgomp.oacc-c-c++-common/acc_get_property-aux.c:      fprintf (stderr, "Expected acc_property_memory to equal %zd, "
    libgomp.oacc-c-c++-common/acc_get_property-aux.c:            "but was %zd.\n", expected_memory, total_mem);
    libgomp.oacc-c-c++-common/acc_get_property-aux.c:            ", but free memory was %zd and total memory was %zd.\n",
    libgomp.oacc-c-c++-common/acc_get_property-aux.c:            "but was %zd.\n", v);
    libgomp.oacc-c-c++-common/acc_get_property.c:      printf ("    Total memory: %zd\n", v);
    libgomp.oacc-c-c++-common/acc_get_property.c:      printf ("    Free memory: %zd\n", v);


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2020-01-23 15:08             ` Thomas Schwinge
@ 2020-01-24  9:36               ` Harwath, Frederik
  0 siblings, 0 replies; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-24  9:36 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 2851 bytes --]

Hi Thomas,

On 23.01.20 15:32, Thomas Schwinge wrote:

> On 2020-01-20T15:01:01+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>> On 16.01.20 17:00, Thomas Schwinge wrote:
>>> On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>> Ok to push the commit to master?
> 
> Thanks, OK.  Reviewed-by: Thomas Schwinge <thomas@codesourcery.com>

Thank you. Committed as 4bd03ed69bd789278a0286017b692f49052ffe5c, including the changes to the size_t
formatting.

Best regards,
Frederik

> 
> 
> As a low-priority follow-up, please look into:
> 
>     source-gcc/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c: In function 'expect_device_properties':
>     source-gcc/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c:74:24: warning: format '%d' expects argument of type 'int', but argument 3 has type 'const char *' [-Wformat=]
>        74 |       fprintf (stderr, "Expected value of unknown string property to be NULL, "
>           |                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>        75 |         "but was %d.\n", s);
>           |                          ~
>           |                          |
>           |                          const char *
>     source-gcc/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c:75:19: note: format string is defined here
>        75 |         "but was %d.\n", s);
>           |                  ~^
>           |                   |
>           |                   int
>           |                  %s
> 
> ..., and (random example):
> 
>>    int unknown_property = 16058;
>> -  int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
>> +  size_t v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
>>    if (v != 0)
>>      {
>>        fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
>> -	       "but was %d.\n", v);
>> +	       "but was %zd.\n", v);
>>        abort ();
>>      }
> 
> ..., shouldn't that be '%zu' given that 'size_t' is 'unsigned'?
> 
>     libgomp.oacc-c-c++-common/acc_get_property-aux.c:      fprintf (stderr, "Expected acc_property_memory to equal %zd, "
>     libgomp.oacc-c-c++-common/acc_get_property-aux.c:            "but was %zd.\n", expected_memory, total_mem);
>     libgomp.oacc-c-c++-common/acc_get_property-aux.c:            ", but free memory was %zd and total memory was %zd.\n",
>     libgomp.oacc-c-c++-common/acc_get_property-aux.c:            "but was %zd.\n", v);
>     libgomp.oacc-c-c++-common/acc_get_property.c:      printf ("    Total memory: %zd\n", v);
>     libgomp.oacc-c-c++-common/acc_get_property.c:      printf ("    Free memory: %zd\n", v);
> 
> 
> Grüße
>  Thomas
> 


[-- Attachment #2: 0001-Fix-expectation-and-types-in-acc_get_property-tests.patch --]
[-- Type: text/x-patch, Size: 7803 bytes --]

From 4bd03ed69bd789278a0286017b692f49052ffe5c Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Mon, 20 Jan 2020 14:07:03 +0100
Subject: [PATCH 1/2] Fix expectation and types in acc_get_property tests

* Weaken expectation concerning acc_property_free_memory.
  Do not expect the value returned by CUDA since that value might have
  changed in the meantime.
* Use correct type for the results of calls to acc_get_property in tests.

libgomp/
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
	(expect_device_properties): Remove "expected_free_mem" argument,
	change "expected_total_mem" argument type to size_t;
	change types of acc_get_property results to size_t,
	adapt format strings.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property.c:
	Use %zu instead of %zd to print size_t values.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c: Adapt and
	rename to ...
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c: ... this.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c: Adapt and
	rename to ...
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c: ... this.

Reviewed-by: Thomas Schwinge  <thomas@codesourcery.com>
---
 .../acc_get_property-aux.c                    | 30 +++++++++----------
 ...t_property-3.c => acc_get_property-host.c} |  7 ++---
 ..._property-2.c => acc_get_property-nvptx.c} |  9 +++---
 .../acc_get_property.c                        |  4 +--
 4 files changed, 25 insertions(+), 25 deletions(-)
 rename libgomp/testsuite/libgomp.oacc-c-c++-common/{acc_get_property-3.c => acc_get_property-host.c} (63%)
 rename libgomp/testsuite/libgomp.oacc-c-c++-common/{acc_get_property-2.c => acc_get_property-nvptx.c} (86%)

diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
index 952bdbf6aea..6bb01250148 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
@@ -8,9 +8,8 @@
 
 void expect_device_properties
 (acc_device_t dev_type, int dev_num,
- int expected_total_mem, int expected_free_mem,
- const char* expected_vendor, const char* expected_name,
- const char* expected_driver)
+ size_t expected_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver)
 {
   const char *vendor = acc_get_property_string (dev_num, dev_type,
 						acc_property_vendor);
@@ -21,22 +20,23 @@ void expect_device_properties
       abort ();
     }
 
-  int total_mem = acc_get_property (dev_num, dev_type,
-				    acc_property_memory);
-  if (total_mem != expected_total_mem)
+  size_t total_mem = acc_get_property (dev_num, dev_type,
+				       acc_property_memory);
+  if (total_mem != expected_memory)
     {
-      fprintf (stderr, "Expected acc_property_memory to equal %d, "
-	       "but was %d.\n", expected_total_mem, total_mem);
+      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
+	       "but was %zu.\n", expected_memory, total_mem);
       abort ();
 
     }
 
-  int free_mem = acc_get_property (dev_num, dev_type,
+  size_t free_mem = acc_get_property (dev_num, dev_type,
 				   acc_property_free_memory);
-  if (free_mem != expected_free_mem)
+  if (free_mem > total_mem)
     {
-      fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
-	       "but was %d.\n", expected_free_mem, free_mem);
+      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
+	       ", but free memory was %zu and total memory was %zu.\n",
+	       free_mem, total_mem);
       abort ();
     }
 
@@ -59,11 +59,11 @@ void expect_device_properties
     }
 
   int unknown_property = 16058;
-  int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
+  size_t v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
   if (v != 0)
     {
       fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
-	       "but was %d.\n", v);
+	       "but was %zu.\n", v);
       abort ();
     }
 
@@ -72,7 +72,7 @@ void expect_device_properties
   if (s != NULL)
     {
       fprintf (stderr, "Expected value of unknown string property to be NULL, "
-	       "but was %d.\n", s);
+	       "but was %s.\n", s);
       abort ();
     }
 
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
similarity index 63%
rename from libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
rename to libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
index 92565000e49..f1cd7cfef39 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
@@ -8,12 +8,11 @@
 
 void expect_device_properties
 (acc_device_t dev_type, int dev_num,
- int expected_total_mem, int expected_free_mem,
- const char* expected_vendor, const char* expected_name,
- const char* expected_driver);
+ size_t expected_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver);
 
 int main()
 {
   printf ("Checking acc_device_host device properties\n");
-  expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0");
+  expect_device_properties (acc_device_host, 0, 0, "GNU", "GOMP", "1.0");
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
similarity index 86%
rename from libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
rename to libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
index 4dd13c401d3..0dcaea7c3e8 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
@@ -13,9 +13,8 @@
 
 void expect_device_properties
 (acc_device_t dev_type, int dev_num,
- int expected_total_mem, int expected_free_mem,
- const char* expected_vendor, const char* expected_name,
- const char* expected_driver);
+ size_t expected_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver);
 
 int main ()
 {
@@ -62,7 +61,9 @@ int main ()
       snprintf (driver, sizeof driver, "CUDA Driver %u.%u",
 		driver_version / 1000, driver_version % 1000 / 10);
 
+      /* Note that this check relies on the fact that the device numbering
+	 used by the nvptx plugin agrees with the CUDA device ordering. */
       expect_device_properties(acc_device_nvidia, dev_num,
-			       total_mem, free_mem, vendor, p.name, driver);
+			       total_mem, vendor, p.name, driver);
     }
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
index 289d1bab7f8..388c66c1319 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
@@ -35,10 +35,10 @@ print_device_properties(acc_device_t type)
 	}
 
       v = acc_get_property (i, type,  acc_property_memory);
-      printf ("    Total memory: %zd\n", v);
+      printf ("    Total memory: %zu\n", v);
 
       v = acc_get_property (i, type, acc_property_free_memory);
-      printf ("    Free memory: %zd\n", v);
+      printf ("    Free memory: %zu\n", v);
 
       s = acc_get_property_string (i, type, acc_property_name);
       printf ("    Name: %s\n", s);
-- 
2.17.1


[-- Attachment #3: 0002-Add-missing-ChangeLog-entry-for-my-last-commit.patch --]
[-- Type: text/x-patch, Size: 1452 bytes --]

From 9e424d974974c18b432c96f0df31b79a857819e6 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Fri, 24 Jan 2020 09:22:54 +0100
Subject: [PATCH 2/2] Add missing ChangeLog entry for my last commit

libgomp/ChangeLog: Add entry for commit 4bd03ed69bd.
---
 libgomp/ChangeLog | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index c0dde5cec3c..721627080cd 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,19 @@
+2020-01-24  Frederik Harwath  <frederik@codesourcery.com>
+
+	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
+	(expect_device_properties): Remove "expected_free_mem" argument,
+	change "expected_total_mem" argument type to size_t;
+	change types of acc_get_property results to size_t,
+	adapt format strings.
+	* testsuite/libgomp.oacc-c-c++-common/acc_get_property.c:
+	Use %zu instead of %zd to print size_t values.
+	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-2.c: Adapt and
+	rename to ...
+	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c: ... this.
+	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-3.c: Adapt and
+	rename to ...
+	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c: ... this.
+
 2020-01-23  Andrew Stubbs  <ams@codesourcery.com>
 
 	* plugin/plugin-gcn.c (parse_target_attributes): Use correct mask for
-- 
2.17.1


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Fortran 'acc_get_property' return type (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support)
  2019-12-20 17:11       ` Harwath, Frederik
  2019-12-21 23:01         ` Thomas Schwinge
  2020-01-16 16:03         ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge
@ 2020-01-27 14:57         ` Thomas Schwinge
  2020-01-28 15:31         ` [PATCH] Add OpenACC acc_get_property support for AMD GCN Harwath, Frederik
  3 siblings, 0 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-27 14:57 UTC (permalink / raw)
  To: Frederik Harwath, Tobias Burnus, fortran; +Cc: gcc-patches, Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 9260 bytes --]

Hi!

On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>> > --- a/libgomp/libgomp-plugin.h
>> > +++ b/libgomp/libgomp-plugin.h
>> > @@ -54,6 +54,13 @@ enum offload_target_type
>> >    OFFLOAD_TARGET_TYPE_GCN =3D 8
>> >  };
>> >=20=20
>> > +/* Container type for passing device properties.  */
>> > +union gomp_device_property_value
>> > +{
>> > +  void *ptr;
>> > +  uintmax_t val;
>> > +};
>>
>> Why wouldn't that be 'size_t', 'const char *', as the actual data types
>> used?  (Maybe I'm missing something.)
>
> I do not see a reason for this either. Changed.

For reference: C/C++ has 'size_t' ('acc_get_property'), or 'const char*'
('acc_get_property_string') return types.

>> > --- a/libgomp/openacc.f90
>> > +++ b/libgomp/openacc.f90
>> > @@ -28,7 +28,7 @@
>> >  !  <http://www.gnu.org/licenses/>.
>> >=20=20
>> >  module openacc_kinds
>> > -  use iso_fortran_env, only: int32
>> > +  use iso_fortran_env, only: int32, int64
>> >    implicit none
>> >=20=20
>> >    private :: int32
>> > @@ -47,6 +47,21 @@ module openacc_kinds
>> >    integer (acc_device_kind), parameter :: acc_device_not_host =3D 4
>> >    integer (acc_device_kind), parameter :: acc_device_nvidia =3D 5
>> >    integer (acc_device_kind), parameter :: acc_device_gcn =3D 8
>> > +  integer (acc_device_kind), parameter :: acc_device_current =3D -3
>> > +
>> > +  public :: acc_device_property
>> > +
>> > +  integer, parameter :: acc_device_property =3D int64
>>
>> Why 'int64'?  I changed this to 'int32', but please tell if there's a
>> reason for 'int64'.
>
> int32 is too narrow as - conforming to the OpenACC spec - acc_device_property
> is also used for the return type of acc_get_property (a bit strang, isn't it?).
> int64 also did not seem quite right. I have changed the type of acc_device_property
> to c_size_t to match the type that is used internally and as the return type of the
> corresponding C function.

I filed <https://github.com/OpenACC/openacc-spec/issues/260> "Fortran
'acc_get_property' return type":

| During review/implementation of `acc_get_property` in GCC, @frederik-h
| found that for Fortran `function acc_get_property`, the return type is
| specified as `integer(acc_device_property) :: acc_get_property`,
| whereas in C/C++, it is `size_t`.  For avoidance of doubt: it's correct
| to map the C/C++ `acc_device_property_t property` formal parameter to
| Fortran `integer(acc_device_property), value :: property`, but it's not
| clear why `integer(acc_device_property)` is also used as the function's
| return type -- the return type/values don't actually (conceptually)
| relate to the `integer(acc_device_property)` data type.
| 
| Should we use `c_size_t` for Fortran `acc_get_property` return type to
| explicitly match C/C++, or use plain `integer` (as used in all other
| interfaces taking `size_t` in C/C++ -- currently only as input formal
| parameters though)?


Grüße
 Thomas


> --- a/libgomp/libgomp.texi
> +++ b/libgomp/libgomp.texi

> +@node acc_get_property
> +@section @code{acc_get_property} -- Get device property.
> +@cindex acc_get_property
> +@cindex acc_get_property_string
> +@table @asis
> +@item @emph{Description}
> +These routines return the value of the specified @var{property} for the
> +device being queried according to @var{devicenum} and @var{devicetype}.
> +Integer-valued and string-valued properties are returned by
> +@code{acc_get_property} and @code{acc_get_property_string} respectively.
> +The Fortran @code{acc_get_property_string} subroutine returns the string
> +retrieved in its fourth argument while the remaining entry points are
> +functions, which pass the return value as their result.
> +
> +@item @emph{C/C++}:
> +@multitable @columnfractions .20 .80
> +@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
> +@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
> +@end multitable
> +
> +@item @emph{Fortran}:
> +@multitable @columnfractions .20 .80
> +@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
> +@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
> +@item                   @tab @code{integer devicenum}
> +@item                   @tab @code{integer(kind=acc_device_kind) devicetype}
> +@item                   @tab @code{integer(kind=acc_device_property) property}
> +@item                   @tab @code{integer(kind=acc_device_property) acc_get_property}
> +@item                   @tab @code{character(*) string}
> +@end multitable
> +
> +@item @emph{Reference}:
> +@uref{https://www.openacc.org, OpenACC specification v2.6}, section
> +3.2.6.
> +@end table


> --- a/libgomp/openacc.f90
> +++ b/libgomp/openacc.f90
> @@ -31,16 +31,18 @@
>  
>  module openacc_kinds
>    use iso_fortran_env, only: int32
> +  use iso_c_binding, only: c_size_t
>    implicit none
>  
>    public
> -  private :: int32
> +  private :: int32, c_size_t
>  

> @@ -89,6 +100,24 @@ module openacc_internal
>        integer (acc_device_kind) d
>      end function
>  
> +    function acc_get_property_h (n, d, p)
> +      import
> +      implicit none (type, external)
> +      integer (acc_device_property) :: acc_get_property_h
> +      integer, value :: n
> +      integer (acc_device_kind), value :: d
> +      integer (acc_device_property), value :: p
> +    end function
> +
> +    subroutine acc_get_property_string_h (n, d, p, s)
> +      import
> +      implicit none (type, external)
> +      integer, value :: n
> +      integer (acc_device_kind), value :: d
> +      integer (acc_device_property), value :: p
> +      character (*) :: s
> +    end subroutine
> +
>      function acc_async_test_h (a)
>        logical acc_async_test_h
>        integer a
> @@ -508,6 +537,26 @@ module openacc_internal
>        integer (c_int), value :: d
>      end function
>  
> +    function acc_get_property_l (n, d, p) &
> +        bind (C, name = "acc_get_property")
> +      use iso_c_binding, only: c_int, c_size_t
> +      implicit none (type, external)
> +      integer (c_size_t) :: acc_get_property_l
> +      integer (c_int), value :: n
> +      integer (c_int), value :: d
> +      integer (c_int), value :: p
> +    end function
> +
> +    function acc_get_property_string_l (n, d, p) &
> +        bind (C, name = "acc_get_property_string")
> +      use iso_c_binding, only: c_int, c_ptr
> +      implicit none (type, external)
> +      type (c_ptr) :: acc_get_property_string_l
> +      integer (c_int), value :: n
> +      integer (c_int), value :: d
> +      integer (c_int), value :: p
> +    end function

> @@ -758,6 +814,14 @@ module openacc
>      procedure :: acc_get_device_num_h
>    end interface
>  
> +  interface acc_get_property
> +    procedure :: acc_get_property_h
> +  end interface
> +
> +  interface acc_get_property_string
> +    procedure :: acc_get_property_string_h
> +  end interface
> +
>    interface acc_async_test
>      procedure :: acc_async_test_h
>    end interface
> @@ -976,6 +1040,63 @@ function acc_get_device_num_h (d)
>    acc_get_device_num_h = acc_get_device_num_l (d)
>  end function
>  
> +function acc_get_property_h (n, d, p)
> +  use iso_c_binding, only: c_int, c_size_t
> +  use openacc_internal, only: acc_get_property_l
> +  use openacc_kinds
> +  implicit none (type, external)
> +  integer (acc_device_property) :: acc_get_property_h
> +  integer, value :: n
> +  integer (acc_device_kind), value :: d
> +  integer (acc_device_property), value :: p
> +
> +  integer (c_int) :: pint
> +
> +  pint = int (p, c_int)
> +  acc_get_property_h = acc_get_property_l (n, d, pint)
> +end function
> +
> +subroutine acc_get_property_string_h (n, d, p, s)
> +  use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer, c_associated
> +  use openacc_internal, only: acc_get_property_string_l
> +  use openacc_kinds
> +  implicit none (type, external)
> +  integer, value :: n
> +  integer (acc_device_kind), value :: d
> +  integer (acc_device_property), value :: p
> +  character (*) :: s
> +
> +  integer (c_int) :: pint
> +  type (c_ptr) :: cptr
> +  integer :: clen
> +  character (kind=c_char, len=1), pointer, contiguous :: sptr (:)
> +  integer :: slen
> +  integer :: i
> +
> +  interface
> +     function strlen (s) bind (C, name = "strlen")
> +       use iso_c_binding, only: c_ptr, c_size_t
> +       type (c_ptr), intent(in), value :: s
> +       integer (c_size_t) :: strlen
> +     end function strlen
> +  end interface
> +
> +  pint = int (p, c_int)
> +  cptr = acc_get_property_string_l (n, d, pint)
> +  s = ""
> +  if (.not. c_associated (cptr)) then
> +     return
> +  end if
> +
> +  clen = int (strlen (cptr))
> +  call c_f_pointer (cptr, sptr, [clen])
> +
> +  slen = min (clen, len (s))
> +  do i = 1, slen
> +    s (i:i) = sptr (i)
> +  end do
> +end subroutine

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH] Add OpenACC acc_get_property support for AMD GCN
@ 2020-01-28 15:31         ` Harwath, Frederik
  2020-01-28 16:14           ` Andrew Stubbs
  0 siblings, 1 reply; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-28 15:31 UTC (permalink / raw)
  To: GCC Patches, Stubbs, Andrew, Thomas Schwinge; +Cc: Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 622 bytes --]

Hi,
this patch adds full support for the OpenACC 2.6 acc_get_property and
acc_get_property_string functions to the libgomp GCN plugin. This replaces
the existing stub in libgomp/plugin-gcn.c.

Andrew: The value returned for acc_property_memory ("size of device memory in bytes"
according to the spec) is the HSA_REGION_INFO_SIZE of the agent's data_region. This
has been adapted from a previous incomplete implementation that we had on the OG9 branch.
Does that sound reasonable?

I have tested the patch with amdgcn and nvptx offloading.

Ok to commit this to the main branch?


Best regards,
Frederik


[-- Attachment #2: 0001-Add-OpenACC-acc_get_property-support-for-AMD-GCN.patch --]
[-- Type: text/x-patch, Size: 14149 bytes --]

From 6f1855281c38993a088f9b4af020a786f8e05fe9 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Tue, 28 Jan 2020 08:01:00 +0100
Subject: [PATCH] Add OpenACC acc_get_property support for AMD GCN

Add full support for the OpenACC 2.6 acc_get_property and
acc_get_property_string functions to the libgomp GCN plugin.

libgomp/
	* plugin-gcn.c (struct agent_info): Add fields "name" and
	"vendor_name" ...
	(GOMP_OFFLOAD_init_device): ... and init from here.
	(struct hsa_context_info): Add field "driver_version_s" ...
	(init_hsa_contest): ... and init from here.
	(GOMP_OFFLOAD_openacc_get_property): Replace stub with a proper
	implementation.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property.c:
	Enable test execution for amdgcn and host offloading targets.
	* testsuite/libgomp.oacc-fortran/acc_get_property.f90: Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
	(expect_device_properties): Split function into ...
	(expect_device_string_properties): ... this new function ...
	(expect_device_memory): ... and this new function.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c:
	Add test.
---
 libgomp/plugin/plugin-gcn.c                   |  63 +++++++--
 .../acc_get_property-aux.c                    |  60 +++++---
 .../acc_get_property-gcn.c                    | 132 ++++++++++++++++++
 .../acc_get_property.c                        |   5 +-
 .../libgomp.oacc-fortran/acc_get_property.f90 |   2 -
 5 files changed, 224 insertions(+), 38 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c

diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 7854c142f05..0a09daaa0a4 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -425,7 +425,10 @@ struct agent_info
 
   /* The instruction set architecture of the device. */
   gcn_isa device_isa;
-
+  /* Name of the agent. */
+  char name[64];
+  /* Name of the vendor of the agent. */
+  char vendor_name[64];
   /* Command queues of the agent.  */
   hsa_queue_t *sync_queue;
   struct goacc_asyncqueue *async_queues, *omp_async_queue;
@@ -544,6 +547,8 @@ struct hsa_context_info
   int agent_count;
   /* Array of agent_info structures describing the individual HSA agents.  */
   struct agent_info *agents;
+  /* Driver version string. */
+  char driver_version_s[30];
 };
 
 /* Format of the on-device heap.
@@ -1513,6 +1518,15 @@ init_hsa_context (void)
 	GOMP_PLUGIN_error ("Failed to list all HSA runtime agents");
     }
 
+  uint16_t minor, major;
+  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MINOR, &minor);
+  if (status != HSA_STATUS_SUCCESS)
+    GOMP_PLUGIN_error ("Failed to obtain HSA runtime minor version");
+  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MAJOR, &major);
+  if (status != HSA_STATUS_SUCCESS)
+    GOMP_PLUGIN_error ("Failed to obtain HSA runtime major version");
+  sprintf (hsa_context.driver_version_s, "HSA Runtime %d.%d", major, minor);
+
   hsa_context.initialized = true;
   return true;
 }
@@ -3410,15 +3424,19 @@ GOMP_OFFLOAD_init_device (int n)
     return hsa_error ("Error requesting maximum queue size of the GCN agent",
 		      status);
 
-  char buf[64];
   status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_NAME,
-					  &buf);
+					  &agent->name);
   if (status != HSA_STATUS_SUCCESS)
     return hsa_error ("Error querying the name of the agent", status);
 
-  agent->device_isa = isa_code (buf);
+  agent->device_isa = isa_code (agent->name);
   if (agent->device_isa < 0)
-    return hsa_error ("Unknown GCN agent architecture.", HSA_STATUS_ERROR);
+    return hsa_error ("Unknown GCN agent architecture", HSA_STATUS_ERROR);
+
+  status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_VENDOR_NAME,
+					  &agent->vendor_name);
+  if (status != HSA_STATUS_SUCCESS)
+    return hsa_error ("Error querying the vendor name of the agent", status);
 
   status = hsa_fns.hsa_queue_create_fn (agent->id, queue_size,
 					HSA_QUEUE_TYPE_MULTI,
@@ -4115,12 +4133,37 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src,
 union goacc_property_value
 GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop)
 {
-  /* Stub. Check device and return default value for unsupported properties. */
-  /* TODO: Implement this function. */
-  get_agent_info (device);
+  struct agent_info *agent = get_agent_info (device);
+
+  union goacc_property_value propval = { .val = 0 };
+
+  switch (prop)
+    {
+    case GOACC_PROPERTY_FREE_MEMORY:
+      /* Not supported. */
+      break;
+    case GOACC_PROPERTY_MEMORY:
+      {
+	size_t size;
+	hsa_region_t region = agent->data_region;
+	hsa_status_t status =
+	  hsa_fns.hsa_region_get_info_fn (region, HSA_REGION_INFO_SIZE, &size);
+	if (status == HSA_STATUS_SUCCESS)
+	  propval.val = size;
+	break;
+      }
+    case GOACC_PROPERTY_NAME:
+      propval.ptr = agent->name;
+      break;
+    case GOACC_PROPERTY_VENDOR:
+      propval.ptr = agent->vendor_name;
+      break;
+    case GOACC_PROPERTY_DRIVER:
+      propval.ptr = hsa_context.driver_version_s;
+      break;
+    }
 
-  union goacc_property_value nullval = { .val = 0 };
-  return nullval;
+  return propval;
 }
 
 /* Set up plugin-specific thread-local-data (host-side).  */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
index 6bb01250148..6a4a499eb21 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
@@ -6,10 +6,11 @@
 #include <stdio.h>
 #include <string.h>
 
-void expect_device_properties
+
+void expect_device_string_properties
 (acc_device_t dev_type, int dev_num,
- size_t expected_memory, const char* expected_vendor,
- const char* expected_name, const char* expected_driver)
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver)
 {
   const char *vendor = acc_get_property_string (dev_num, dev_type,
 						acc_property_vendor);
@@ -20,26 +21,6 @@ void expect_device_properties
       abort ();
     }
 
-  size_t total_mem = acc_get_property (dev_num, dev_type,
-				       acc_property_memory);
-  if (total_mem != expected_memory)
-    {
-      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
-	       "but was %zu.\n", expected_memory, total_mem);
-      abort ();
-
-    }
-
-  size_t free_mem = acc_get_property (dev_num, dev_type,
-				   acc_property_free_memory);
-  if (free_mem > total_mem)
-    {
-      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
-	       ", but free memory was %zu and total memory was %zu.\n",
-	       free_mem, total_mem);
-      abort ();
-    }
-
   const char *name = acc_get_property_string (dev_num, dev_type,
 					      acc_property_name);
   if (strcmp (name, expected_name))
@@ -75,6 +56,39 @@ void expect_device_properties
 	       "but was %s.\n", s);
       abort ();
     }
+}
+
+void expect_device_memory
+(acc_device_t dev_type, int dev_num, size_t expected_total_memory)
+{
+
+  size_t total_mem = acc_get_property (dev_num, dev_type,
+				       acc_property_memory);
+
+  if (total_mem != expected_total_memory)
+    {
+      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
+	       "but was %zu.\n", expected_total_memory, total_mem);
+      abort ();
+    }
 
+  size_t free_mem = acc_get_property (dev_num, dev_type,
+				      acc_property_free_memory);
+  if (free_mem > total_mem)
+    {
+      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
+	       ", but free memory was %zu and total memory was %zu.\n",
+	       free_mem, total_mem);
+      abort ();
+    }
+}
 
+void expect_device_properties
+(acc_device_t dev_type, int dev_num,
+ size_t expected_total_memory, const char* expected_vendor,
+ const char* expected_name, const char* expected_driver)
+{
+  expect_device_string_properties (dev_type, dev_num, expected_vendor,
+				   expected_name, expected_driver);
+  expect_device_memory (dev_type, dev_num, expected_total_memory);
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
new file mode 100644
index 00000000000..305bb1af365
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
@@ -0,0 +1,132 @@
+/* Test the `acc_get_property' and `acc_get_property_string' library
+   functions on amdgcn devices by comparing property values with
+   those obtained through the HSA API. */
+/* { dg-additional-sources acc_get_property-aux.c } */
+/* { dg-additional-options "-ldl" } */
+/* { dg-do run { target openacc_amdgcn_accel_selected } } */
+
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openacc.h>
+
+#ifndef __cplusplus
+typedef int bool;
+#endif
+#include <hsa.h>
+
+
+void expect_device_string_properties
+(acc_device_t dev_type, int dev_num,
+ const char* expected_vendor, const char* expected_name,
+ const char* expected_driver);
+
+hsa_status_t (*hsa_agent_get_info_fn) (hsa_agent_t agent,
+				       hsa_agent_info_t attribute,
+				       void *value);
+hsa_status_t (*hsa_system_get_info_fn) (hsa_system_info_t attribute,
+					void *value);
+hsa_status_t (*hsa_iterate_agents_fn)
+(hsa_status_t (*callback)(hsa_agent_t agent, void *data), void *data);
+hsa_status_t (*hsa_init_fn) (void);
+
+char* support_cpu_devices;
+
+void test_setup ()
+{
+  char* env_runtime;
+  char* hsa_runtime_lib;
+  void *handle;
+
+#define DLSYM_FN(function)						\
+  function##_fn = (typeof(function##_fn))dlsym (handle, #function);	\
+  if (function##_fn == NULL)						\
+    {									\
+      fprintf (stderr, "Could not get symbol " #function ".\n");	\
+      abort (); 							\
+    }
+
+  env_runtime = getenv ("HSA_RUNTIME_LIB");
+  hsa_runtime_lib = env_runtime ? env_runtime : (char*)"libhsa-runtime64.so";
+
+  handle = dlopen (hsa_runtime_lib, RTLD_LAZY);
+  if (!handle)
+    {
+      fprintf (stderr, "Could not load %s.\n", hsa_runtime_lib);
+      abort ();
+    }
+
+  DLSYM_FN (hsa_agent_get_info)
+  DLSYM_FN (hsa_system_get_info)
+  DLSYM_FN (hsa_iterate_agents)
+  DLSYM_FN (hsa_init)
+
+  hsa_init_fn ();
+
+  support_cpu_devices = getenv ("GCN_SUPPORT_CPU_DEVICES");
+}
+
+static hsa_status_t check_agent_properties
+(hsa_agent_t agent, void *dev_num_arg)
+{
+
+  char name[64];
+  char vendor_name[64];
+  uint16_t minor;
+  uint16_t major;
+  char driver[30];
+
+  hsa_status_t status;
+  hsa_device_type_t device_type;
+  int* dev_num = (int*)dev_num_arg;
+
+#define AGENT_GET_INFO(info_type, val)				\
+  status = hsa_agent_get_info_fn (agent, info_type, &val);	\
+  if (status != HSA_STATUS_SUCCESS)				\
+    {								\
+      fprintf (stderr, "Failed to obtain " #info_type ".\n");	\
+      abort ();							\
+    }
+#define SYSTEM_GET_INFO(info_type, val)				\
+  status = hsa_system_get_info_fn (info_type, &val);		\
+  if (status != HSA_STATUS_SUCCESS)				\
+    {								\
+      fprintf (stderr, "Failed to obtain " #info_type ".\n");	\
+      abort ();							\
+    }
+
+  AGENT_GET_INFO (HSA_AGENT_INFO_DEVICE, device_type)
+
+    /* Skip unsupported device types.  Mimic the GCN plugin's behavior. */
+    if (!(device_type == HSA_DEVICE_TYPE_GPU
+	  || (support_cpu_devices && device_type == HSA_DEVICE_TYPE_CPU)))
+      return HSA_STATUS_SUCCESS;
+
+  AGENT_GET_INFO (HSA_AGENT_INFO_NAME, name)
+  AGENT_GET_INFO (HSA_AGENT_INFO_VENDOR_NAME, vendor_name)
+
+  SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MINOR, minor)
+  SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MAJOR, major)
+
+  sprintf (driver, "HSA Runtime %d.%d", major, minor);
+
+  expect_device_string_properties(acc_device_radeon, *dev_num,
+				  vendor_name, name, driver);
+
+  (*dev_num)++;
+
+  return status;
+}
+
+int main()
+{
+  int dev_num = 0;
+  test_setup ();
+
+  hsa_status_t status =
+    hsa_iterate_agents_fn (&check_agent_properties, &dev_num);
+
+  return status;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
index 388c66c1319..1984ad3a28d 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
@@ -3,8 +3,7 @@
    of all device types mentioned in the OpenACC standard.
 
    See also acc_get_property.f90. */
-/* { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } } */
-/* FIXME: This test does not work with the GCN implementation stub yet.  */
+/* { dg-do run } */
 
 #include <openacc.h>
 #include <stdlib.h>
@@ -20,7 +19,7 @@ print_device_properties(acc_device_t type)
   const char *s;
   size_t v;
 
-  int dev_count = acc_get_num_devices(type);
+  int dev_count = acc_get_num_devices (type);
 
   for (int i = 0; i < dev_count; ++i)
     {
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
index ce695475ae4..80ae292f41f 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
@@ -3,8 +3,6 @@
 ! of all device types mentioned in the OpenACC standard.
 !
 ! See also acc_get_property.c
-! { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } }
-! FIXME: This test does not work with the GCN implementation stub yet.
 
 program test
   use openacc
-- 
2.17.1



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-28 15:31         ` [PATCH] Add OpenACC acc_get_property support for AMD GCN Harwath, Frederik
@ 2020-01-28 16:14           ` Andrew Stubbs
  2020-01-29 10:10             ` Harwath, Frederik
  0 siblings, 1 reply; 38+ messages in thread
From: Andrew Stubbs @ 2020-01-28 16:14 UTC (permalink / raw)
  To: Harwath, Frederik, GCC Patches, Thomas Schwinge; +Cc: Jakub Jelinek

On 28/01/2020 14:55, Harwath, Frederik wrote:
> Hi,
> this patch adds full support for the OpenACC 2.6 acc_get_property and
> acc_get_property_string functions to the libgomp GCN plugin. This replaces
> the existing stub in libgomp/plugin-gcn.c.
> 
> Andrew: The value returned for acc_property_memory ("size of device memory in bytes"
> according to the spec) is the HSA_REGION_INFO_SIZE of the agent's data_region. This
> has been adapted from a previous incomplete implementation that we had on the OG9 branch.
> Does that sound reasonable?

I don't think we can do better than that.

> I have tested the patch with amdgcn and nvptx offloading.
> 
> Ok to commit this to the main branch?
> 
> 
> Best regards,
> Frederik
> 

> @@ -544,6 +547,8 @@ struct hsa_context_info
>    int agent_count;
>    /* Array of agent_info structures describing the individual HSA agents.  */
>    struct agent_info *agents;
> +  /* Driver version string. */
> +  char driver_version_s[30];
>  };
>  
>  /* Format of the on-device heap.
> @@ -1513,6 +1518,15 @@ init_hsa_context (void)
>  	GOMP_PLUGIN_error ("Failed to list all HSA runtime agents");
>      }
>  
> +  uint16_t minor, major;
> +  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MINOR, &minor);
> +  if (status != HSA_STATUS_SUCCESS)
> +    GOMP_PLUGIN_error ("Failed to obtain HSA runtime minor version");
> +  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MAJOR, &major);
> +  if (status != HSA_STATUS_SUCCESS)
> +    GOMP_PLUGIN_error ("Failed to obtain HSA runtime major version");
> +  sprintf (hsa_context.driver_version_s, "HSA Runtime %d.%d", major, minor);
> +
>    hsa_context.initialized = true;
>    return true;
>  }

If we're going to use a fixed-size buffer then we should use snprintf 
and emit GCN_WARNING if the return value is greater than 
"sizeof(driver_version_s)", even though that is unlikely. Do the same in 
the testcase, but use a bigger buffer so that truncation causes a 
mismatch and test failure.

> @@ -75,6 +56,39 @@ void expect_device_properties
>  	       "but was %s.\n", s);
>        abort ();
>      }
> +}
> +
> +void expect_device_memory
> +(acc_device_t dev_type, int dev_num, size_t expected_total_memory)
> +{
> +
> +

I realise that an existing function in this testcase uses this layout, 
but the code style does not normally have the parameter list on the next 
line, and certainly not in column 1.

> +
> +int main()
> +{

Space before ().

Thanks

Andrew

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-28 16:14           ` Andrew Stubbs
@ 2020-01-29 10:10             ` Harwath, Frederik
  2020-01-29 11:07               ` Andrew Stubbs
                                 ` (2 more replies)
  0 siblings, 3 replies; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-29 10:10 UTC (permalink / raw)
  To: Andrew Stubbs, GCC Patches, Thomas Schwinge; +Cc: Jakub Jelinek

[-- Attachment #1: Type: text/plain, Size: 811 bytes --]

Hi Andrew,

On 28.01.20 16:42, Andrew Stubbs wrote:
> On 28/01/2020 14:55, Harwath, Frederik wrote:
> 
> If we're going to use a fixed-size buffer then we should use snprintf and emit GCN_WARNING if the return value is greater than "sizeof(driver_version_s)", even though that is unlikely. Do the same in the testcase, but use a bigger buffer so that truncation causes a mismatch and test failure.

Ok.


> I realise that an existing function in this testcase uses this layout, but the code style does not normally have the parameter list on the next line, and certainly not in column 1.

Ok. I have also adjusted the formatting in the other acc_get_property tests to the code style. I have turned this into a separate trivial patch.

Ok to commit the revised patch?

Best regards,
Frederik


[-- Attachment #2: 0001-Add-OpenACC-acc_get_property-support-for-AMD-GCN.patch --]
[-- Type: text/x-patch, Size: 15061 bytes --]

From fb15cb9058feeda8891d6454d32f43fda885b789 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Wed, 29 Jan 2020 10:19:50 +0100
Subject: [PATCH 1/2] Add OpenACC acc_get_property support for AMD GCN

Add full support for the OpenACC 2.6 acc_get_property and
acc_get_property_string functions to the libgomp GCN plugin.

libgomp/
	* plugin-gcn.c (struct agent_info): Add fields "name" and
	"vendor_name" ...
	(GOMP_OFFLOAD_init_device): ... and init from here.
	(struct hsa_context_info): Add field "driver_version_s" ...
	(init_hsa_contest): ... and init from here.
	(GOMP_OFFLOAD_openacc_get_property): Replace stub with a proper
	implementation.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property.c:
	Enable test execution for amdgcn and host offloading targets.
	* testsuite/libgomp.oacc-fortran/acc_get_property.f90: Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
	(expect_device_properties): Split function into ...
	(expect_device_string_properties): ... this new function ...
	(expect_device_memory): ... and this new function.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c:
	Add test.
---
 libgomp/plugin/plugin-gcn.c                   |  71 ++++++++--
 .../acc_get_property-aux.c                    |  79 ++++++-----
 .../acc_get_property-gcn.c                    | 132 ++++++++++++++++++
 .../acc_get_property.c                        |   5 +-
 .../libgomp.oacc-fortran/acc_get_property.f90 |   2 -
 5 files changed, 242 insertions(+), 47 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c

diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 7854c142f05..45c625495b9 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -425,7 +425,10 @@ struct agent_info
 
   /* The instruction set architecture of the device. */
   gcn_isa device_isa;
-
+  /* Name of the agent. */
+  char name[64];
+  /* Name of the vendor of the agent. */
+  char vendor_name[64];
   /* Command queues of the agent.  */
   hsa_queue_t *sync_queue;
   struct goacc_asyncqueue *async_queues, *omp_async_queue;
@@ -544,6 +547,8 @@ struct hsa_context_info
   int agent_count;
   /* Array of agent_info structures describing the individual HSA agents.  */
   struct agent_info *agents;
+  /* Driver version string. */
+  char driver_version_s[30];
 };
 
 /* Format of the on-device heap.
@@ -1513,6 +1518,23 @@ init_hsa_context (void)
 	GOMP_PLUGIN_error ("Failed to list all HSA runtime agents");
     }
 
+  uint16_t minor, major;
+  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MINOR, &minor);
+  if (status != HSA_STATUS_SUCCESS)
+    GOMP_PLUGIN_error ("Failed to obtain HSA runtime minor version");
+  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MAJOR, &major);
+  if (status != HSA_STATUS_SUCCESS)
+    GOMP_PLUGIN_error ("Failed to obtain HSA runtime major version");
+
+  size_t len = sizeof hsa_context.driver_version_s;
+  int printed = snprintf (hsa_context.driver_version_s, len,
+			  "HSA Runtime %hu.%hu", (unsigned short int)major,
+			  (unsigned short int)minor);
+  if (printed >= len)
+    GCN_WARNING ("HSA runtime version string was truncated."
+		 "Version %hu.%hu is too long.", (unsigned short int)major,
+		 (unsigned short int)minor);
+
   hsa_context.initialized = true;
   return true;
 }
@@ -3410,15 +3432,19 @@ GOMP_OFFLOAD_init_device (int n)
     return hsa_error ("Error requesting maximum queue size of the GCN agent",
 		      status);
 
-  char buf[64];
   status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_NAME,
-					  &buf);
+					  &agent->name);
   if (status != HSA_STATUS_SUCCESS)
     return hsa_error ("Error querying the name of the agent", status);
 
-  agent->device_isa = isa_code (buf);
+  agent->device_isa = isa_code (agent->name);
   if (agent->device_isa < 0)
-    return hsa_error ("Unknown GCN agent architecture.", HSA_STATUS_ERROR);
+    return hsa_error ("Unknown GCN agent architecture", HSA_STATUS_ERROR);
+
+  status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_VENDOR_NAME,
+					  &agent->vendor_name);
+  if (status != HSA_STATUS_SUCCESS)
+    return hsa_error ("Error querying the vendor name of the agent", status);
 
   status = hsa_fns.hsa_queue_create_fn (agent->id, queue_size,
 					HSA_QUEUE_TYPE_MULTI,
@@ -4115,12 +4141,37 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src,
 union goacc_property_value
 GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop)
 {
-  /* Stub. Check device and return default value for unsupported properties. */
-  /* TODO: Implement this function. */
-  get_agent_info (device);
+  struct agent_info *agent = get_agent_info (device);
+
+  union goacc_property_value propval = { .val = 0 };
+
+  switch (prop)
+    {
+    case GOACC_PROPERTY_FREE_MEMORY:
+      /* Not supported. */
+      break;
+    case GOACC_PROPERTY_MEMORY:
+      {
+	size_t size;
+	hsa_region_t region = agent->data_region;
+	hsa_status_t status =
+	  hsa_fns.hsa_region_get_info_fn (region, HSA_REGION_INFO_SIZE, &size);
+	if (status == HSA_STATUS_SUCCESS)
+	  propval.val = size;
+	break;
+      }
+    case GOACC_PROPERTY_NAME:
+      propval.ptr = agent->name;
+      break;
+    case GOACC_PROPERTY_VENDOR:
+      propval.ptr = agent->vendor_name;
+      break;
+    case GOACC_PROPERTY_DRIVER:
+      propval.ptr = hsa_context.driver_version_s;
+      break;
+    }
 
-  union goacc_property_value nullval = { .val = 0 };
-  return nullval;
+  return propval;
 }
 
 /* Set up plugin-specific thread-local-data (host-side).  */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
index 6bb01250148..f43f75b364a 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
@@ -6,39 +6,20 @@
 #include <stdio.h>
 #include <string.h>
 
-void expect_device_properties
-(acc_device_t dev_type, int dev_num,
- size_t expected_memory, const char* expected_vendor,
- const char* expected_name, const char* expected_driver)
-{
-  const char *vendor = acc_get_property_string (dev_num, dev_type,
-						acc_property_vendor);
-  if (strcmp (vendor, expected_vendor))
-    {
-      fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
-	       "but was \"%s\".\n", expected_vendor, vendor);
-      abort ();
-    }
-
-  size_t total_mem = acc_get_property (dev_num, dev_type,
-				       acc_property_memory);
-  if (total_mem != expected_memory)
-    {
-      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
-	       "but was %zu.\n", expected_memory, total_mem);
-      abort ();
-
-    }
 
-  size_t free_mem = acc_get_property (dev_num, dev_type,
-				   acc_property_free_memory);
-  if (free_mem > total_mem)
-    {
-      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
-	       ", but free memory was %zu and total memory was %zu.\n",
-	       free_mem, total_mem);
-      abort ();
-    }
+void expect_device_string_properties (acc_device_t dev_type, int dev_num,
+				      const char* expected_vendor,
+				      const char* expected_name,
+				      const char* expected_driver)
+{
+const char *vendor = acc_get_property_string (dev_num, dev_type,
+					    acc_property_vendor);
+if (strcmp (vendor, expected_vendor))
+{
+    fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
+	    "but was \"%s\".\n", expected_vendor, vendor);
+    abort ();
+}
 
   const char *name = acc_get_property_string (dev_num, dev_type,
 					      acc_property_name);
@@ -75,6 +56,40 @@ void expect_device_properties
 	       "but was %s.\n", s);
       abort ();
     }
+}
+
+void expect_device_memory (acc_device_t dev_type, int dev_num,
+			   size_t expected_total_memory)
+{
+
+  size_t total_mem = acc_get_property (dev_num, dev_type,
+				       acc_property_memory);
+
+  if (total_mem != expected_total_memory)
+    {
+      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
+	       "but was %zu.\n", expected_total_memory, total_mem);
+      abort ();
+    }
 
+  size_t free_mem = acc_get_property (dev_num, dev_type,
+				      acc_property_free_memory);
+  if (free_mem > total_mem)
+    {
+      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
+	       ", but free memory was %zu and total memory was %zu.\n",
+	       free_mem, total_mem);
+      abort ();
+    }
+}
 
+void expect_device_properties (acc_device_t dev_type, int dev_num,
+			       size_t expected_total_memory,
+			       const char* expected_vendor,
+			       const char* expected_name,
+			       const char* expected_driver)
+{
+  expect_device_string_properties (dev_type, dev_num, expected_vendor,
+				   expected_name, expected_driver);
+  expect_device_memory (dev_type, dev_num, expected_total_memory);
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
new file mode 100644
index 00000000000..059b503bbf6
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
@@ -0,0 +1,132 @@
+/* Test the `acc_get_property' and `acc_get_property_string' library
+   functions on amdgcn devices by comparing property values with
+   those obtained through the HSA API. */
+/* { dg-additional-sources acc_get_property-aux.c } */
+/* { dg-additional-options "-ldl" } */
+/* { dg-do run { target openacc_amdgcn_accel_selected } } */
+
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openacc.h>
+
+#ifndef __cplusplus
+typedef int bool;
+#endif
+#include <hsa.h>
+
+
+void expect_device_string_properties (acc_device_t dev_type, int dev_num,
+				      const char* expected_vendor,
+				      const char* expected_name,
+				      const char* expected_driver);
+
+hsa_status_t (*hsa_agent_get_info_fn) (hsa_agent_t agent,
+				       hsa_agent_info_t attribute,
+				       void *value);
+hsa_status_t (*hsa_system_get_info_fn) (hsa_system_info_t attribute,
+					void *value);
+hsa_status_t (*hsa_iterate_agents_fn)
+(hsa_status_t (*callback)(hsa_agent_t agent, void *data), void *data);
+hsa_status_t (*hsa_init_fn) (void);
+
+char* support_cpu_devices;
+
+void test_setup ()
+{
+  char* env_runtime;
+  char* hsa_runtime_lib;
+  void *handle;
+
+#define DLSYM_FN(function)						\
+  function##_fn = (typeof(function##_fn))dlsym (handle, #function);	\
+  if (function##_fn == NULL)						\
+    {									\
+      fprintf (stderr, "Could not get symbol " #function ".\n");	\
+      abort (); 							\
+    }
+
+  env_runtime = getenv ("HSA_RUNTIME_LIB");
+  hsa_runtime_lib = env_runtime ? env_runtime : (char*)"libhsa-runtime64.so";
+
+  handle = dlopen (hsa_runtime_lib, RTLD_LAZY);
+  if (!handle)
+    {
+      fprintf (stderr, "Could not load %s.\n", hsa_runtime_lib);
+      abort ();
+    }
+
+  DLSYM_FN (hsa_agent_get_info)
+  DLSYM_FN (hsa_system_get_info)
+  DLSYM_FN (hsa_iterate_agents)
+  DLSYM_FN (hsa_init)
+
+  hsa_init_fn ();
+
+  support_cpu_devices = getenv ("GCN_SUPPORT_CPU_DEVICES");
+}
+
+static hsa_status_t check_agent_properties (hsa_agent_t agent, void *dev_num_arg)
+{
+
+  char name[64];
+  char vendor_name[64];
+  uint16_t minor;
+  uint16_t major;
+  char driver[60];
+
+  hsa_status_t status;
+  hsa_device_type_t device_type;
+  int* dev_num = (int*)dev_num_arg;
+
+#define AGENT_GET_INFO(info_type, val)				\
+  status = hsa_agent_get_info_fn (agent, info_type, &val);	\
+  if (status != HSA_STATUS_SUCCESS)				\
+    {								\
+      fprintf (stderr, "Failed to obtain " #info_type ".\n");	\
+      abort ();							\
+    }
+#define SYSTEM_GET_INFO(info_type, val)				\
+  status = hsa_system_get_info_fn (info_type, &val);		\
+  if (status != HSA_STATUS_SUCCESS)				\
+    {								\
+      fprintf (stderr, "Failed to obtain " #info_type ".\n");	\
+      abort ();							\
+    }
+
+  AGENT_GET_INFO (HSA_AGENT_INFO_DEVICE, device_type)
+
+    /* Skip unsupported device types.  Mimic the GCN plugin's behavior. */
+    if (!(device_type == HSA_DEVICE_TYPE_GPU
+	  || (support_cpu_devices && device_type == HSA_DEVICE_TYPE_CPU)))
+      return HSA_STATUS_SUCCESS;
+
+  AGENT_GET_INFO (HSA_AGENT_INFO_NAME, name)
+  AGENT_GET_INFO (HSA_AGENT_INFO_VENDOR_NAME, vendor_name)
+
+  SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MINOR, minor)
+  SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MAJOR, major)
+
+  snprintf (driver, sizeof driver, "HSA Runtime %hu.%hu",
+	    (unsigned short int)major, (unsigned short int)minor);
+
+  expect_device_string_properties(acc_device_radeon, *dev_num,
+				  vendor_name, name, driver);
+
+  (*dev_num)++;
+
+  return status;
+}
+
+int main ()
+{
+  int dev_num = 0;
+  test_setup ();
+
+  hsa_status_t status =
+    hsa_iterate_agents_fn (&check_agent_properties, &dev_num);
+
+  return status;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
index 388c66c1319..1984ad3a28d 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
@@ -3,8 +3,7 @@
    of all device types mentioned in the OpenACC standard.
 
    See also acc_get_property.f90. */
-/* { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } } */
-/* FIXME: This test does not work with the GCN implementation stub yet.  */
+/* { dg-do run } */
 
 #include <openacc.h>
 #include <stdlib.h>
@@ -20,7 +19,7 @@ print_device_properties(acc_device_t type)
   const char *s;
   size_t v;
 
-  int dev_count = acc_get_num_devices(type);
+  int dev_count = acc_get_num_devices (type);
 
   for (int i = 0; i < dev_count; ++i)
     {
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
index ce695475ae4..80ae292f41f 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
@@ -3,8 +3,6 @@
 ! of all device types mentioned in the OpenACC standard.
 !
 ! See also acc_get_property.c
-! { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } }
-! FIXME: This test does not work with the GCN implementation stub yet.
 
 program test
   use openacc
-- 
2.17.1


[-- Attachment #3: 0002-Adjust-formatting-of-acc_get_property-tests.patch --]
[-- Type: text/x-patch, Size: 5680 bytes --]

From fd9cdadbbada9ec7f0f108991937455952df7697 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <frederik@codesourcery.com>
Date: Wed, 29 Jan 2020 10:21:18 +0100
Subject: [PATCH 2/2] Adjust formatting of acc_get_property tests

libgomp/
 * testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c:
 Adjust to GNU coding style.
 * testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c: Likewise.
 * testsuite/libgomp.oacc-c-c++-common/acc_get_property.c: Likewise.
---
 .../acc_get_property-host.c                   | 11 +++++-----
 .../acc_get_property-nvptx.c                  | 21 ++++++++++---------
 .../acc_get_property.c                        | 20 +++++++++---------
 3 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
index f1cd7cfef39..bb80f3f52a3 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
@@ -6,12 +6,13 @@
 #include <openacc.h>
 #include <stdio.h>
 
-void expect_device_properties
-(acc_device_t dev_type, int dev_num,
- size_t expected_memory, const char* expected_vendor,
- const char* expected_name, const char* expected_driver);
+void expect_device_properties (acc_device_t dev_type, int dev_num,
+			       size_t expected_memory,
+			       const char* expected_vendor,
+			       const char* expected_name,
+			       const char* expected_driver);
 
-int main()
+int main ()
 {
   printf ("Checking acc_device_host device properties\n");
   expect_device_properties (acc_device_host, 0, 0, "GNU", "GOMP", "1.0");
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
index 0dcaea7c3e8..3e1b51036bc 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
@@ -11,10 +11,11 @@
 #include <string.h>
 #include <stdio.h>
 
-void expect_device_properties
-(acc_device_t dev_type, int dev_num,
- size_t expected_memory, const char* expected_vendor,
- const char* expected_name, const char* expected_driver);
+void expect_device_properties (acc_device_t dev_type, int dev_num,
+			       size_t expected_memory,
+			       const char* expected_vendor,
+			       const char* expected_name,
+			       const char* expected_driver);
 
 int main ()
 {
@@ -29,26 +30,26 @@ int main ()
 	  abort ();
 	}
 
-      printf("Checking device %d\n", dev_num);
+      printf ("Checking device %d\n", dev_num);
 
       const char *vendor = "Nvidia";
       size_t free_mem;
       size_t total_mem;
-      if (cudaMemGetInfo(&free_mem, &total_mem) != cudaSuccess)
+      if (cudaMemGetInfo (&free_mem, &total_mem) != cudaSuccess)
 	{
 	  fprintf (stderr, "cudaMemGetInfo failed.\n");
 	  abort ();
 	}
 
       struct cudaDeviceProp p;
-      if (cudaGetDeviceProperties(&p, dev_num) != cudaSuccess)
+      if (cudaGetDeviceProperties (&p, dev_num) != cudaSuccess)
 	{
 	  fprintf (stderr, "cudaGetDeviceProperties failed.\n");
 	  abort ();
 	}
 
       int driver_version;
-      if (cudaDriverGetVersion(&driver_version) != cudaSuccess)
+      if (cudaDriverGetVersion (&driver_version) != cudaSuccess)
 	{
 	  fprintf (stderr, "cudaDriverGetVersion failed.\n");
 	  abort ();
@@ -63,7 +64,7 @@ int main ()
 
       /* Note that this check relies on the fact that the device numbering
 	 used by the nvptx plugin agrees with the CUDA device ordering. */
-      expect_device_properties(acc_device_nvidia, dev_num,
-			       total_mem, vendor, p.name, driver);
+      expect_device_properties (acc_device_nvidia, dev_num,
+				total_mem, vendor, p.name, driver);
     }
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
index 1984ad3a28d..79b67084852 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
@@ -14,7 +14,7 @@
    and do basic device independent validation. */
 
 void
-print_device_properties(acc_device_t type)
+print_device_properties (acc_device_t type)
 {
   const char *s;
   size_t v;
@@ -23,7 +23,7 @@ print_device_properties(acc_device_t type)
 
   for (int i = 0; i < dev_count; ++i)
     {
-      printf("  Device %d:\n", i+1);
+      printf ("  Device %d:\n", i+1);
 
       s = acc_get_property_string (i, type, acc_property_vendor);
       printf ("    Vendor: %s\n", s);
@@ -59,17 +59,17 @@ print_device_properties(acc_device_t type)
 
 int main ()
 {
-  printf("acc_device_none:\n");
+  printf ("acc_device_none:\n");
   /* For completness; not expected to print anything since there
      should be no devices of this type. */
-  print_device_properties(acc_device_none);
+  print_device_properties (acc_device_none);
 
-  printf("acc_device_default:\n");
-  print_device_properties(acc_device_default);
+  printf ("acc_device_default:\n");
+  print_device_properties (acc_device_default);
 
-  printf("acc_device_host:\n");
-  print_device_properties(acc_device_host);
+  printf ("acc_device_host:\n");
+  print_device_properties (acc_device_host);
 
-  printf("acc_device_not_host:\n");
-  print_device_properties(acc_device_not_host);
+  printf ("acc_device_not_host:\n");
+  print_device_properties (acc_device_not_host);
 }
-- 
2.17.1


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-29 10:10             ` Harwath, Frederik
@ 2020-01-29 11:07               ` Andrew Stubbs
  2020-01-29 11:47                 ` Harwath, Frederik
  2020-01-29 17:58               ` Thomas Schwinge
  2020-01-30 16:28               ` Thomas Schwinge
  2 siblings, 1 reply; 38+ messages in thread
From: Andrew Stubbs @ 2020-01-29 11:07 UTC (permalink / raw)
  To: Harwath, Frederik, GCC Patches, Thomas Schwinge; +Cc: Jakub Jelinek

On 29/01/2020 09:52, Harwath, Frederik wrote:
> @@ -1513,6 +1518,23 @@ init_hsa_context (void)
>  	GOMP_PLUGIN_error ("Failed to list all HSA runtime agents");
>      }
>  
> +  uint16_t minor, major;
> +  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MINOR, &minor);
> +  if (status != HSA_STATUS_SUCCESS)
> +    GOMP_PLUGIN_error ("Failed to obtain HSA runtime minor version");
> +  status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MAJOR, &major);
> +  if (status != HSA_STATUS_SUCCESS)
> +    GOMP_PLUGIN_error ("Failed to obtain HSA runtime major version");
> +
> +  size_t len = sizeof hsa_context.driver_version_s;
> +  int printed = snprintf (hsa_context.driver_version_s, len,
> +			  "HSA Runtime %hu.%hu", (unsigned short int)major,
> +			  (unsigned short int)minor);
> +  if (printed >= len)
> +    GCN_WARNING ("HSA runtime version string was truncated."
> +		 "Version %hu.%hu is too long.", (unsigned short int)major,
> +		 (unsigned short int)minor);
> +
>    hsa_context.initialized = true;
>    return true;
>  }

Please wrap the long lines (I should have spotted this before, sorry).

The buffer checking is good, thank you.

> +void expect_device_string_properties (acc_device_t dev_type, int dev_num,
> +				      const char* expected_vendor,
> +				      const char* expected_name,
> +				      const char* expected_driver)
> +

GNU style would be ...

void
expect_device_string_properties (acc_device_t dev_type, int dev_num,
                                  const char* expected_vendor,
                                  const char* expected_name,
                                  const char* expected_driver)

That is, with the return type on the previous line, and the function 
name starting in the first column. The prototype should have the type on 
the same line, however. (I think the point is that you should be able to 
find a function definition with "grep '^name' *".)

Otherwise you have the parameter list correct now.

Patch 1 is OK with the formatting fixed.
Patch 2 is OK.

Thanks very much,

Andrew

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-29 11:07               ` Andrew Stubbs
@ 2020-01-29 11:47                 ` Harwath, Frederik
  0 siblings, 0 replies; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-29 11:47 UTC (permalink / raw)
  To: Andrew Stubbs, GCC Patches, Thomas Schwinge; +Cc: Jakub Jelinek

Hi Andrew,

On 29.01.20 11:38, Andrew Stubbs wrote:
> On 29/01/2020 09:52, Harwath, Frederik wrote:

> 
> Patch 1 is OK with the formatting fixed.
> Patch 2 is OK.
> 
> Thanks very much,
> 

Committed as 2e5ea57959183bd5bd0356739bb5167417401a31 and 87c3fcfa6bbb5c372d4e275276d21f601d0b62b0.

Thank you for the review,
Frederik

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-29 10:10             ` Harwath, Frederik
  2020-01-29 11:07               ` Andrew Stubbs
@ 2020-01-29 17:58               ` Thomas Schwinge
  2020-01-29 18:12                 ` Andrew Stubbs
  2020-01-30  8:04                 ` Harwath, Frederik
  2020-01-30 16:28               ` Thomas Schwinge
  2 siblings, 2 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-29 17:58 UTC (permalink / raw)
  To: Frederik Harwath; +Cc: Jakub Jelinek, Andrew Stubbs, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4435 bytes --]

Hi!

On 2020-01-29T10:52:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
> On 28.01.20 16:42, Andrew Stubbs wrote:
>> On 28/01/2020 14:55, Harwath, Frederik wrote:
>> 
>> If we're going to use a fixed-size buffer then we should use snprintf and emit GCN_WARNING if the return value is greater than "sizeof(driver_version_s)", even though that is unlikely. Do the same in the testcase, but use a bigger buffer so that truncation causes a mismatch and test failure.

> --- a/libgomp/plugin/plugin-gcn.c
> +++ b/libgomp/plugin/plugin-gcn.c
> @@ -425,7 +425,10 @@ struct agent_info
>  
>    /* The instruction set architecture of the device. */
>    gcn_isa device_isa;
> -
> +  /* Name of the agent. */
> +  char name[64];
> +  /* Name of the vendor of the agent. */
> +  char vendor_name[64];
>    /* Command queues of the agent.  */
>    hsa_queue_t *sync_queue;
>    struct goacc_asyncqueue *async_queues, *omp_async_queue;
> @@ -544,6 +547,8 @@ struct hsa_context_info
>    int agent_count;
>    /* Array of agent_info structures describing the individual HSA agents.  */
>    struct agent_info *agents;
> +  /* Driver version string. */
> +  char driver_version_s[30];
>  };

> @@ -1513,6 +1518,23 @@ init_hsa_context (void)

> +  size_t len = sizeof hsa_context.driver_version_s;
> +  int printed = snprintf (hsa_context.driver_version_s, len,
> +			  "HSA Runtime %hu.%hu", (unsigned short int)major,
> +			  (unsigned short int)minor);
> +  if (printed >= len)
> +    GCN_WARNING ("HSA runtime version string was truncated."
> +		 "Version %hu.%hu is too long.", (unsigned short int)major,
> +		 (unsigned short int)minor);

(Can it actually happen that 'snprintf' returns 'printed > len' --
meaning that it's written into random memory?  I thought 'snprintf' has a
hard stop at 'len'?  Or does this indicate the amount of memory it
would've written?  I should re-read the manpage at some point...)  ;-)

For 'printed = len' does or doesn't 'snprintf' store the terminating
'NUL' character, or do we manually have to set:

    hsa_context.driver_version_s[len - 1] = '\0';

... in that case?

> @@ -3410,15 +3432,19 @@ GOMP_OFFLOAD_init_device (int n)

> -  char buf[64];
>    status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_NAME,
> -					  &buf);
> +					  &agent->name);
>    if (status != HSA_STATUS_SUCCESS)
>      return hsa_error ("Error querying the name of the agent", status);

(That's of course pre-existing, but) this looks like a dangerous API,
given that 'hsa_agent_get_info_fn' doesn't know 'sizeof agent->name' (or
'sizeof buf' before)...

> +  status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_VENDOR_NAME,
> +					  &agent->vendor_name);
> +  if (status != HSA_STATUS_SUCCESS)
> +    return hsa_error ("Error querying the vendor name of the agent", status);

Similar here.


> --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
> @@ -3,8 +3,7 @@
>     of all device types mentioned in the OpenACC standard.
>  
>     See also acc_get_property.f90. */
> -/* { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } } */
> -/* FIXME: This test does not work with the GCN implementation stub yet.  */

(I had wondered why 'host' was disabled here; now I don't need to wonder
any longer.)  ;-)

> +/* { dg-do run } */

This one is not actually needed, is the default.  (But no reason to
remove it.)

> --- a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
> @@ -3,8 +3,6 @@
>  ! of all device types mentioned in the OpenACC standard.
>  !
>  ! See also acc_get_property.c
> -! { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } }
> -! FIXME: This test does not work with the GCN implementation stub yet.

..., but here, with 'dg-do run' removed, this is no longer doing "torture
testing" (cycle through optimization levels/flags).  (See the rationale
in 'libgomp/testsuite/libgomp.oacc-fortran/fortran.exp'.)

... but that should actually be OK given that we're really only testing
the 'acc_get_property'/'acc_get_property_string' API calls, no other
Fortran extravaganza.


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-29 17:58               ` Thomas Schwinge
@ 2020-01-29 18:12                 ` Andrew Stubbs
  2020-01-30  8:04                 ` Harwath, Frederik
  1 sibling, 0 replies; 38+ messages in thread
From: Andrew Stubbs @ 2020-01-29 18:12 UTC (permalink / raw)
  To: Thomas Schwinge, Frederik Harwath; +Cc: Jakub Jelinek, gcc-patches

On 29/01/2020 17:44, Thomas Schwinge wrote:
>> @@ -1513,6 +1518,23 @@ init_hsa_context (void)
> 
>> +  size_t len = sizeof hsa_context.driver_version_s;
>> +  int printed = snprintf (hsa_context.driver_version_s, len,
>> +			  "HSA Runtime %hu.%hu", (unsigned short int)major,
>> +			  (unsigned short int)minor);
>> +  if (printed >= len)
>> +    GCN_WARNING ("HSA runtime version string was truncated."
>> +		 "Version %hu.%hu is too long.", (unsigned short int)major,
>> +		 (unsigned short int)minor);
> 
> (Can it actually happen that 'snprintf' returns 'printed > len' --
> meaning that it's written into random memory?  I thought 'snprintf' has a
> hard stop at 'len'?  Or does this indicate the amount of memory it
> would've written?  I should re-read the manpage at some point...)  ;-)

snprintf returns the length it would have been, if not truncated.

> For 'printed = len' does or doesn't 'snprintf' store the terminating
> 'NUL' character, or do we manually have to set:
> 
>      hsa_context.driver_version_s[len - 1] = '\0';
> 
> ... in that case?

It does the right thing already, hence why printed == len is an 
overflow: the last character will be missing.

> 
>> @@ -3410,15 +3432,19 @@ GOMP_OFFLOAD_init_device (int n)
> 
>> -  char buf[64];
>>     status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_NAME,
>> -					  &buf);
>> +					  &agent->name);
>>     if (status != HSA_STATUS_SUCCESS)
>>       return hsa_error ("Error querying the name of the agent", status);
> 
> (That's of course pre-existing, but) this looks like a dangerous API,
> given that 'hsa_agent_get_info_fn' doesn't know 'sizeof agent->name' (or
> 'sizeof buf' before)...

Those ones are written into the HSA documentation. They are fixed-sized 
fields, so there must be 64 bytes regardless of the actual name of the 
agent.

>> +  status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_VENDOR_NAME,
>> +					  &agent->vendor_name);
>> +  if (status != HSA_STATUS_SUCCESS)
>> +    return hsa_error ("Error querying the vendor name of the agent", status);
> 
> Similar here.

Same reason.

>> --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
>> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
>> @@ -3,8 +3,7 @@
>>      of all device types mentioned in the OpenACC standard.
>>   
>>      See also acc_get_property.f90. */
>> -/* { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } } */
>> -/* FIXME: This test does not work with the GCN implementation stub yet.  */
> 
> (I had wondered why 'host' was disabled here; now I don't need to wonder
> any longer.)  ;-)
> 
>> +/* { dg-do run } */
> 
> This one is not actually needed, is the default.  (But no reason to
> remove it.)
> 
>> --- a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
>> +++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
>> @@ -3,8 +3,6 @@
>>   ! of all device types mentioned in the OpenACC standard.
>>   !
>>   ! See also acc_get_property.c
>> -! { dg-do run { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } }
>> -! FIXME: This test does not work with the GCN implementation stub yet.
> 
> ..., but here, with 'dg-do run' removed, this is no longer doing "torture
> testing" (cycle through optimization levels/flags).  (See the rationale
> in 'libgomp/testsuite/libgomp.oacc-fortran/fortran.exp'.)
> 
> ... but that should actually be OK given that we're really only testing
> the 'acc_get_property'/'acc_get_property_string' API calls, no other
> Fortran extravaganza.

Thanks for the additional review, Thomas.

Andrew

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-29 17:58               ` Thomas Schwinge
  2020-01-29 18:12                 ` Andrew Stubbs
@ 2020-01-30  8:04                 ` Harwath, Frederik
  1 sibling, 0 replies; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-30  8:04 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Jakub Jelinek, Andrew Stubbs, gcc-patches

Hi Thomas,

On 29.01.20 18:44, Thomas Schwinge wrote:

>> +  size_t len = sizeof hsa_context.driver_version_s;
>> +  int printed = snprintf (hsa_context.driver_version_s, len,
>> +			  "HSA Runtime %hu.%hu", (unsigned short int)major,
>> +			  (unsigned short int)minor);
>> +  if (printed >= len)
>> +    GCN_WARNING ("HSA runtime version string was truncated."
>> +		 "Version %hu.%hu is too long.", (unsigned short int)major,
>> +		 (unsigned short int)minor);
> 
> (Can it actually happen that 'snprintf' returns 'printed > len' --
> meaning that it's written into random memory?  I thought 'snprintf' has a
> hard stop at 'len'?  Or does this indicate the amount of memory it
> would've written?  I should re-read the manpage at some point...)  ;-)
> 

Yes, "printed > len" can happen. Seems that I have chosen a bad variable name.
"actual_len" (of the formatted string that should have been written -
excluding the terminating '\0') would have been more appropriate.


> For 'printed = len' does or doesn't 'snprintf' store the terminating
> 'NUL' character, or do we manually have to set:
> 
>     hsa_context.driver_version_s[len - 1] = '\0';
> 
> ... in that case?

No, in this case, the printed string is missing the last character, but the
terminating '\0' has been written. Consider:

#include <stdio.h>

int main () {
char s[] = "foo";
char buf[3];

// buf is too short to hold terminating '\0'
int actual_len = snprintf (buf, 3, "%s", s);
printf ("buf: %s\n", buf);
printf ("actual_len: %d\n", actual_len);
}

Output:


buf: fo
actual_len: 3

> 
>> @@ -3410,15 +3432,19 @@ GOMP_OFFLOAD_init_device (int n)
> 
>> -  char buf[64];
>>    status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_NAME,
>> -					  &buf);
>> +					  &agent->name);
>>    if (status != HSA_STATUS_SUCCESS)
>>      return hsa_error ("Error querying the name of the agent", status);
> 
> (That's of course pre-existing, but) this looks like a dangerous API,
> given that 'hsa_agent_get_info_fn' doesn't know 'sizeof agent->name' (or
> 'sizeof buf' before)...

The API documentation
(cf. https://rocm-documentation.readthedocs.io/en/latest/ROCm_API_References/ROCr-API.html)
states that "the type of this attribute is a NUL-terminated char[64]".
But, right, should this ever change, we might not notice it.

Best regards,
Frederik


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Make OpenACC 'acc_get_property' with 'acc_device_current' work (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support)
  2020-01-10 23:44           ` Thomas Schwinge
@ 2020-01-30 16:14             ` Thomas Schwinge
  2020-02-03 12:16               ` Harwath, Frederik
  2020-02-03 14:41               ` Make OpenACC 'acc_get_property' with 'acc_device_current' work Tobias Burnus
  0 siblings, 2 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-30 16:14 UTC (permalink / raw)
  To: Frederik Harwath, gcc-patches, Tobias Burnus; +Cc: Jakub Jelinek, fortran


[-- Attachment #1.1: Type: text/plain, Size: 2105 bytes --]

Hi!

On 2020-01-10T23:52:11+0100, I wrote:
> On 2019-12-21T23:02:38+0100, I wrote:
>> On 2019-12-20T17:46:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>>>> > --- a/include/gomp-constants.h
>>>> > +++ b/include/gomp-constants.h
>
>>>> > +#define GOMP_DEVICE_CURRENT		-3
>
>>>> Should this actually get value '-1' instead of '-3'?  Or, is the OpenACC
>>>> 'acc_device_t' code already paying special attention to negative values
>>>> '-1', '-2'?  (I don't think so.)
>
>>>> | Also, 'acc_device_current' is a libgomp-internal thing (doesn't interface
>>>> | with the compiler proper), so strictly speaking 'GOMP_DEVICE_CURRENT'
>>>> | isn't needed in 'include/gomp-constants.h'.  But probably still a good
>>>> | idea to list it there, in this canonical place, to keep the several lists
>>>> | of device types coherent.
>
>>>> I still wonder about that...  ;-)
>
>> I still think that 'GOMP_DEVICE_CURENT' should get value '-1' (and
>> probably be rename 'GOACC_DEVICE_CURRENT' to make more obvious that it's
>> not related to the 'GOMP_DEVICE_*' ones), but we shall have a look at
>> that later (before GCC 10 release); that's libgomp/OpenACC-internal,
>> doesn't affect anything else.
>
> That's still pending.  Recently,
> <https://github.com/OpenACC/openacc-spec/issues/256> "Missing definition
> for acc_device_current" got filed; let's (also/first) watch/wait what
> comes out of that.

(That's still pending, but) notwithstanding the specific value we'll use
eventually, the 'acc_device_current' interface should work already now.

..., but I noticed that we don't have any test cases for that (so by that
definition, it must be broken).  The curious guy that I am sometimes ;-)
I gave that a try, and... "of course"... it doesn't work.  Please review
the attached (Tobias the Fortran test cases, please), and test with AMD
GCN offloading.  If approving this patch, please respond with
"Reviewed-by: NAME <EMAIL>" so that your effort will be recorded in the
commit log, see <https://gcc.gnu.org/wiki/Reviewed-by>.


Grüße
 Thomas



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0001-Make-OpenACC-acc_get_property-with-acc_device.master.patch --]
[-- Type: text/x-diff, Size: 23422 bytes --]

From 5ce3725cf160f086e99c01e73c26a0bf5654f5b6 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 29 Jan 2020 22:11:15 +0100
Subject: [PATCH] Make OpenACC 'acc_get_property' with 'acc_device_current'
 work

	libgomp/
	* oacc-init.c (acc_get_property, acc_get_property_string): Allow
	'acc_device_current'.
	* openacc.f90 (module openacc): Export 'acc_device_current'.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
	(expect_device_memory): Rename to...
	(expect_device_memory_properties): ... this.  Make 'static'.
	(expect_device_string_properties): Rename to...
	(expect_device_non_memory_properties): ... this.  Adjust all
	users.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.h: New
	file.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c: Use it.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c:
	Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c:
	Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c:
	Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c: Add
	some more testing.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c:
	Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c:
	Likewise.
	* testsuite/libgomp.oacc-c-c++-common/acc_get_property.c:
	Likewise.
	* testsuite/libgomp.oacc-fortran/acc_get_property.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/acc_get_property-aux.f90: New
	file.
	* testsuite/libgomp.oacc-fortran/acc_get_property-host.F90: New
	file.
---
 libgomp/oacc-init.c                           |   8 +-
 libgomp/openacc.f90                           |   1 +
 .../acc_get_property-aux.c                    |  76 ++++++-------
 .../acc_get_property-aux.h                    |  14 +++
 .../acc_get_property-gcn.c                    |  26 +++--
 .../acc_get_property-host.c                   |  26 +++--
 .../acc_get_property-nvptx.c                  |  27 +++--
 .../acc_get_property.c                        |  16 ++-
 .../acc_get_property-aux.f90                  | 102 ++++++++++++++++++
 .../acc_get_property-host.F90                 |  31 ++++++
 .../libgomp.oacc-fortran/acc_get_property.f90 |  15 ++-
 11 files changed, 274 insertions(+), 68 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.h
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-aux.f90
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-host.F90

diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
index ef12b4c16d01..c28c0f689ba2 100644
--- a/libgomp/oacc-init.c
+++ b/libgomp/oacc-init.c
@@ -796,7 +796,9 @@ get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
 size_t
 acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
 {
-  if (!known_device_type_p (d))
+  if (d == acc_device_current)
+    ; /* Allowed only for 'acc_get_property', 'acc_get_property_string'.  */
+  else if (!known_device_type_p (d))
     unknown_device_type_error(d);
 
   if (prop & GOACC_PROPERTY_STRING_MASK)
@@ -810,7 +812,9 @@ ialias (acc_get_property)
 const char *
 acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
 {
-  if (!known_device_type_p (d))
+  if (d == acc_device_current)
+    ; /* Allowed only for 'acc_get_property', 'acc_get_property_string'.  */
+  else if (!known_device_type_p (d))
     unknown_device_type_error(d);
 
   if (prop & GOACC_PROPERTY_STRING_MASK)
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index e2639bf622ed..5112a4ee951a 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -766,6 +766,7 @@ module openacc
 
   ! From openacc_kinds
   public :: acc_device_kind
+  public :: acc_device_current
   public :: acc_device_none, acc_device_default, acc_device_host
   public :: acc_device_not_host, acc_device_nvidia, acc_device_radeon
 
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
index 47285fc7e63b..189fe1e26957 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
@@ -1,17 +1,44 @@
 /* Auxiliary functions for acc_get_property tests */
 /* { dg-do compile  { target skip-all-targets } } */
+/* See also '../libgomp.oacc-fortran/acc_get_property-aux.f90'.  */
 
 #include <openacc.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
+#include "acc_get_property-aux.h"
+
+
+static void
+expect_device_memory_properties (acc_device_t dev_type, int dev_num,
+				 size_t expected_total_memory)
+{
+  size_t total_mem = acc_get_property (dev_num, dev_type,
+				       acc_property_memory);
+  if (total_mem != expected_total_memory)
+    {
+      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
+	       "but was %zu.\n", expected_total_memory, total_mem);
+      abort ();
+    }
+
+  size_t free_mem = acc_get_property (dev_num, dev_type,
+				      acc_property_free_memory);
+  if (free_mem > total_mem)
+    {
+      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
+	       ", but free memory was %zu and total memory was %zu.\n",
+	       free_mem, total_mem);
+      abort ();
+    }
+}
 
 void
-expect_device_string_properties (acc_device_t dev_type, int dev_num,
-				 const char* expected_vendor,
-				 const char* expected_name,
-				 const char* expected_driver)
+expect_device_non_memory_properties (acc_device_t dev_type, int dev_num,
+				     const char* expected_vendor,
+				     const char* expected_name,
+				     const char* expected_driver)
 {
   const char *vendor = acc_get_property_string (dev_num, dev_type,
 						acc_property_vendor);
@@ -40,8 +67,8 @@ expect_device_string_properties (acc_device_t dev_type, int dev_num,
       abort ();
     }
 
-  int unknown_property = 16058;
-  size_t v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
+  size_t v = acc_get_property (dev_num, dev_type,
+			       /* unknown */ (acc_device_property_t) 16058);
   if (v != 0)
     {
       fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
@@ -49,8 +76,8 @@ expect_device_string_properties (acc_device_t dev_type, int dev_num,
       abort ();
     }
 
-  int unknown_property2 = -16058;
-  const char *s = acc_get_property_string (dev_num, dev_type, (acc_device_property_t)unknown_property2);
+  const char *s = acc_get_property_string (dev_num, dev_type,
+					   /* unknown */ (acc_device_property_t) -16058);
   if (s != NULL)
     {
       fprintf (stderr, "Expected value of unknown string property to be NULL, "
@@ -59,32 +86,6 @@ expect_device_string_properties (acc_device_t dev_type, int dev_num,
     }
 }
 
-void
-expect_device_memory (acc_device_t dev_type, int dev_num,
-		      size_t expected_total_memory)
-{
-
-  size_t total_mem = acc_get_property (dev_num, dev_type,
-				       acc_property_memory);
-
-  if (total_mem != expected_total_memory)
-    {
-      fprintf (stderr, "Expected acc_property_memory to equal %zu, "
-	       "but was %zu.\n", expected_total_memory, total_mem);
-      abort ();
-    }
-
-  size_t free_mem = acc_get_property (dev_num, dev_type,
-				      acc_property_free_memory);
-  if (free_mem > total_mem)
-    {
-      fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory"
-	       ", but free memory was %zu and total memory was %zu.\n",
-	       free_mem, total_mem);
-      abort ();
-    }
-}
-
 void
 expect_device_properties (acc_device_t dev_type, int dev_num,
 			  size_t expected_total_memory,
@@ -92,7 +93,8 @@ expect_device_properties (acc_device_t dev_type, int dev_num,
 			  const char* expected_name,
 			  const char* expected_driver)
 {
-  expect_device_string_properties (dev_type, dev_num, expected_vendor,
-				   expected_name, expected_driver);
-  expect_device_memory (dev_type, dev_num, expected_total_memory);
+  expect_device_memory_properties (dev_type, dev_num,
+				    expected_total_memory);
+  expect_device_non_memory_properties (dev_type, dev_num,
+				       expected_vendor, expected_name, expected_driver);
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.h b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.h
new file mode 100644
index 000000000000..b3cfa47ce2eb
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.h
@@ -0,0 +1,14 @@
+/* Auxiliary functions for acc_get_property tests */
+
+#include <openacc.h>
+#include <stddef.h>
+
+void expect_device_non_memory_properties (acc_device_t dev_type, int dev_num,
+					  const char* expected_vendor,
+					  const char* expected_name,
+					  const char* expected_driver);
+void expect_device_properties (acc_device_t dev_type, int dev_num,
+			       size_t expected_total_memory,
+			       const char* expected_vendor,
+			       const char* expected_name,
+			       const char* expected_driver);
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
index ce59264a60dc..a09d64749f1b 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
@@ -17,11 +17,8 @@ typedef int bool;
 #endif
 #include <hsa.h>
 
+#include "acc_get_property-aux.h"
 
-void expect_device_string_properties (acc_device_t dev_type, int dev_num,
-				      const char* expected_vendor,
-				      const char* expected_name,
-				      const char* expected_driver);
 
 hsa_status_t (*hsa_agent_get_info_fn) (hsa_agent_t agent,
 				       hsa_agent_info_t attribute,
@@ -114,8 +111,25 @@ check_agent_properties (hsa_agent_t agent, void *dev_num_arg)
   snprintf (driver, sizeof driver, "HSA Runtime %hu.%hu",
 	    (unsigned short int)major, (unsigned short int)minor);
 
-  expect_device_string_properties(acc_device_radeon, *dev_num,
-				  vendor_name, name, driver);
+  expect_device_non_memory_properties (acc_device_default, *dev_num,
+				       vendor_name, name, driver);
+
+  /* Per 'acc_device_t' ordering, the following 'acc_device_not_host' resolves
+     to...  */
+  if (acc_get_num_devices (acc_device_nvidia) > 0)
+    /* ... 'acc_device_nvidia'.  */
+    ;
+  else
+    /* ... 'acc_device_radeon'.  */
+    expect_device_non_memory_properties (acc_device_not_host, *dev_num,
+					 vendor_name, name, driver);
+
+  expect_device_non_memory_properties (acc_device_radeon, *dev_num,
+				       vendor_name, name, driver);
+
+  acc_set_device_num (*dev_num, acc_device_default);
+  expect_device_non_memory_properties (acc_device_current, /* "'devicenum' is ignored" */ 135,
+				       vendor_name, name, driver);
 
   (*dev_num)++;
 
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
index 4ed0dfa8886f..c5c006ff3e5a 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-host.c
@@ -1,20 +1,30 @@
-/* Test the `acc_get_property' and '`acc_get_property_string' library
+/* Test the `acc_get_property' and `acc_get_property_string' library
    functions for the host device. */
 /* { dg-additional-sources acc_get_property-aux.c } */
-/* { dg-do run } */
+/* See also '../libgomp.oacc-fortran/acc_get_property-host.F90'.  */
 
 #include <openacc.h>
 #include <stdio.h>
 
-void expect_device_properties (acc_device_t dev_type, int dev_num,
-			       size_t expected_memory,
-			       const char* expected_vendor,
-			       const char* expected_name,
-			       const char* expected_driver);
+#include "acc_get_property-aux.h"
+
 
 int
 main ()
 {
+#if ACC_DEVICE_TYPE_host
+  printf ("Checking acc_device_default device properties\n");
+  expect_device_properties (acc_device_default, 0,
+			    0, "GNU", "GOMP", "1.0");
+#endif
+
   printf ("Checking acc_device_host device properties\n");
-  expect_device_properties (acc_device_host, 0, 0, "GNU", "GOMP", "1.0");
+  expect_device_properties (acc_device_host, 0,
+			    0, "GNU", "GOMP", "1.0");
+
+#if ACC_DEVICE_TYPE_host
+  printf ("Checking acc_device_current device properties\n");
+  expect_device_properties (acc_device_current, /* "'devicenum' is ignored" */ 135,
+			    0, "GNU", "GOMP", "1.0");
+#endif
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
index 6334cfdd2f73..109655a1b7d8 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-nvptx.c
@@ -1,4 +1,4 @@
-/* Test the `acc_get_property' and '`acc_get_property_string' library
+/* Test the `acc_get_property' and `acc_get_property_string' library
    functions on Nvidia devices by comparing property values with
    those obtained through the CUDA API. */
 /* { dg-additional-sources acc_get_property-aux.c } */
@@ -11,11 +11,8 @@
 #include <string.h>
 #include <stdio.h>
 
-void expect_device_properties (acc_device_t dev_type, int dev_num,
-			       size_t expected_memory,
-			       const char* expected_vendor,
-			       const char* expected_name,
-			       const char* expected_driver);
+#include "acc_get_property-aux.h"
+
 
 int
 main ()
@@ -63,9 +60,23 @@ main ()
       snprintf (driver, sizeof driver, "CUDA Driver %u.%u",
 		driver_version / 1000, driver_version % 1000 / 10);
 
-      /* Note that this check relies on the fact that the device numbering
-	 used by the nvptx plugin agrees with the CUDA device ordering. */
+      /* Note that 'dev_num' usage in the following relies on the fact that the
+	 device numbering used by the libgomp nvptx plugin agrees with the CUDA
+	 device ordering. */
+
+      expect_device_properties (acc_device_default, dev_num,
+				total_mem, vendor, p.name, driver);
+
+      /* Per 'acc_device_t' ordering, the following 'acc_device_not_host'
+	 resolves to 'acc_device_nvidia'.  */
+      expect_device_properties (acc_device_not_host, dev_num,
+				total_mem, vendor, p.name, driver);
+
       expect_device_properties (acc_device_nvidia, dev_num,
 				total_mem, vendor, p.name, driver);
+
+      acc_set_device_num (dev_num, acc_device_default);
+      expect_device_properties (acc_device_current, /* "'devicenum' is ignored" */ 135,
+				total_mem, vendor, p.name, driver);
     }
 }
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
index 3460035f0035..459044d35e53 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c
@@ -1,9 +1,8 @@
-/* Test the `acc_get_property' and '`acc_get_property_string' library
+/* Test the `acc_get_property' and `acc_get_property_string' library
    functions by printing the results of those functions for all devices
    of all device types mentioned in the OpenACC standard.
 
-   See also acc_get_property.f90. */
-/* { dg-do run } */
+   See also '../libgomp.oacc-fortran/acc_get_property.f90'.  */
 
 #include <openacc.h>
 #include <stdlib.h>
@@ -19,7 +18,13 @@ print_device_properties (acc_device_t type)
   const char *s;
   size_t v;
 
-  int dev_count = acc_get_num_devices (type);
+  int dev_count;
+  if (type != acc_device_current)
+    dev_count = acc_get_num_devices (type);
+  else
+    /* "'devicenum' is ignored and the value of the property for the current
+       device is returned".  We'd like that printed ten times, please.  */
+    dev_count = 10;
 
   for (int i = 0; i < dev_count; ++i)
     {
@@ -73,4 +78,7 @@ main ()
 
   printf ("acc_device_not_host:\n");
   print_device_properties (acc_device_not_host);
+
+  printf ("acc_device_current:\n");
+  print_device_properties (acc_device_current);
 }
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-aux.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-aux.f90
new file mode 100644
index 000000000000..02f5fbd64fb2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-aux.f90
@@ -0,0 +1,102 @@
+! Auxiliary functions for acc_get_property tests
+! { dg-do compile { target skip-all-targets } }
+! See also '../libgomp.oacc-c-c++-common/acc_get_property-aux.c'.
+
+module acc_get_property_aux
+  use openacc
+  implicit none
+
+  private
+  public :: expect_device_properties
+
+contains
+
+  subroutine expect_device_memory_properties (dev_type, dev_num, &
+       expected_total_memory)
+    integer, intent(in) :: dev_type
+    integer, intent(in) :: dev_num
+    integer(acc_device_property), intent(in) :: expected_total_memory
+
+    integer(acc_device_property) :: total_mem
+    integer(acc_device_property) :: free_mem
+
+    total_mem = acc_get_property (dev_num, dev_type, &
+         acc_property_memory)
+    if (total_mem /= expected_total_memory) then
+       print *, total_mem, expected_total_memory
+       error stop
+    end if
+
+    free_mem = acc_get_property (dev_num, dev_type, &
+         acc_property_free_memory)
+    if (free_mem .gt. total_mem) then
+       print *, free_mem, total_mem
+       error stop
+    end if
+  end subroutine expect_device_memory_properties
+
+  subroutine expect_device_non_memory_properties (dev_type, dev_num, &
+       expected_vendor, expected_name, expected_driver)
+    integer, intent(in) :: dev_type
+    integer, intent(in) :: dev_num
+    character*(*), intent(in) :: expected_vendor
+    character*(*), intent(in) :: expected_name
+    character*(*), intent(in) :: expected_driver
+
+    character*256 :: vendor
+    character*256 :: name
+    character*256 :: driver
+    integer(acc_device_property) :: v
+    character*256 :: s
+
+    call acc_get_property_string  (dev_num, dev_type, &
+         acc_property_vendor, vendor)
+    if (vendor /= expected_vendor) then
+       print *, vendor, expected_vendor
+       error stop
+    end if
+
+    call acc_get_property_string  (dev_num, dev_type, &
+         acc_property_name, name)
+    if (name /= expected_name) then
+       print *, name, expected_name
+       error stop
+    end if
+
+    call acc_get_property_string  (dev_num, dev_type, &
+         acc_property_driver, driver)
+    if (driver /= expected_driver) then
+       print *, driver, expected_driver
+       error stop
+    end if
+
+    v = acc_get_property (dev_num, dev_type, &
+         int(85061, kind = acc_device_property)) ! unknown
+    if (v /= 0) then
+       print *, v
+       error stop
+    end if
+
+    call acc_get_property_string (dev_num, dev_type, &
+         int(-85061, kind = acc_device_property), s) ! unknown
+    if (s /= "") then
+       print *, s
+       error stop
+    end if
+  end subroutine expect_device_non_memory_properties
+
+  subroutine expect_device_properties (dev_type, dev_num, &
+       expected_total_memory, expected_vendor, expected_name, expected_driver)
+    integer, intent(in) :: dev_type
+    integer, intent(in) :: dev_num
+    integer(acc_device_property), intent(in) :: expected_total_memory
+    character*(*), intent(in) :: expected_vendor
+    character*(*), intent(in) :: expected_name
+    character*(*), intent(in) :: expected_driver
+
+    call expect_device_memory_properties (dev_type, dev_num, &
+         expected_total_memory)
+    call expect_device_non_memory_properties (dev_type, dev_num, &
+         expected_vendor, expected_name, expected_driver)
+  end subroutine expect_device_properties
+end module acc_get_property_aux
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-host.F90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-host.F90
new file mode 100644
index 000000000000..3394fb74141b
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-host.F90
@@ -0,0 +1,31 @@
+! Test the `acc_get_property' and `acc_get_property_string' library
+! functions for the host device.
+! See also '../libgomp.oacc-c-c++-common/acc_get_property-host.c'.
+
+! The libgomp test harness doesn't make it easy to use modules in separate
+! compilation units, so work around that: simply 'include' the file.
+include "acc_get_property-aux.f90"
+
+program test
+  use acc_get_property_aux
+  use openacc
+  implicit none
+
+#if ACC_DEVICE_TYPE_host
+  print *, "Checking acc_device_default device properties"
+  call expect_device_properties (acc_device_default, 0, &
+      int(0, kind = acc_device_property), "GNU", "GOMP", "1.0")
+#endif
+
+  print *, "Checking acc_device_host device properties"
+  call expect_device_properties (acc_device_host, 0, &
+      int(0, kind = acc_device_property), "GNU", "GOMP", "1.0")
+
+#if ACC_DEVICE_TYPE_host
+  print *, "Checking acc_device_current device properties"
+  call expect_device_properties (acc_device_current, 135, & ! "'devicenum' is ignored"
+      int(0, kind = acc_device_property), "GNU", "GOMP", "1.0")
+#endif
+end program test
+
+! { dg-final { cleanup-modules "acc_get_property_aux" } }
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
index 80ae292f41fc..dd387683ff97 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90
@@ -1,8 +1,8 @@
-! Test the `acc_get_property' and '`acc_get_property_string' library
+! Test the `acc_get_property' and `acc_get_property_string' library
 ! functions by printing the results of those functions for all devices
 ! of all device types mentioned in the OpenACC standard.
 !
-! See also acc_get_property.c
+! See also '../libgomp.oacc-c-c++-common/acc_get_property.c'.
 
 program test
   use openacc
@@ -20,6 +20,9 @@ program test
 
   print *, "acc_device_not_host:"
   call print_device_properties (acc_device_not_host)
+
+  print *, "acc_device_current:"
+  call print_device_properties (acc_device_current)
 end program test
 
 ! Print the values of the properties of all devices of the given type
@@ -35,7 +38,13 @@ subroutine print_device_properties (device_type)
   integer(acc_device_property) :: v
   character*256 :: s
 
-  device_count = acc_get_num_devices(device_type)
+  if (device_type /= acc_device_current) then
+     device_count = acc_get_num_devices (device_type)
+  else
+     ! "'devicenum' is ignored and the value of the property for the current
+     ! device is returned".  We'd like that printed ten times, please.
+     device_count = 10
+  end if
 
   do device = 0, device_count - 1
      print "(a, i0)", "  Device ", device
-- 
2.17.1


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-29 10:10             ` Harwath, Frederik
  2020-01-29 11:07               ` Andrew Stubbs
  2020-01-29 17:58               ` Thomas Schwinge
@ 2020-01-30 16:28               ` Thomas Schwinge
  2020-01-30 16:54                 ` Andrew Stubbs
  2020-01-31 12:32                 ` Harwath, Frederik
  2 siblings, 2 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-30 16:28 UTC (permalink / raw)
  To: Frederik Harwath; +Cc: Jakub Jelinek, gcc-patches, Andrew Stubbs

[-- Attachment #1: Type: text/plain, Size: 6052 bytes --]

Hi!

Andrew and Frederik, thanks for your emails reminding/educating me about
'snprintf' as well as this HSA fixed-size buffer API.  There doesn't
happen to be something available in the HSA API available so that we
could use 'sizeof [something]' instead of hard-coding '64' etc.?


I understand correctly that the only reason for:

On 2020-01-29T10:52:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
> 	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
> 	(expect_device_properties): Split function into ...
> 	(expect_device_string_properties): ... this new function ...
> 	(expect_device_memory): ... and this new function.

... this split is that we can't test 'expect_device_memory' here:

> 	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c:
> 	Add test.

..., because that one doesn't (re-)implement the 'acc_property_memory'
interface?

> --- a/libgomp/plugin/plugin-gcn.c
> +++ b/libgomp/plugin/plugin-gcn.c

> @@ -4115,12 +4141,37 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src,
>  union goacc_property_value
>  GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop)
>  {
> [...]
> +  switch (prop)
> +    {
> +    case GOACC_PROPERTY_FREE_MEMORY:
> +      /* Not supported. */
> +      break;

(OK, can be added later when somebody feels like doing that.)

> +    case GOACC_PROPERTY_MEMORY:
> +      {
> +	size_t size;
> +	hsa_region_t region = agent->data_region;
> +	hsa_status_t status =
> +	  hsa_fns.hsa_region_get_info_fn (region, HSA_REGION_INFO_SIZE, &size);
> +	if (status == HSA_STATUS_SUCCESS)
> +	  propval.val = size;
> +	break;
> +      }
> [...]
>  }

Here we got 'acc_property_memory' implemented, but not here:

> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
> @@ -0,0 +1,132 @@
> +/* Test the `acc_get_property' and `acc_get_property_string' library
> +   functions on amdgcn devices by comparing property values with
> +   those obtained through the HSA API. */
> +/* { dg-additional-sources acc_get_property-aux.c } */
> +/* { dg-additional-options "-ldl" } */
> +/* { dg-do run { target openacc_amdgcn_accel_selected } } */
> +
> +#include <dlfcn.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <openacc.h>
> +
> +#ifndef __cplusplus
> +typedef int bool;
> +#endif
> +#include <hsa.h>
> +
> +
> +void expect_device_string_properties (acc_device_t dev_type, int dev_num,
> +				      const char* expected_vendor,
> +				      const char* expected_name,
> +				      const char* expected_driver);
> +
> +hsa_status_t (*hsa_agent_get_info_fn) (hsa_agent_t agent,
> +				       hsa_agent_info_t attribute,
> +				       void *value);
> +hsa_status_t (*hsa_system_get_info_fn) (hsa_system_info_t attribute,
> +					void *value);
> +hsa_status_t (*hsa_iterate_agents_fn)
> +(hsa_status_t (*callback)(hsa_agent_t agent, void *data), void *data);
> +hsa_status_t (*hsa_init_fn) (void);
> +
> +char* support_cpu_devices;
> +
> +void test_setup ()
> +{
> +  char* env_runtime;
> +  char* hsa_runtime_lib;
> +  void *handle;
> +
> +#define DLSYM_FN(function)						\
> +  function##_fn = (typeof(function##_fn))dlsym (handle, #function);	\
> +  if (function##_fn == NULL)						\
> +    {									\
> +      fprintf (stderr, "Could not get symbol " #function ".\n");	\
> +      abort (); 							\
> +    }
> +
> +  env_runtime = getenv ("HSA_RUNTIME_LIB");
> +  hsa_runtime_lib = env_runtime ? env_runtime : (char*)"libhsa-runtime64.so";
> +
> +  handle = dlopen (hsa_runtime_lib, RTLD_LAZY);
> +  if (!handle)
> +    {
> +      fprintf (stderr, "Could not load %s.\n", hsa_runtime_lib);
> +      abort ();
> +    }
> +
> +  DLSYM_FN (hsa_agent_get_info)
> +  DLSYM_FN (hsa_system_get_info)
> +  DLSYM_FN (hsa_iterate_agents)
> +  DLSYM_FN (hsa_init)
> +
> +  hsa_init_fn ();
> +
> +  support_cpu_devices = getenv ("GCN_SUPPORT_CPU_DEVICES");
> +}
> +
> +static hsa_status_t check_agent_properties (hsa_agent_t agent, void *dev_num_arg)
> +{
> +
> +  char name[64];
> +  char vendor_name[64];
> +  uint16_t minor;
> +  uint16_t major;
> +  char driver[60];
> +
> +  hsa_status_t status;
> +  hsa_device_type_t device_type;
> +  int* dev_num = (int*)dev_num_arg;
> +
> +#define AGENT_GET_INFO(info_type, val)				\
> +  status = hsa_agent_get_info_fn (agent, info_type, &val);	\
> +  if (status != HSA_STATUS_SUCCESS)				\
> +    {								\
> +      fprintf (stderr, "Failed to obtain " #info_type ".\n");	\
> +      abort ();							\
> +    }
> +#define SYSTEM_GET_INFO(info_type, val)				\
> +  status = hsa_system_get_info_fn (info_type, &val);		\
> +  if (status != HSA_STATUS_SUCCESS)				\
> +    {								\
> +      fprintf (stderr, "Failed to obtain " #info_type ".\n");	\
> +      abort ();							\
> +    }
> +
> +  AGENT_GET_INFO (HSA_AGENT_INFO_DEVICE, device_type)
> +
> +    /* Skip unsupported device types.  Mimic the GCN plugin's behavior. */
> +    if (!(device_type == HSA_DEVICE_TYPE_GPU
> +	  || (support_cpu_devices && device_type == HSA_DEVICE_TYPE_CPU)))
> +      return HSA_STATUS_SUCCESS;
> +
> +  AGENT_GET_INFO (HSA_AGENT_INFO_NAME, name)
> +  AGENT_GET_INFO (HSA_AGENT_INFO_VENDOR_NAME, vendor_name)
> +
> +  SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MINOR, minor)
> +  SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MAJOR, major)
> +
> +  snprintf (driver, sizeof driver, "HSA Runtime %hu.%hu",
> +	    (unsigned short int)major, (unsigned short int)minor);
> +
> +  expect_device_string_properties(acc_device_radeon, *dev_num,
> +				  vendor_name, name, driver);
> +
> +  (*dev_num)++;
> +
> +  return status;
> +}
> +
> +int main ()
> +{
> +  int dev_num = 0;
> +  test_setup ();
> +
> +  hsa_status_t status =
> +    hsa_iterate_agents_fn (&check_agent_properties, &dev_num);
> +
> +  return status;
> +}


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-30 16:28               ` Thomas Schwinge
@ 2020-01-30 16:54                 ` Andrew Stubbs
  2020-01-31  9:32                   ` Thomas Schwinge
  2020-01-31 12:32                 ` Harwath, Frederik
  1 sibling, 1 reply; 38+ messages in thread
From: Andrew Stubbs @ 2020-01-30 16:54 UTC (permalink / raw)
  To: Thomas Schwinge, Frederik Harwath; +Cc: Jakub Jelinek, gcc-patches

On 30/01/2020 16:08, Thomas Schwinge wrote:
> Hi!
> 
> Andrew and Frederik, thanks for your emails reminding/educating me about
> 'snprintf' as well as this HSA fixed-size buffer API.  There doesn't
> happen to be something available in the HSA API available so that we
> could use 'sizeof [something]' instead of hard-coding '64' etc.?

No, not at present; hsa_agent_get_info_fn is a somewhat generic 
interface that takes an enum and returns a void*. The return type is 
written in the documentation: 
https://rocm-documentation.readthedocs.io/en/latest/ROCm_API_References/ROCr-API.html#rocr-api

However, we don't use the official ROCm header files, because 
dependencies and licenses, so we could invent our own typedefs in hsa.h, 
if we chose. I don't see that doing so would be worth the effort now, or 
maintenance burden later.

I'll let Frederik explain his implementation decisions.

Andrew

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-30 16:54                 ` Andrew Stubbs
@ 2020-01-31  9:32                   ` Thomas Schwinge
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-31  9:32 UTC (permalink / raw)
  To: Andrew Stubbs, Frederik Harwath; +Cc: Jakub Jelinek, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1148 bytes --]

Hi!

On 2020-01-30T16:45:39+0000, Andrew Stubbs <ams@codesourcery.com> wrote:
> On 30/01/2020 16:08, Thomas Schwinge wrote:
>> Andrew and Frederik, thanks for your emails reminding/educating me about
>> 'snprintf' as well as this HSA fixed-size buffer API.  There doesn't
>> happen to be something available in the HSA API available so that we
>> could use 'sizeof [something]' instead of hard-coding '64' etc.?
>
> No, not at present; hsa_agent_get_info_fn is a somewhat generic 
> interface that takes an enum and returns a void*. The return type is 
> written in the documentation: 
> https://rocm-documentation.readthedocs.io/en/latest/ROCm_API_References/ROCr-API.html#rocr-api
>
> However, we don't use the official ROCm header files, because 
> dependencies and licenses, so we could invent our own typedefs in hsa.h, 
> if we chose. I don't see that doing so would be worth the effort now, or 
> maintenance burden later.

ACK.  I was just curious if there's an easy way to properly resolve this
"magic numbers" issue now, once and for all.  Apparently, there isn't --
which shall be fine, then.


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-30 16:28               ` Thomas Schwinge
  2020-01-30 16:54                 ` Andrew Stubbs
@ 2020-01-31 12:32                 ` Harwath, Frederik
  2020-01-31 14:49                   ` Thomas Schwinge
  1 sibling, 1 reply; 38+ messages in thread
From: Harwath, Frederik @ 2020-01-31 12:32 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Jakub Jelinek, gcc-patches, Andrew Stubbs

Hi Thomas,

On 30.01.20 17:08, Thomas Schwinge wrote:

> I understand correctly that the only reason for:
> 
> On 2020-01-29T10:52:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>> 	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
>> 	(expect_device_properties): Split function into ...
>> 	(expect_device_string_properties): ... this new function ...
>> 	(expect_device_memory): ... and this new function.
> 
> ... this split is that we can't test 'expect_device_memory' here:

> [...]

> ..., because that one doesn't (re-)implement the 'acc_property_memory'
> interface?

Correct. But why "re-"? It has not been implemented before.

>> --- a/libgomp/plugin/plugin-gcn.c
>> +++ b/libgomp/plugin/plugin-gcn.c
> 
>> @@ -4115,12 +4141,37 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src,
>>  union goacc_property_value
>>  GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop)
>>  {
>> [...]
>> +  switch (prop)
>> +    {
>> +    case GOACC_PROPERTY_FREE_MEMORY:
>> +      /* Not supported. */
>> +      break;
> 
> (OK, can be added later when somebody feels like doing that.)

Well, "not supported" means that there seems to be no (reasonable) way to obtain
the necessary information from the runtime - in contrast to the nvptx plugin
where it can be obtained easily through the CUDA API.

> 
>> +    case GOACC_PROPERTY_MEMORY:
>> +      {
>> +	size_t size;
>> +	hsa_region_t region = agent->data_region;
>> +	hsa_status_t status =
>> +	  hsa_fns.hsa_region_get_info_fn (region, HSA_REGION_INFO_SIZE, &size);
>> +	if (status == HSA_STATUS_SUCCESS)
>> +	  propval.val = size;
>> +	break;
>> +      }
>> [...]
>>  }
> 
> Here we got 'acc_property_memory' implemented, but not here:
> 
>> --- /dev/null
>> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c

Yes, there seems to be no straightforward way to determine the expected value through
the runtime API. We might of course try to replicate the logic that is
used in plugin-gcn.c.

Best regards,
Frederik

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC acc_get_property support for AMD GCN
  2020-01-31 12:32                 ` Harwath, Frederik
@ 2020-01-31 14:49                   ` Thomas Schwinge
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-01-31 14:49 UTC (permalink / raw)
  To: Frederik Harwath; +Cc: Jakub Jelinek, gcc-patches, Andrew Stubbs

[-- Attachment #1: Type: text/plain, Size: 3178 bytes --]

Hi Frederik!

On 2020-01-31T13:17:52+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
> On 30.01.20 17:08, Thomas Schwinge wrote:
>
>> I understand correctly that the only reason for:
>> 
>> On 2020-01-29T10:52:57+0100, "Harwath, Frederik" <frederik@codesourcery.com> wrote:
>>> 	* testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c
>>> 	(expect_device_properties): Split function into ...
>>> 	(expect_device_string_properties): ... this new function ...
>>> 	(expect_device_memory): ... and this new function.
>> 
>> ... this split is that we can't test 'expect_device_memory' here:
>
>> [...]
>
>> ..., because that one doesn't (re-)implement the 'acc_property_memory'
>> interface?
>
> Correct.

OK, thanks for confirming.

> But why "re-"? It has not been implemented before.

Well, yes, it has already been implemented: in
'libgomp/plugin/plugin-gcn.c' ;-) -- that's why I meant it's
re-implemented in the test case(s): in a similar yet slightly different
way compared to the respective plugin(s).  And for avoidance of doubt: I
agree that's a good approach to verify that we're getting some consistent
and meaningful results.)

>>> --- a/libgomp/plugin/plugin-gcn.c
>>> +++ b/libgomp/plugin/plugin-gcn.c

>>> +    case GOACC_PROPERTY_MEMORY:
>>> +      {
>>> +	size_t size;
>>> +	hsa_region_t region = agent->data_region;
>>> +	hsa_status_t status =
>>> +	  hsa_fns.hsa_region_get_info_fn (region, HSA_REGION_INFO_SIZE, &size);
>>> +	if (status == HSA_STATUS_SUCCESS)
>>> +	  propval.val = size;
>>> +	break;
>>> +      }
>>> [...]
>>>  }
>> 
>> Here we got 'acc_property_memory' implemented, but not here:
>> 
>>> --- /dev/null
>>> +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c
>
> Yes, there seems to be no straightforward way to determine the expected value through
> the runtime API. We might of course try to replicate the logic that is
> used in plugin-gcn.c.

No need to do that now; I was just curious whether that's the reason.


>>> --- a/libgomp/plugin/plugin-gcn.c
>>> +++ b/libgomp/plugin/plugin-gcn.c
>> 
>>> @@ -4115,12 +4141,37 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src,
>>>  union goacc_property_value
>>>  GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop)
>>>  {
>>> [...]
>>> +  switch (prop)
>>> +    {
>>> +    case GOACC_PROPERTY_FREE_MEMORY:
>>> +      /* Not supported. */
>>> +      break;
>> 
>> (OK, can be added later when somebody feels like doing that.)
>
> Well, "not supported" means that there seems to be no (reasonable) way to obtain
> the necessary information from the runtime - in contrast to the nvptx plugin
> where it can be obtained easily through the CUDA API.

OK, I see, and again that's fine.  (The API explicitly permits such
"zero" returns.)

And, I don't know what a user is actually supposed to tell from
'acc_property_free_memory' given that this can change at any point in
time, arbitrarily, not under control of the executing processe, given
that multiple processes may be using the GPU concurrently.


Grüße
 Thomas

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 658 bytes --]

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Make OpenACC 'acc_get_property' with 'acc_device_current' work (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support)
  2020-01-30 16:14             ` Make OpenACC 'acc_get_property' with 'acc_device_current' work (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support) Thomas Schwinge
@ 2020-02-03 12:16               ` Harwath, Frederik
  2020-02-03 14:41               ` Make OpenACC 'acc_get_property' with 'acc_device_current' work Tobias Burnus
  1 sibling, 0 replies; 38+ messages in thread
From: Harwath, Frederik @ 2020-02-03 12:16 UTC (permalink / raw)
  To: Thomas Schwinge, gcc-patches, Tobias Burnus; +Cc: Jakub Jelinek, fortran

Hi Thomas,

On 30.01.20 16:54, Thomas Schwinge wrote:
> 
> [...] the 'acc_device_current' interface should work already now.
> 
> [...] Please review
> the attached (Tobias the Fortran test cases, please), and test with AMD
> GCN offloading.  If approving this patch, please respond with

I have tested the patch with AMD GCN offloading and I have observed no regressions.
The new tests pass as expected and print the correct output.
Great that you have extended the Fortran tests!

> diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c
> index ef12b4c16d01..c28c0f689ba2 100644
> --- a/libgomp/oacc-init.c
> +++ b/libgomp/oacc-init.c
> @@ -796,7 +796,9 @@ get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
> size_t
> acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
> {
> -  if (!known_device_type_p (d))
> +  if (d == acc_device_current)
> +    ; /* Allowed only for 'acc_get_property', 'acc_get_property_string'.  */
> +  else if (!known_device_type_p (d))
>     unknown_device_type_error(d);

I don't like the empty if branch very much. Introducing a variable
(for instance, "bool allowed_device_type = acc_device_current
|| known_device_type(d);") would also provide a place for your comment.
You could also extract a function to avoid duplicating the explanation
in acc_get_property_string.

The patch looks good to me.

Reviewed-by: Frederik Harwath  <frederik@codesourcery.com>

Best regards,
Frederik

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: Make OpenACC 'acc_get_property' with 'acc_device_current' work
  2020-01-30 16:14             ` Make OpenACC 'acc_get_property' with 'acc_device_current' work (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support) Thomas Schwinge
  2020-02-03 12:16               ` Harwath, Frederik
@ 2020-02-03 14:41               ` Tobias Burnus
  1 sibling, 0 replies; 38+ messages in thread
From: Tobias Burnus @ 2020-02-03 14:41 UTC (permalink / raw)
  To: Thomas Schwinge, Frederik Harwath, gcc-patches; +Cc: Jakub Jelinek, fortran

Hi Thomas,

On 1/30/20 4:54 PM, Thomas Schwinge wrote:

>> That's still pending.  Recently,<https://github.com/OpenACC/openacc-spec/issues/256>  "Missing definition
>> for acc_device_current" got filed; let's (also/first) watch/wait what
>> comes out of that.

(Still pending.)

> Please review the attached (Tobias the Fortran test cases, please),
> and test with AMD GCN offloading.  If approving this patch, please respond with
> "Reviewed-by: NAME <EMAIL>" so that your effort will be recorded in the
> commit log, see<https://gcc.gnu.org/wiki/Reviewed-by>.

LGTM with the minor nit regarding the integer kind used
for dev_type (default/unspecified vs. "acc_device_kind").
To make you happy:

Reviewed-by: Tobias Burnus <tobias@codesourcery.com>

Thanks,

Tobias

> --- a/libgomp/openacc.f90
> +++ b/libgomp/openacc.f90
> @@ -766,6 +766,7 @@ module openacc
>   
>     ! From openacc_kinds
>     public :: acc_device_kind
> +  public :: acc_device_current

Good catch!

> +++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property-aux.f90
> …
> +  subroutine expect_device_memory_properties (dev_type, dev_num, &
> +       expected_total_memory)
> +    integer, intent(in) :: dev_type

I think you should use (w/ or w/o "value" attribute)
    integer (acc_device_kind) :: dev_type
instead for consistency. It does not matter in practice but is nicer.

> +       expected_vendor, expected_name, expected_driver)
> +    integer, intent(in) :: dev_type
> +    integer, intent(in) :: dev_num
> +    character*(*), intent(in) :: expected_vendor

Likewise for dev_num.

(Side note: I personally prefer "character(*)" or (even better:) "character(len=*)"
to the "character*…" syntax – as I find it more readable. But that your syntax is
not even marked as obsolescent and, hence, is perfectly valid.)

> +    integer, intent(in) :: dev_num

Ditto.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH] Add OpenACC 2.6 `acc_get_property' support
  2019-12-16 23:06     ` Thomas Schwinge
                         ` (2 preceding siblings ...)
  2019-12-20 17:11       ` Harwath, Frederik
@ 2020-04-29  9:19       ` Thomas Schwinge
  3 siblings, 0 replies; 38+ messages in thread
From: Thomas Schwinge @ 2020-04-29  9:19 UTC (permalink / raw)
  To: Frederik Harwath, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1174 bytes --]

Hi!

On 2019-12-17T00:00:04+0100, I wrote:
> On 2019-11-14T16:35:31+0100, Frederik Harwath <frederik@codesourcery.com> wrote:
>> this patch implements OpenACC 2.6 "acc_get_property" and related functions.

> As I mentioned before ("thinking aloud"):
>
> | [...] 'acc_device_current' [is] relevant only for
> | 'acc_get_property', to return "the value of the property for the current
> | device".  This [now has a] special (negative?) value
> | [...], so that when additional real device types are added
> | later on, we can just add them with increasing numbers, and keep the
> | scanning code simple.

> Should this actually get value '-1' instead of '-3'?  Or, is the OpenACC
> 'acc_device_t' code already paying special attention to negative values
> '-1', '-2'?  (I don't think so.)

Now pushed this change to master branch in commit
a5d0bc12e1bfa956941cd9c49d5b978256bd11ec "[OpenACC] Set
'acc_device_current = -1'", see attached.


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-OpenACC-Set-acc_device_current-1.patch --]
[-- Type: text/x-diff, Size: 3662 bytes --]

From a5d0bc12e1bfa956941cd9c49d5b978256bd11ec Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Wed, 29 Apr 2020 08:12:36 +0200
Subject: [PATCH] [OpenACC] Set 'acc_device_current = -1'

There's no point in using value '-3', and even though not directly related,
value '-1' does match 'GOMP_DEVICE_ICV'.

	libgomp/
	* config/accel/openacc.f90 (acc_device_current): Set to '-1'.
	* openacc.f90 (acc_device_current): Likewise.
	* openacc.h (acc_device_current): Likewise.
	* openacc_lib.h (acc_device_current): Likewise.
---
 libgomp/ChangeLog                | 5 +++++
 libgomp/config/accel/openacc.f90 | 2 +-
 libgomp/openacc.f90              | 2 +-
 libgomp/openacc.h                | 2 +-
 libgomp/openacc_lib.h            | 2 +-
 5 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 1a7046f2fc64..b6828adcbe3d 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,5 +1,10 @@
 2020-04-29  Thomas Schwinge  <thomas@codesourcery.com>
 
+	* config/accel/openacc.f90 (acc_device_current): Set to '-1'.
+	* openacc.f90 (acc_device_current): Likewise.
+	* openacc.h (acc_device_current): Likewise.
+	* openacc_lib.h (acc_device_current): Likewise.
+
 	PR target/94282
 	* testsuite/libgomp.c-c++-common/function-not-offloaded.c: Remove
 	'dg-allow-blank-lines-in-output'.
diff --git a/libgomp/config/accel/openacc.f90 b/libgomp/config/accel/openacc.f90
index 275afe43475c..99330733d8f8 100644
--- a/libgomp/config/accel/openacc.f90
+++ b/libgomp/config/accel/openacc.f90
@@ -44,7 +44,7 @@ module openacc_kinds
   integer, parameter :: acc_device_kind = int32
 
   ! Keep in sync with include/gomp-constants.h.
-  integer (acc_device_kind), parameter :: acc_device_current = -3
+  integer (acc_device_kind), parameter :: acc_device_current = -1
   integer (acc_device_kind), parameter :: acc_device_none = 0
   integer (acc_device_kind), parameter :: acc_device_default = 1
   integer (acc_device_kind), parameter :: acc_device_host = 2
diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90
index 467fb612c548..111705d0fb60 100644
--- a/libgomp/openacc.f90
+++ b/libgomp/openacc.f90
@@ -41,7 +41,7 @@ module openacc_kinds
   integer, parameter :: acc_device_kind = int32
 
   ! Keep in sync with include/gomp-constants.h.
-  integer (acc_device_kind), parameter :: acc_device_current = -3
+  integer (acc_device_kind), parameter :: acc_device_current = -1
   integer (acc_device_kind), parameter :: acc_device_none = 0
   integer (acc_device_kind), parameter :: acc_device_default = 1
   integer (acc_device_kind), parameter :: acc_device_host = 2
diff --git a/libgomp/openacc.h b/libgomp/openacc.h
index 617364634748..1dc471f62bc7 100644
--- a/libgomp/openacc.h
+++ b/libgomp/openacc.h
@@ -49,7 +49,7 @@ extern "C" {
 /* Types */
 typedef enum acc_device_t {
   /* Keep in sync with include/gomp-constants.h.  */
-  acc_device_current = -3,
+  acc_device_current = -1,
   acc_device_none = 0,
   acc_device_default = 1,
   acc_device_host = 2,
diff --git a/libgomp/openacc_lib.h b/libgomp/openacc_lib.h
index ee08e9787cc9..82a3735b1063 100644
--- a/libgomp/openacc_lib.h
+++ b/libgomp/openacc_lib.h
@@ -37,7 +37,7 @@
       integer, parameter :: acc_device_kind = 4
 
 !     Keep in sync with include/gomp-constants.h.
-      integer (acc_device_kind), parameter :: acc_device_current = -3
+      integer (acc_device_kind), parameter :: acc_device_current = -1
       integer (acc_device_kind), parameter :: acc_device_none = 0
       integer (acc_device_kind), parameter :: acc_device_default = 1
       integer (acc_device_kind), parameter :: acc_device_host = 2
-- 
2.26.2


^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2020-04-29  9:20 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-03 16:51 [PATCH, og8] Add OpenACC 2.6 `acc_get_property' support Maciej W. Rozycki
2018-12-05 10:12 ` Chung-Lin Tang
2018-12-05 18:17   ` Maciej W. Rozycki
2018-12-10  9:06     ` Chung-Lin Tang
2018-12-20 14:25       ` Maciej W. Rozycki
2019-01-08 17:42 ` Thomas Schwinge
2019-10-07 18:41 ` Thomas Schwinge
2019-11-05 15:09   ` Harwath, Frederik
2019-11-14 15:41   ` [PATCH] " Frederik Harwath
2019-12-16 23:06     ` Thomas Schwinge
2019-12-17  9:39       ` Martin Jambor
2019-12-17  9:47       ` Andrew Stubbs
2019-12-20 17:11       ` Harwath, Frederik
2019-12-21 23:01         ` Thomas Schwinge
2019-12-22 22:20           ` Harwath, Frederik
2020-01-10 23:44           ` Thomas Schwinge
2020-01-30 16:14             ` Make OpenACC 'acc_get_property' with 'acc_device_current' work (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support) Thomas Schwinge
2020-02-03 12:16               ` Harwath, Frederik
2020-02-03 14:41               ` Make OpenACC 'acc_get_property' with 'acc_device_current' work Tobias Burnus
2020-01-16 16:03         ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge
2020-01-20 14:20           ` Harwath, Frederik
2020-01-23 15:08             ` Thomas Schwinge
2020-01-24  9:36               ` Harwath, Frederik
2020-01-27 14:57         ` Fortran 'acc_get_property' return type (was: [PATCH] Add OpenACC 2.6 `acc_get_property' support) Thomas Schwinge
2020-01-28 15:31         ` [PATCH] Add OpenACC acc_get_property support for AMD GCN Harwath, Frederik
2020-01-28 16:14           ` Andrew Stubbs
2020-01-29 10:10             ` Harwath, Frederik
2020-01-29 11:07               ` Andrew Stubbs
2020-01-29 11:47                 ` Harwath, Frederik
2020-01-29 17:58               ` Thomas Schwinge
2020-01-29 18:12                 ` Andrew Stubbs
2020-01-30  8:04                 ` Harwath, Frederik
2020-01-30 16:28               ` Thomas Schwinge
2020-01-30 16:54                 ` Andrew Stubbs
2020-01-31  9:32                   ` Thomas Schwinge
2020-01-31 12:32                 ` Harwath, Frederik
2020-01-31 14:49                   ` Thomas Schwinge
2020-04-29  9:19       ` [PATCH] Add OpenACC 2.6 `acc_get_property' support Thomas Schwinge

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).