Hi Jakub! On 2018-12-03T16:51:14+0000, "Maciej W. Rozycki" <ma...@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
From 4674caa90e82c209db51bf1fb5d7ec42364d47a2 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" <ma...@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 <ma...@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 <jul...@codesourcery.com> Maciej W. Rozycki <ma...@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 <ma...@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 <jul...@codesourcery.com> Maciej W. Rozycki <ma...@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
From 1fa609ba73e9990ae7a65b083047f0ee219167b3 Mon Sep 17 00:00:00 2001 From: Thomas Schwinge <tho...@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 <tho...@codesourcery.com> + + * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property): + New function. + 2019-02-26 Chung-Lin Tang <clt...@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
signature.asc
Description: PGP signature