From: Maciej W. Rozycki Date: Thu, 20 Dec 2018 14:10:17 +0000 (+0000) Subject: Add OpenACC 2.6 `acc_get_property' support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=10b865e4c06a2a0b33ec0d9518110c0b8f6ed4ac;p=thirdparty%2Fgcc.git 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. (cherry picked from openacc-gcc-9-branch commit 4674caa90e82c209db51bf1fb5d7ec42364d47a2) --- diff --git a/include/ChangeLog.omp b/include/ChangeLog.omp index bd8dba0544c6..2cbb9919f600 100644 --- a/include/ChangeLog.omp +++ b/include/ChangeLog.omp @@ -1,3 +1,11 @@ +2018-12-20 Maciej W. Rozycki + + * 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 Maciej W. Rozycki diff --git a/include/gomp-constants.h b/include/gomp-constants.h index dae4eea66de2..5634babd8402 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.omp b/libgomp/ChangeLog.omp index 6c1defe2011b..963e28621e40 100644 --- a/libgomp/ChangeLog.omp +++ b/libgomp/ChangeLog.omp @@ -1,3 +1,47 @@ +2018-12-20 Maciej W. Rozycki + + * 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 Maciej W. Rozycki diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h index be7c994faebc..da8ce260564a 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 9c9157d826c1..31403ba67a9c 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 aa76ee309ffd..717ae6684008 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 e2e384ae8b62..b2fc35b32c29 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 b19b7479afd6..beeca287e15b 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 7e34c856f33e..0cd673ecc205 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 bc205453f820..05ed3cd83db8 100644 --- a/libgomp/openacc.f90 +++ b/libgomp/openacc.f90 @@ -28,7 +28,7 @@ ! . 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 8af3478f3666..26084dc5ddd3 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 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 a2b9bdbeb34a..3c990c52067c 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 b7a1a6c40f57..cb18e875a40e 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 62b8ee4759ee..8e6b4264b720 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 000000000000..5bf1b849e2b9 --- /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 +#include +#include +#include + +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 000000000000..9ffeb05148e5 --- /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