Add OpenACC 2.6 `acc_get_property' support

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

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

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

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

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

with the NVPTX driver.

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

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

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

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

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

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

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


Co-Authored-By: Frederik Harwath <frederik@codesourcery.com>
Co-Authored-By: Thomas Schwinge <tschwinge@codesourcery.com>

From-SVN: r279710
This commit is contained in:
Maciej W. Rozycki 2019-12-22 19:54:09 +00:00 committed by Frederik Harwath
parent edadb8adc3
commit 6c84c8bf9b
23 changed files with 841 additions and 6 deletions

View File

@ -1,3 +1,9 @@
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.

View File

@ -195,6 +195,21 @@ enum gomp_map_kind
#define GOMP_DEVICE_ICV -1
#define GOMP_DEVICE_HOST_FALLBACK -2
/* Device property codes. Keep in sync with
libgomp/{openacc.h,openacc.f90}:acc_device_property_t */
/* Start from 1 to catch uninitialized use. */
enum gomp_device_property
{
GOMP_DEVICE_PROPERTY_MEMORY = 1,
GOMP_DEVICE_PROPERTY_FREE_MEMORY = 2,
GOMP_DEVICE_PROPERTY_NAME = 0x10001,
GOMP_DEVICE_PROPERTY_VENDOR = 0x10002,
GOMP_DEVICE_PROPERTY_DRIVER = 0x10003
};
/* Internal property mask to tell numeric and string values apart. */
#define GOMP_DEVICE_PROPERTY_STRING_MASK 0x10000
/* GOMP_task/GOMP_taskloop* flags argument. */
#define GOMP_TASK_FLAG_UNTIED (1 << 0)
#define GOMP_TASK_FLAG_FINAL (1 << 1)

View File

@ -1,3 +1,54 @@
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

View File

@ -54,6 +54,13 @@ enum offload_target_type
OFFLOAD_TARGET_TYPE_GCN = 8
};
/* Container type for passing device properties. */
union gomp_device_property_value
{
const char *ptr;
size_t val;
};
/* Opaque type to represent plugin-dependent implementation of an
OpenACC asynchronous queue. */
struct goacc_asyncqueue;
@ -94,6 +101,7 @@ extern const char *GOMP_OFFLOAD_get_name (void);
extern unsigned int GOMP_OFFLOAD_get_caps (void);
extern int GOMP_OFFLOAD_get_type (void);
extern int GOMP_OFFLOAD_get_num_devices (void);
extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int);
extern bool GOMP_OFFLOAD_init_device (int);
extern bool GOMP_OFFLOAD_fini_device (int);
extern unsigned GOMP_OFFLOAD_version (void);

View File

@ -1113,6 +1113,7 @@ struct gomp_device_descr
__typeof (GOMP_OFFLOAD_get_caps) *get_caps_func;
__typeof (GOMP_OFFLOAD_get_type) *get_type_func;
__typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func;
__typeof (GOMP_OFFLOAD_get_property) *get_property_func;
__typeof (GOMP_OFFLOAD_init_device) *init_device_func;
__typeof (GOMP_OFFLOAD_fini_device) *fini_device_func;
__typeof (GOMP_OFFLOAD_version) *version_func;

View File

@ -492,6 +492,10 @@ OACC_2.6 {
acc_detach_async;
acc_detach_finalize;
acc_detach_finalize_async;
acc_get_property;
acc_get_property_h_;
acc_get_property_string;
acc_get_property_string_h_;
} OACC_2.5.1;
GOACC_2.0 {

View File

@ -1849,6 +1849,7 @@ acceleration device.
* acc_get_device_type:: Get type of device accelerator to be used.
* acc_set_device_num:: Set device number to use.
* acc_get_device_num:: Get device number to be used.
* acc_get_property:: Get device property.
* acc_async_test:: Tests for completion of a specific asynchronous
operation.
* acc_async_test_all:: Tests for completion of all asychronous
@ -2038,6 +2039,44 @@ region.
@node acc_get_property
@section @code{acc_get_property} -- Get device property.
@cindex acc_get_property
@cindex acc_get_property_string
@table @asis
@item @emph{Description}
These routines return the value of the specified @var{property} for the
device being queried according to @var{devicenum} and @var{devicetype}.
Integer-valued and string-valued properties are returned by
@code{acc_get_property} and @code{acc_get_property_string} respectively.
The Fortran @code{acc_get_property_string} subroutine returns the string
retrieved in its fourth argument while the remaining entry points are
functions, which pass the return value as their result.
@item @emph{C/C++}:
@multitable @columnfractions .20 .80
@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);}
@end multitable
@item @emph{Fortran}:
@multitable @columnfractions .20 .80
@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)}
@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)}
@item @tab @code{integer devicenum}
@item @tab @code{integer(kind=acc_device_kind) devicetype}
@item @tab @code{integer(kind=acc_device_property) property}
@item @tab @code{integer(kind=acc_device_property) acc_get_property}
@item @tab @code{character(*) string}
@end multitable
@item @emph{Reference}:
@uref{https://www.openacc.org, OpenACC specification v2.6}, section
3.2.6.
@end table
@node acc_async_test
@section @code{acc_async_test} -- Test for completion of a specific asynchronous operation.
@table @asis

View File

@ -59,6 +59,27 @@ host_get_num_devices (void)
return 1;
}
static union gomp_device_property_value
host_get_property (int n, int prop)
{
union gomp_device_property_value nullval = { .val = 0 };
if (n >= host_get_num_devices ())
return nullval;
switch (prop)
{
case GOMP_DEVICE_PROPERTY_NAME:
return (union gomp_device_property_value) { .ptr = "GOMP" };
case GOMP_DEVICE_PROPERTY_VENDOR:
return (union gomp_device_property_value) { .ptr = "GNU" };
case GOMP_DEVICE_PROPERTY_DRIVER:
return (union gomp_device_property_value) { .ptr = VERSION };
default:
return nullval;
}
}
static bool
host_init_device (int n __attribute__ ((unused)))
{
@ -248,6 +269,7 @@ static struct gomp_device_descr host_dispatch =
.get_caps_func = host_get_caps,
.get_type_func = host_get_type,
.get_num_devices_func = host_get_num_devices,
.get_property_func = host_get_property,
.init_device_func = host_init_device,
.fini_device_func = host_fini_device,
.version_func = host_version,

View File

@ -670,7 +670,8 @@ acc_get_device_type (void)
}
assert (res != acc_device_default
&& res != acc_device_not_host);
&& res != acc_device_not_host
&& res != acc_device_current);
return res;
}
@ -759,6 +760,66 @@ acc_set_device_num (int ord, acc_device_t d)
ialias (acc_set_device_num)
static union gomp_device_property_value
get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
{
goacc_lazy_initialize ();
struct goacc_thread *thr = goacc_thread ();
if (d == acc_device_current && thr && thr->dev)
return thr->dev->get_property_func (thr->dev->target_id, prop);
gomp_mutex_lock (&acc_device_lock);
struct gomp_device_descr *dev = resolve_device (d, true);
int num_devices = dev->get_num_devices_func ();
if (num_devices <= 0 || ord >= num_devices)
acc_dev_num_out_of_range (d, ord, num_devices);
dev += ord;
gomp_mutex_lock (&dev->lock);
if (dev->state == GOMP_DEVICE_UNINITIALIZED)
gomp_init_device (dev);
gomp_mutex_unlock (&dev->lock);
gomp_mutex_unlock (&acc_device_lock);
assert (dev);
return dev->get_property_func (dev->target_id, prop);
}
size_t
acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
{
if (!known_device_type_p (d))
unknown_device_type_error(d);
if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
return 0;
else
return get_property_any (ord, d, prop).val;
}
ialias (acc_get_property)
const char *
acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
{
if (!known_device_type_p (d))
unknown_device_type_error(d);
if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK)
return get_property_any (ord, d, prop).ptr;
else
return NULL;
}
ialias (acc_get_property_string)
/* For -O and higher, the compiler always attempts to expand acc_on_device, but
if the user disables the builtin, or calls it via a pointer, we'll need this
version.

View File

@ -31,16 +31,18 @@
module openacc_kinds
use iso_fortran_env, only: int32
use iso_c_binding, only: c_size_t
implicit none
public
private :: int32
private :: int32, c_size_t
! When adding items, also update 'public' setting in 'module openacc' below.
integer, parameter :: acc_device_kind = int32
! Keep in sync with include/gomp-constants.h.
integer (acc_device_kind), parameter :: acc_device_current = -3
integer (acc_device_kind), parameter :: acc_device_none = 0
integer (acc_device_kind), parameter :: acc_device_default = 1
integer (acc_device_kind), parameter :: acc_device_host = 2
@ -49,6 +51,15 @@ module openacc_kinds
integer (acc_device_kind), parameter :: acc_device_nvidia = 5
integer (acc_device_kind), parameter :: acc_device_gcn = 8
integer, parameter :: acc_device_property = c_size_t
! Keep in sync with include/gomp-constants.h.
integer (acc_device_property), parameter :: acc_property_memory = 1
integer (acc_device_property), parameter :: acc_property_free_memory = 2
integer (acc_device_property), parameter :: acc_property_name = int(Z'10001')
integer (acc_device_property), parameter :: acc_property_vendor = int(Z'10002')
integer (acc_device_property), parameter :: acc_property_driver = int(Z'10003')
integer, parameter :: acc_handle_kind = int32
! Keep in sync with include/gomp-constants.h.
@ -89,6 +100,24 @@ module openacc_internal
integer (acc_device_kind) d
end function
function acc_get_property_h (n, d, p)
import
implicit none (type, external)
integer (acc_device_property) :: acc_get_property_h
integer, value :: n
integer (acc_device_kind), value :: d
integer (acc_device_property), value :: p
end function
subroutine acc_get_property_string_h (n, d, p, s)
import
implicit none (type, external)
integer, value :: n
integer (acc_device_kind), value :: d
integer (acc_device_property), value :: p
character (*) :: s
end subroutine
function acc_async_test_h (a)
logical acc_async_test_h
integer a
@ -508,6 +537,26 @@ module openacc_internal
integer (c_int), value :: d
end function
function acc_get_property_l (n, d, p) &
bind (C, name = "acc_get_property")
use iso_c_binding, only: c_int, c_size_t
implicit none (type, external)
integer (c_size_t) :: acc_get_property_l
integer (c_int), value :: n
integer (c_int), value :: d
integer (c_int), value :: p
end function
function acc_get_property_string_l (n, d, p) &
bind (C, name = "acc_get_property_string")
use iso_c_binding, only: c_int, c_ptr
implicit none (type, external)
type (c_ptr) :: acc_get_property_string_l
integer (c_int), value :: n
integer (c_int), value :: d
integer (c_int), value :: p
end function
function acc_async_test_l (a) &
bind (C, name = "acc_async_test")
use iso_c_binding, only: c_int
@ -716,16 +765,23 @@ module openacc
private
! From openacc_kinds
public :: acc_device_kind, acc_handle_kind
public :: acc_device_kind
public :: acc_device_none, acc_device_default, acc_device_host
public :: acc_device_not_host, acc_device_nvidia, acc_device_gcn
public :: acc_device_property
public :: acc_property_memory, acc_property_free_memory
public :: acc_property_name, acc_property_vendor, acc_property_driver
public :: acc_handle_kind
public :: acc_async_noval, acc_async_sync
public :: openacc_version
public :: acc_get_num_devices, acc_set_device_type, acc_get_device_type
public :: acc_set_device_num, acc_get_device_num, acc_async_test
public :: acc_async_test_all
public :: acc_set_device_num, acc_get_device_num
public :: acc_get_property, acc_get_property_string
public :: acc_async_test, acc_async_test_all
public :: acc_wait, acc_async_wait, acc_wait_async
public :: acc_wait_all, acc_async_wait_all, acc_wait_all_async
public :: acc_init, acc_shutdown, acc_on_device
@ -758,6 +814,14 @@ module openacc
procedure :: acc_get_device_num_h
end interface
interface acc_get_property
procedure :: acc_get_property_h
end interface
interface acc_get_property_string
procedure :: acc_get_property_string_h
end interface
interface acc_async_test
procedure :: acc_async_test_h
end interface
@ -976,6 +1040,63 @@ function acc_get_device_num_h (d)
acc_get_device_num_h = acc_get_device_num_l (d)
end function
function acc_get_property_h (n, d, p)
use iso_c_binding, only: c_int, c_size_t
use openacc_internal, only: acc_get_property_l
use openacc_kinds
implicit none (type, external)
integer (acc_device_property) :: acc_get_property_h
integer, value :: n
integer (acc_device_kind), value :: d
integer (acc_device_property), value :: p
integer (c_int) :: pint
pint = int (p, c_int)
acc_get_property_h = acc_get_property_l (n, d, pint)
end function
subroutine acc_get_property_string_h (n, d, p, s)
use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer, c_associated
use openacc_internal, only: acc_get_property_string_l
use openacc_kinds
implicit none (type, external)
integer, value :: n
integer (acc_device_kind), value :: d
integer (acc_device_property), value :: p
character (*) :: s
integer (c_int) :: pint
type (c_ptr) :: cptr
integer :: clen
character (kind=c_char, len=1), pointer, contiguous :: sptr (:)
integer :: slen
integer :: i
interface
function strlen (s) bind (C, name = "strlen")
use iso_c_binding, only: c_ptr, c_size_t
type (c_ptr), intent(in), value :: s
integer (c_size_t) :: strlen
end function strlen
end interface
pint = int (p, c_int)
cptr = acc_get_property_string_l (n, d, pint)
s = ""
if (.not. c_associated (cptr)) then
return
end if
clen = int (strlen (cptr))
call c_f_pointer (cptr, sptr, [clen])
slen = min (clen, len (s))
do i = 1, slen
s (i:i) = sptr (i)
end do
end subroutine
function acc_async_test_h (a)
use openacc_internal, only: acc_async_test_l
logical acc_async_test_h

View File

@ -49,6 +49,7 @@ extern "C" {
/* Types */
typedef enum acc_device_t {
/* Keep in sync with include/gomp-constants.h. */
acc_device_current = -3,
acc_device_none = 0,
acc_device_default = 1,
acc_device_host = 2,
@ -62,6 +63,16 @@ typedef enum acc_device_t {
_ACC_neg = -1
} acc_device_t;
typedef enum acc_device_property_t {
/* Keep in sync with include/gomp-constants.h. */
/* Start from 1 to catch uninitialized use. */
acc_property_memory = 1,
acc_property_free_memory = 2,
acc_property_name = 0x10001,
acc_property_vendor = 0x10002,
acc_property_driver = 0x10003
} acc_device_property_t;
typedef enum acc_async_t {
/* Keep in sync with include/gomp-constants.h. */
acc_async_noval = -1,
@ -73,6 +84,10 @@ void acc_set_device_type (acc_device_t) __GOACC_NOTHROW;
acc_device_t acc_get_device_type (void) __GOACC_NOTHROW;
void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW;
int acc_get_device_num (acc_device_t) __GOACC_NOTHROW;
size_t acc_get_property
(int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
const char *acc_get_property_string
(int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW;
int acc_async_test (int) __GOACC_NOTHROW;
int acc_async_test_all (void) __GOACC_NOTHROW;
void acc_wait (int) __GOACC_NOTHROW;

View File

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

View File

@ -3236,6 +3236,17 @@ GOMP_OFFLOAD_get_num_devices (void)
return hsa_context.agent_count;
}
union gomp_device_property_value
GOMP_OFFLOAD_get_property (int device, int prop)
{
/* Stub. Check device and return default value for unsupported properties. */
/* TODO: Implement this function. */
get_agent_info (device);
union gomp_device_property_value nullval = { .val = 0 };
return nullval;
}
/* Initialize device (agent) number N so that it can be used for computation.
Return TRUE on success. */

View File

@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void)
return hsa_context.agent_count;
}
/* Part of the libgomp plugin interface. Return the value of property
PROP of agent number N. */
union gomp_device_property_value
GOMP_OFFLOAD_get_property (int n, int prop)
{
union gomp_device_property_value nullval = { .val = 0 };
if (!init_hsa_context ())
return nullval;
if (n >= hsa_context.agent_count)
{
GOMP_PLUGIN_error
("Request for a property of a non-existing HSA device %i", n);
return nullval;
}
switch (prop)
{
case GOMP_DEVICE_PROPERTY_VENDOR:
return (union gomp_device_property_value) { .ptr = "HSA" };
default:
return nullval;
}
}
/* Part of the libgomp plugin interface. Initialize agent number N so that it
can be used for computation. Return TRUE on success. */

View File

@ -189,6 +189,10 @@ cuda_error (CUresult r)
return fallback;
}
/* Version of the CUDA Toolkit in the same MAJOR.MINOR format that is used by
Nvidia, such as in the 'deviceQuery' program (Nvidia's CUDA samples). */
static char cuda_driver_version_s[30];
static unsigned int instantiated_devices = 0;
static pthread_mutex_t ptx_dev_lock = PTHREAD_MUTEX_INITIALIZER;
@ -284,7 +288,7 @@ struct ptx_device
bool map;
bool concur;
bool mkern;
int mode;
int mode;
int clock_khz;
int num_sms;
int regs_per_block;
@ -294,6 +298,9 @@ struct ptx_device
int max_threads_per_multiprocessor;
int default_dims[GOMP_DIM_MAX];
/* Length as used by the CUDA Runtime API ('struct cudaDeviceProp'). */
char name[256];
struct ptx_image_data *images; /* Images loaded on device. */
pthread_mutex_t image_lock; /* Lock for above list. */
@ -327,9 +334,16 @@ nvptx_init (void)
CUDA_CALL (cuInit, 0);
int cuda_driver_version;
CUDA_CALL_ERET (NULL, cuDriverGetVersion, &cuda_driver_version);
snprintf (cuda_driver_version_s, sizeof cuda_driver_version_s,
"CUDA Driver %u.%u",
cuda_driver_version / 1000, cuda_driver_version % 1000 / 10);
CUDA_CALL (cuDeviceGetCount, &ndevs);
ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *)
* ndevs);
return true;
}
@ -491,6 +505,9 @@ nvptx_open_device (int n)
for (int i = 0; i != GOMP_DIM_MAX; i++)
ptx_dev->default_dims[i] = 0;
CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, sizeof ptx_dev->name,
dev);
ptx_dev->images = NULL;
pthread_mutex_init (&ptx_dev->image_lock, NULL);
@ -1104,6 +1121,74 @@ GOMP_OFFLOAD_get_num_devices (void)
return nvptx_get_num_devices ();
}
union gomp_device_property_value
GOMP_OFFLOAD_get_property (int n, int prop)
{
union gomp_device_property_value propval = { .val = 0 };
pthread_mutex_lock (&ptx_dev_lock);
if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL)
{
pthread_mutex_unlock (&ptx_dev_lock);
return propval;
}
struct ptx_device *ptx_dev = ptx_devices[n];
switch (prop)
{
case GOMP_DEVICE_PROPERTY_MEMORY:
{
size_t total_mem;
CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev);
propval.val = total_mem;
}
break;
case GOMP_DEVICE_PROPERTY_FREE_MEMORY:
{
size_t total_mem;
size_t free_mem;
CUdevice ctxdev;
CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev);
if (ptx_dev->dev == ctxdev)
CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
else if (ptx_dev->ctx)
{
CUcontext old_ctx;
CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx);
CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx);
}
else
{
CUcontext new_ctx;
CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO,
ptx_dev->dev);
CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem);
CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx);
}
propval.val = free_mem;
}
break;
case GOMP_DEVICE_PROPERTY_NAME:
propval.ptr = ptx_dev->name;
break;
case GOMP_DEVICE_PROPERTY_VENDOR:
propval.ptr = "Nvidia";
break;
case GOMP_DEVICE_PROPERTY_DRIVER:
propval.ptr = cuda_driver_version_s;
break;
}
pthread_mutex_unlock (&ptx_dev_lock);
return propval;
}
bool
GOMP_OFFLOAD_init_device (int n)
{

View File

@ -3001,6 +3001,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);

View File

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

View File

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

View File

@ -0,0 +1,80 @@
/* Auxiliary functions for acc_get_property tests */
/* { dg-do compile { target skip-all-targets } } */
#include <openacc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void expect_device_properties
(acc_device_t dev_type, int dev_num,
int expected_total_mem, int expected_free_mem,
const char* expected_vendor, const char* expected_name,
const char* expected_driver)
{
const char *vendor = acc_get_property_string (dev_num, dev_type,
acc_property_vendor);
if (strcmp (vendor, expected_vendor))
{
fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", "
"but was \"%s\".\n", expected_vendor, vendor);
abort ();
}
int total_mem = acc_get_property (dev_num, dev_type,
acc_property_memory);
if (total_mem != expected_total_mem)
{
fprintf (stderr, "Expected acc_property_memory to equal %d, "
"but was %d.\n", expected_total_mem, total_mem);
abort ();
}
int free_mem = acc_get_property (dev_num, dev_type,
acc_property_free_memory);
if (free_mem != expected_free_mem)
{
fprintf (stderr, "Expected acc_property_free_memory to equal %d, "
"but was %d.\n", expected_free_mem, free_mem);
abort ();
}
const char *name = acc_get_property_string (dev_num, dev_type,
acc_property_name);
if (strcmp (name, expected_name))
{
fprintf(stderr, "Expected acc_property_name to equal \"%s\", "
"but was \"%s\".\n", expected_name, name);
abort ();
}
const char *driver = acc_get_property_string (dev_num, dev_type,
acc_property_driver);
if (strcmp (expected_driver, driver))
{
fprintf (stderr, "Expected acc_property_driver to equal %s, "
"but was %s.\n", expected_driver, driver);
abort ();
}
int unknown_property = 16058;
int v = acc_get_property (dev_num, dev_type, (acc_device_property_t)unknown_property);
if (v != 0)
{
fprintf (stderr, "Expected value of unknown numeric property to equal 0, "
"but was %d.\n", v);
abort ();
}
int unknown_property2 = -16058;
const char *s = acc_get_property_string (dev_num, dev_type, (acc_device_property_t)unknown_property2);
if (s != NULL)
{
fprintf (stderr, "Expected value of unknown string property to be NULL, "
"but was %d.\n", s);
abort ();
}
}

View File

@ -0,0 +1,76 @@
/* 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);
}

View File

@ -0,0 +1,93 @@
! 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

View File

@ -1,3 +1,11 @@
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.

View File

@ -174,6 +174,27 @@ GOMP_OFFLOAD_get_num_devices (void)
return num_devices;
}
extern "C" union gomp_device_property_value
GOMP_OFFLOAD_get_property (int n, int prop)
{
union gomp_device_property_value nullval = { .val = 0 };
if (n >= num_devices)
{
GOMP_PLUGIN_error
("Request for a property of a non-existing Intel MIC device %i", n);
return nullval;
}
switch (prop)
{
case GOMP_DEVICE_PROPERTY_VENDOR:
return (union gomp_device_property_value) { .ptr = "Intel" };
default:
return nullval;
}
}
static bool
offload (const char *file, uint64_t line, int device, const char *name,
int num_vars, VarDesc *vars, const void **async_data)