+2019-12-22 Maciej W. Rozycki <macro@codesourcery.com>
+ Frederik Harwath <frederik@codesourcery.com>
+ Thomas Schwinge <tschwinge@codesourcery.com>
+
+ * gomp-constants.h (gomp_device_property): New enum.
+
2019-12-19 Julian Brown <julian@codesourcery.com>
* gomp-constants.h (gomp_map_kind): Add GOMP_MAP_ATTACH_DETACH.
#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)
+2019-12-22 Maciej W. Rozycki <macro@codesourcery.com>
+ Frederik Harwath <frederik@codesourcery.com>
+ Thomas Schwinge <tschwinge@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 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.
+
2019-12-22 Maciej W. Rozycki <macro@wdc.com>
* testsuite/libgomp-test-support.exp.in (GCC_UNDER_TEST): New
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;
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);
__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;
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 {
* 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
+@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
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)))
{
.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,
}
assert (res != acc_device_default
- && res != acc_device_not_host);
+ && res != acc_device_not_host
+ && res != acc_device_current);
return res;
}
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.
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
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.
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
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
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
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
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
/* 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,
_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,
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;
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)
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)
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. */
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. */
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;
bool map;
bool concur;
bool mkern;
- int mode;
+ int mode;
int clock_khz;
int num_sms;
int regs_per_block;
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. */
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;
}
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);
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)
{
DLSYM (get_caps);
DLSYM (get_type);
DLSYM (get_num_devices);
+ DLSYM (get_property);
DLSYM (init_device);
DLSYM (fini_device);
DLSYM (load_image);
--- /dev/null
+/* 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);
+ }
+}
--- /dev/null
+/* 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
+/* 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 ();
+ }
+
+
+}
--- /dev/null
+/* 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 { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } } */
+/* FIXME: This test does not work with the GCN implementation stub yet. */
+
+#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);
+}
--- /dev/null
+! 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 { target { { ! { openacc_host_selected } } && { ! { openacc_amdgcn_accel_selected } } } } }
+! FIXME: This test does not work with the GCN implementation stub yet.
+
+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
+2019-12-22 Maciej W. Rozycki <macro@codesourcery.com>
+ Frederik Harwath <frederik@codesourcery.com>
+ Thomas Schwinge <tschwinge@codesourcery.com>
+
+ liboffloadmic/
+ * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property):
+ New function.
+
2019-10-01 Maciej W. Rozycki <macro@wdc.com>
* plugin/configure: Regenerate.
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)