From patchwork Thu Nov 14 15:35:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frederik Harwath X-Patchwork-Id: 1194932 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-513425-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="yml1Cbhd"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47DQYs6kZrz9sP4 for ; Fri, 15 Nov 2019 02:36:17 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:in-reply-to:references:mime-version :content-type; q=dns; s=default; b=uRbi4pUf3eOi9Jg/PvqE8pkRmXUXF Krrx8hO+qArXiM/ZKGB8pmtiXCHo60qdYsEJ4ivnfQ/XGoaSnr5TKRRVfIssiNEm wtMmB3YvqUJYR9c/6DX4qZa/pFsjkxfW/mC3mvoclf6i0sY0xkaak13VYWgggrV6 PchUwzND1QsEA4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:in-reply-to:references:mime-version :content-type; s=default; bh=SwNEPe/AErV2PUiRoNG5O1Fv0Zg=; b=yml 1Cbhdc3mhbwKe5INx36ls0n/UDR7hO+CMtMHNcBBC/I4BgceQigDyXemesxklU8y xcmxFXeoxpM5l0U1Pson2IMa53v9mwv8r9aBF6YPN+KhZbnFpNUVTqBPSd3RT5JV 4JIaQx9ice+mbOM3gTTtH++OL9zPqSIyCBCq3q9c= Received: (qmail 119804 invoked by alias); 14 Nov 2019 15:36:07 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 119795 invoked by uid 89); 14 Nov 2019 15:36:06 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-18.4 required=5.0 tests=AWL, BAYES_20, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=Images, UD:libgomp-plugin.h, libgomph, UD:libgomp.h X-HELO: esa4.mentor.iphmx.com Received: from esa4.mentor.iphmx.com (HELO esa4.mentor.iphmx.com) (68.232.137.252) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 14 Nov 2019 15:36:00 +0000 IronPort-SDR: gLzTWRq2kQYlVKuexDhcAjHd66pF4o1UcwO+nHfaLh8NPpO5Muanr6+X4y8zWnygAZwUKzaIbY 5KpduR53StdwJ1/8YjrR2idm1BE9zgkqxQft393TWOundTSdopgAeVRk6HlfFl5XCHGuE/HI2V 5NsjTKclY6JsA+bcjk+wE115REoCkspmw83S8v/YV36BXq4s++q+miz+air2Sxv9dxyD8LkDHn eQnj9ZyuHERJEEDBsUTvHyXdiIUxERInVU6wXkT5BhyMNCMG/G4XMmlCHzPaXed662k0g74eWe T8c= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa4.mentor.iphmx.com with ESMTP; 14 Nov 2019 07:35:56 -0800 IronPort-SDR: YsKu1WLqi+kpFa1Sk/kO/sKI5yHFEvt3WUN6Lx4AU7yHLEzPkQREeK1B9RDY2r+g+MtWyz+0wg 8yufc3nTAhntVgm6XMeAXP4rD/S8PnJi/yoCfMlyCaR5GOnuuqZEUgtWNfwYVJwdD/UCGtn1j2 u9q9sez86+wORC5JwrEkkyjtSW4DDjcJNkTePGN/uz68g56F+64w8WRX4XZOnMLpXnDcdW7ke/ jVtrKGmGcIfkaMHMCAHzfgBAvX9chrn/9Kbp2Nufix8kt7FD3qBT9gkmlerLQHAbqlsFoolX5W cIE= From: Frederik Harwath To: , , , , Subject: [PATCH] Add OpenACC 2.6 `acc_get_property' support Date: Thu, 14 Nov 2019 16:35:31 +0100 Message-ID: <20191114153531.7493-1-frederik@codesourcery.com> In-Reply-To: <87imp01jr3.fsf@euler.schwinge.homeip.net> References: <87imp01jr3.fsf@euler.schwinge.homeip.net> MIME-Version: 1.0 X-IsSubscribed: yes Hi, this patch implements OpenACC 2.6 "acc_get_property" and related functions. I have tested the patch on x86_64-linux-gnu with nvptx-none offloading. There is no AMD GCN support yet. This will be added later on. Can this be committed to trunk? Best regards, Frederik ----------------------- 8< ------------------------------------------- Add generic support for the OpenACC 2.6 `acc_get_property' and `acc_get_property_string' routines, as well as full handlers for the host and the NVPTX offload targets and minimal handlers for the HSA and Intel MIC offload targets. Included are C/C++ and Fortran tests that, in particular, print the property values for acc_property_vendor, acc_property_memory, acc_property_free_memory, acc_property_name, and acc_property_driver. The output looks as follows: Vendor: GNU Name: GOMP Total memory: 0 Free memory: 0 Driver: 1.0 with the host driver (where the memory related properties are not supported for the host device and yield 0, conforming to the standard) and output like: OpenACC vendor: Nvidia OpenACC total memory: 12651462656 OpenACC free memory: 12202737664 OpenACC name: TITAN V OpenACC driver: CUDA Driver 9.1 with the NVPTX driver. 2019-11-14 Maciej W. Rozycki Frederik Harwath Thomas Schwinge include/ * gomp-constants.h (GOMP_DEVICE_CURRENT, GOMP_DEVICE_PROPERTY_MEMORY, GOMP_DEVICE_PROPERTY_FREE_MEMORY, GOMP_DEVICE_PROPERTY_NAME, GOMP_DEVICE_PROPERTY_VENDOR, GOMP_DEVICE_PROPERTY_DRIVER, GOMP_DEVICE_PROPERTY_STRING_MASK): New Macros. libgomp/ * libgomp.h (gomp_device_descr): Add `get_property_func' member. * libgomp-plugin.h (gomp_device_property_value): New union. (gomp_device_property_value): New prototype. * openacc.h (acc_device_t): Add `acc_device_current' enumeration constant. (acc_device_property_t): New enum. (acc_get_property, acc_get_property_string): New prototypes. * oacc-init.c (acc_get_device_type): Also assert on `!acc_device_current' result. (get_property_any, acc_get_property, acc_get_property_string): New functions. * openacc.f90 (openacc_kinds): From `iso_fortran_env' also import `int64'. Add `acc_device_current' and `acc_property_memory', `acc_property_free_memory', `acc_property_name', `acc_property_vendor' and `acc_property_driver' constants. Add `acc_device_property' data type. (openacc_internal): Add `acc_get_property' and `acc_get_property_string' interfaces. Add `acc_get_property_h', `acc_get_property_string_h', `acc_get_property_l' and `acc_get_property_string_l'. (openacc_c_string): New module. * oacc-host.c (host_get_property): New function. (host_dispatch): Wire it. * target.c (gomp_load_plugin_for_device): Handle `get_property'. * libgomp.map (OACC_2.6): Add `acc_get_property', `acc_get_property_h_', `acc_get_property_string' and `acc_get_property_string_h_' symbols. * oacc-init.c (acc_known_device_type): Add function. (unknown_device_type_error): Add function. (name_of_acc_device_t): Change to call unknown_device_type_error on unknown type. (resolve_device): Use acc_known_device_type. (acc_init): Fail if acc_device_t argument is not valid. (acc_shutdown): Likewise. (acc_get_num_devices): Likewise. (acc_set_device_type): Likewise. (acc_get_device_num): Likewise. (acc_set_device_num): Likewise. (get_property_any): Likewise. (acc_get_property): Likewise. (acc_get_property_string): Likewise. (acc_on_device): Likewise. (goacc_save_and_set_bind): Likewise. * libgomp.texi (OpenACC Runtime Library Routines): Add `acc_get_property'. (acc_get_property): New node. * plugin/plugin-hsa.c (GOMP_OFFLOAD_get_property): New function. * plugin/plugin-nvptx.c (CUDA_CALLS): Add `cuDeviceGetName', `cuDeviceTotalMem', `cuDriverGetVersion' and `cuMemGetInfo' calls. (GOMP_OFFLOAD_get_property): New function. (struct ptx_device): Add new field "name" ... (nvptx_open_device): ... and alloc and init from here. (nvptx_close_device): ... and free from here. (cuda_driver_version): Add new static variable ... (nvptx_init): ... and init from here. * testsuite/libgomp.oacc-c-c++-common/acc-get-property.c: New test. * testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c: New test. * testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c: New test. * testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c: New file with test helper functions. * testsuite/libgomp.oacc-fortran/acc-get-property.f90: New test. liboffloadmic/ * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_get_property): New function. --- include/gomp-constants.h | 14 ++ libgomp/libgomp-plugin.h | 8 + libgomp/libgomp.h | 1 + libgomp/libgomp.map | 8 + libgomp/libgomp.texi | 39 +++++ libgomp/oacc-host.c | 22 +++ libgomp/oacc-init.c | 139 ++++++++++++++++-- libgomp/openacc.f90 | 116 ++++++++++++++- libgomp/openacc.h | 17 ++- libgomp/plugin/cuda-lib.def | 4 + libgomp/plugin/plugin-hsa.c | 26 ++++ libgomp/plugin/plugin-nvptx.c | 85 ++++++++++- libgomp/target.c | 1 + .../acc-get-property-2.c | 68 +++++++++ .../acc-get-property-3.c | 19 +++ .../acc-get-property-aux.c | 60 ++++++++ .../acc-get-property.c | 75 ++++++++++ .../libgomp.oacc-fortran/acc-get-property.f90 | 80 ++++++++++ .../plugin/libgomp-plugin-intelmic.cpp | 22 +++ 19 files changed, 790 insertions(+), 14 deletions(-) create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90 diff --git a/include/gomp-constants.h b/include/gomp-constants.h index 9e356cdfeec9..150b12d0d6fd 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -178,6 +178,20 @@ enum gomp_map_kind #define GOMP_DEVICE_ICV -1 #define GOMP_DEVICE_HOST_FALLBACK -2 +#define GOMP_DEVICE_CURRENT -3 + +/* Device property codes. Keep in sync with + libgomp/{openacc.h,openacc.f90,openacc_lib.h}:acc_device_property_t + as well as libgomp/libgomp-plugin.h. */ +/* Start from 1 to catch uninitialized use. */ +#define GOMP_DEVICE_PROPERTY_MEMORY 1 +#define GOMP_DEVICE_PROPERTY_FREE_MEMORY 2 +#define GOMP_DEVICE_PROPERTY_NAME 0x10001 +#define GOMP_DEVICE_PROPERTY_VENDOR 0x10002 +#define GOMP_DEVICE_PROPERTY_DRIVER 0x10003 + +/* Internal property mask to tell numeric and string values apart. */ +#define GOMP_DEVICE_PROPERTY_STRING_MASK 0x10000 /* GOMP_task/GOMP_taskloop* flags argument. */ #define GOMP_TASK_FLAG_UNTIED (1 << 0) diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h index 037558c43f56..5f968855f652 100644 --- a/libgomp/libgomp-plugin.h +++ b/libgomp/libgomp-plugin.h @@ -54,6 +54,13 @@ enum offload_target_type OFFLOAD_TARGET_TYPE_GCN = 8 }; +/* Container type for passing device properties. */ +union gomp_device_property_value +{ + void *ptr; + uintmax_t val; +}; + /* Opaque type to represent plugin-dependent implementation of an OpenACC asynchronous queue. */ struct goacc_asyncqueue; @@ -94,6 +101,7 @@ extern const char *GOMP_OFFLOAD_get_name (void); extern unsigned int GOMP_OFFLOAD_get_caps (void); extern int GOMP_OFFLOAD_get_type (void); extern int GOMP_OFFLOAD_get_num_devices (void); +extern union gomp_device_property_value GOMP_OFFLOAD_get_property (int, int); extern bool GOMP_OFFLOAD_init_device (int); extern bool GOMP_OFFLOAD_fini_device (int); extern unsigned GOMP_OFFLOAD_version (void); diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index bab733d2b2da..c3f89a26532c 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -1106,6 +1106,7 @@ struct gomp_device_descr __typeof (GOMP_OFFLOAD_get_caps) *get_caps_func; __typeof (GOMP_OFFLOAD_get_type) *get_type_func; __typeof (GOMP_OFFLOAD_get_num_devices) *get_num_devices_func; + __typeof (GOMP_OFFLOAD_get_property) *get_property_func; __typeof (GOMP_OFFLOAD_init_device) *init_device_func; __typeof (GOMP_OFFLOAD_fini_device) *fini_device_func; __typeof (GOMP_OFFLOAD_version) *version_func; diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index c79430f8d8d1..fba4effbb3eb 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -502,6 +502,14 @@ GOACC_2.0.1 { GOACC_parallel_keyed; } GOACC_2.0; +OACC_2.6 { + global: + acc_get_property; + acc_get_property_h_; + acc_get_property_string; + acc_get_property_string_h_; +} OACC_2.5; + GOMP_PLUGIN_1.0 { global: GOMP_PLUGIN_malloc; diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 6db895f62726..91afca4589d9 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -1849,6 +1849,7 @@ acceleration device. * acc_get_device_type:: Get type of device accelerator to be used. * acc_set_device_num:: Set device number to use. * acc_get_device_num:: Get device number to be used. +* acc_get_property:: Get device property. * acc_async_test:: Tests for completion of a specific asynchronous operation. * acc_async_test_all:: Tests for completion of all asychronous @@ -2038,6 +2039,44 @@ region. +@node acc_get_property +@section @code{acc_get_property} -- Get device property. +@cindex acc_get_property +@cindex acc_get_property_string +@table @asis +@item @emph{Description} +These routines return the value of the specified @var{property} for the +device being queried according to @var{devicenum} and @var{devicetype}. +Integer-valued and string-valued properties are returned by +@code{acc_get_property} and @code{acc_get_property_string} respectively. +The Fortran @code{acc_get_property_string} subroutine returns the string +retrieved in its fourth argument while the remaining entry points are +functions, which pass the return value as their result. + +@item @emph{C/C++}: +@multitable @columnfractions .20 .80 +@item @emph{Prototype}: @tab @code{size_t acc_get_property(int devicenum, acc_device_t devicetype, acc_device_property_t property);} +@item @emph{Prototype}: @tab @code{const char *acc_get_property_string(int devicenum, acc_device_t devicetype, acc_device_property_t property);} +@end multitable + +@item @emph{Fortran}: +@multitable @columnfractions .20 .80 +@item @emph{Interface}: @tab @code{function acc_get_property(devicenum, devicetype, property)} +@item @emph{Interface}: @tab @code{subroutine acc_get_property_string(devicenum, devicetype, property, string)} +@item @tab @code{integer devicenum} +@item @tab @code{integer(kind=acc_device_kind) devicetype} +@item @tab @code{integer(kind=acc_device_property) property} +@item @tab @code{integer(kind=acc_device_property) acc_get_property} +@item @tab @code{character(*) string} +@end multitable + +@item @emph{Reference}: +@uref{https://www.openacc.org, OpenACC specification v2.6}, section +3.2.6. +@end table + + + @node acc_async_test @section @code{acc_async_test} -- Test for completion of a specific asynchronous operation. @table @asis diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c index cbcac9bf7b33..70005c3656db 100644 --- a/libgomp/oacc-host.c +++ b/libgomp/oacc-host.c @@ -59,6 +59,27 @@ host_get_num_devices (void) return 1; } +static union gomp_device_property_value +host_get_property (int n, int prop) +{ + union gomp_device_property_value nullval = { .val = 0 }; + + if (n >= host_get_num_devices ()) + return nullval; + + switch (prop) + { + case GOMP_DEVICE_PROPERTY_NAME: + return (union gomp_device_property_value) { .ptr = "GOMP" }; + case GOMP_DEVICE_PROPERTY_VENDOR: + return (union gomp_device_property_value) { .ptr = "GNU" }; + case GOMP_DEVICE_PROPERTY_DRIVER: + return (union gomp_device_property_value) { .ptr = VERSION }; + default: + return nullval; + } +} + static bool host_init_device (int n __attribute__ ((unused))) { @@ -248,6 +269,7 @@ static struct gomp_device_descr host_dispatch = .get_caps_func = host_get_caps, .get_type_func = host_get_type, .get_num_devices_func = host_get_num_devices, + .get_property_func = host_get_property, .init_device_func = host_init_device, .fini_device_func = host_fini_device, .version_func = host_version, diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c index e1568c535b32..5d8523cf3259 100644 --- a/libgomp/oacc-init.c +++ b/libgomp/oacc-init.c @@ -93,6 +93,21 @@ get_openacc_name (const char *name) return name; } + +static int +acc_known_device_type (acc_device_t __arg) +{ + return __arg >= 0 && __arg < _ACC_device_hwm; +} + + +static void +unknown_device_type_error (unsigned invalid_type) +{ + gomp_fatal ("unknown device type %u", invalid_type); +} + + static const char * name_of_acc_device_t (enum acc_device_t type) { @@ -103,8 +118,9 @@ name_of_acc_device_t (enum acc_device_t type) case acc_device_host: return "host"; case acc_device_not_host: return "not_host"; case acc_device_nvidia: return "nvidia"; - default: gomp_fatal ("unknown device type %u", (unsigned) type); + default: unknown_device_type_error(type); } + return 0; /** Never reached **/ } /* ACC_DEVICE_LOCK must be held before calling this function. If FAIL_IS_ERROR @@ -123,7 +139,7 @@ resolve_device (acc_device_t d, bool fail_is_error) if (goacc_device_type) { /* Lookup the named device. */ - while (++d != _ACC_device_hwm) + while (acc_known_device_type (++d)) if (dispatchers[d] && !strcasecmp (goacc_device_type, get_openacc_name (dispatchers[d]->name)) @@ -147,7 +163,7 @@ resolve_device (acc_device_t d, bool fail_is_error) case acc_device_not_host: /* Find the first available device after acc_device_not_host. */ - while (++d != _ACC_device_hwm) + while (acc_known_device_type (++d)) if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0) goto found; if (d_arg == acc_device_default) @@ -168,7 +184,7 @@ resolve_device (acc_device_t d, bool fail_is_error) break; default: - if (d > _ACC_device_hwm) + if (!acc_known_device_type (d)) { if (fail_is_error) goto unsupported_device; @@ -328,7 +344,6 @@ acc_shutdown_1 (acc_device_t d) gomp_unload_device (acc_dev); gomp_mutex_unlock (&acc_dev->lock); } - gomp_mutex_lock (&goacc_thread_lock); /* Free target-specific TLS data and close all devices. */ @@ -494,7 +509,6 @@ goacc_attach_host_thread_to_device (int ord) thr->api_info = NULL; /* Initially, all callbacks for all events are enabled. */ thr->prof_callbacks_enabled = true; - thr->target_tls = acc_dev->openacc.create_thread_data_func (ord); } @@ -505,12 +519,15 @@ goacc_attach_host_thread_to_device (int ord) void acc_init (acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + gomp_init_targets_once (); gomp_mutex_lock (&acc_device_lock); cached_base_dev = acc_init_1 (d, acc_construct_runtime_api, 0); gomp_mutex_unlock (&acc_device_lock); - + goacc_attach_host_thread_to_device (-1); } @@ -519,6 +536,9 @@ ialias (acc_init) void acc_shutdown (acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + gomp_init_targets_once (); gomp_mutex_lock (&acc_device_lock); @@ -533,6 +553,9 @@ ialias (acc_shutdown) int acc_get_num_devices (acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + int n = 0; struct gomp_device_descr *acc_dev; @@ -564,6 +587,9 @@ ialias (acc_get_num_devices) void acc_set_device_type (acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + struct gomp_device_descr *base_dev, *acc_dev; struct goacc_thread *thr = goacc_thread (); @@ -637,7 +663,8 @@ acc_get_device_type (void) } assert (res != acc_device_default - && res != acc_device_not_host); + && res != acc_device_not_host + && res != acc_device_current); return res; } @@ -647,12 +674,12 @@ ialias (acc_get_device_type) int acc_get_device_num (acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + const struct gomp_device_descr *dev; struct goacc_thread *thr = goacc_thread (); - if (d >= _ACC_device_hwm) - gomp_fatal ("unknown device type %u", (unsigned) d); - acc_prof_info prof_info; acc_api_info api_info; bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info); @@ -682,6 +709,9 @@ ialias (acc_get_device_num) void acc_set_device_num (int ord, acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + struct gomp_device_descr *base_dev, *acc_dev; int num_devices; @@ -723,6 +753,87 @@ acc_set_device_num (int ord, acc_device_t d) ialias (acc_set_device_num) +static union gomp_device_property_value +get_property_any (int ord, acc_device_t d, acc_device_property_t prop) +{ + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + + union gomp_device_property_value propval; + struct gomp_device_descr *dev; + struct goacc_thread *thr; + + if (d == acc_device_none) + return (union gomp_device_property_value) { .val = 0 }; + + goacc_lazy_initialize (); + thr = goacc_thread (); + + if (d == acc_device_current && (!thr || !thr->dev)) + return (union gomp_device_property_value) { .val = 0 }; + + if (d == acc_device_current) + { + dev = thr->dev; + } + else + { + int num_devices; + + gomp_mutex_lock (&acc_device_lock); + + dev = resolve_device (d, false); + + num_devices = dev->get_num_devices_func (); + + if (num_devices <= 0 || ord >= num_devices) + acc_dev_num_out_of_range (d, ord, num_devices); + + dev += ord; + + gomp_mutex_lock (&dev->lock); + if (dev->state == GOMP_DEVICE_UNINITIALIZED) + gomp_init_device (dev); + gomp_mutex_unlock (&dev->lock); + + gomp_mutex_unlock (&acc_device_lock); + } + + assert (dev); + + propval = dev->get_property_func (dev->target_id, prop); + + return propval; +} + +size_t +acc_get_property (int ord, acc_device_t d, acc_device_property_t prop) +{ + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + + if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK) + return 0; + else + return get_property_any (ord, d, prop).val; +} + +ialias (acc_get_property) + +const char * +acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop) +{ + if (!acc_known_device_type (d)) + unknown_device_type_error(d); + + if (prop & GOMP_DEVICE_PROPERTY_STRING_MASK) + return get_property_any (ord, d, prop).ptr; + else + return NULL; +} + +ialias (acc_get_property_string) + /* For -O and higher, the compiler always attempts to expand acc_on_device, but if the user disables the builtin, or calls it via a pointer, we'll need this version. @@ -733,6 +844,9 @@ ialias (acc_set_device_num) int __attribute__ ((__optimize__ ("O2"))) acc_on_device (acc_device_t dev) { + if (!acc_known_device_type (dev)) + unknown_device_type_error(dev); + return __builtin_acc_on_device (dev); } @@ -763,6 +877,9 @@ goacc_runtime_initialize (void) attribute_hidden void goacc_save_and_set_bind (acc_device_t d) { + if (!acc_known_device_type (d)) + unknown_device_type_error (d); + struct goacc_thread *thr = goacc_thread (); assert (!thr->saved_bound_dev); diff --git a/libgomp/openacc.f90 b/libgomp/openacc.f90 index 831a157e703d..f574c7e31a8c 100644 --- a/libgomp/openacc.f90 +++ b/libgomp/openacc.f90 @@ -28,7 +28,7 @@ ! . module openacc_kinds - use iso_fortran_env, only: int32 + use iso_fortran_env, only: int32, int64 implicit none private :: int32 @@ -47,6 +47,21 @@ module openacc_kinds integer (acc_device_kind), parameter :: acc_device_not_host = 4 integer (acc_device_kind), parameter :: acc_device_nvidia = 5 integer (acc_device_kind), parameter :: acc_device_gcn = 8 + integer (acc_device_kind), parameter :: acc_device_current = -3 + + public :: acc_device_property + + integer, parameter :: acc_device_property = int64 + + public :: acc_property_memory, acc_property_free_memory + public :: acc_property_name, acc_property_vendor, acc_property_driver + + ! Keep in sync with include/gomp-constants.h. + integer (acc_device_property), parameter :: acc_property_memory = 1 + integer (acc_device_property), parameter :: acc_property_free_memory = 2 + integer (acc_device_property), parameter :: acc_property_name = int(Z'10001') + integer (acc_device_property), parameter :: acc_property_vendor = int(Z'10002') + integer (acc_device_property), parameter :: acc_property_driver = int(Z'10003') public :: acc_handle_kind @@ -87,6 +102,24 @@ module openacc_internal integer (acc_device_kind) d end subroutine + function acc_get_property_h (n, d, p) + import + implicit none (type, external) + integer (acc_device_property) :: acc_get_property_h + integer, value :: n + integer (acc_device_kind), value :: d + integer (acc_device_property), value :: p + end function + + subroutine acc_get_property_string_h (n, d, p, s) + import + implicit none (type, external) + integer, value :: n + integer (acc_device_kind), value :: d + integer (acc_device_property), value :: p + character (*) :: s + end subroutine + function acc_get_device_num_h (d) import integer acc_get_device_num_h @@ -512,6 +545,26 @@ module openacc_internal integer (c_int), value :: d end function + function acc_get_property_l (n, d, p) & + bind (C, name = "acc_get_property") + use iso_c_binding, only: c_int, c_size_t + implicit none (type, external) + integer (c_size_t) :: acc_get_property_l + integer (c_int), value :: n + integer (c_int), value :: d + integer (c_int), value :: p + end function + + function acc_get_property_string_l (n, d, p) & + bind (C, name = "acc_get_property_string") + use iso_c_binding, only: c_int, c_ptr + implicit none (type, external) + type (c_ptr) :: acc_get_property_string_l + integer (c_int), value :: n + integer (c_int), value :: d + integer (c_int), value :: p + end function + function acc_async_test_l (a) & bind (C, name = "acc_async_test") use iso_c_binding, only: c_int @@ -753,6 +806,14 @@ module openacc procedure :: acc_get_device_num_h end interface + interface acc_get_property + procedure :: acc_get_property_h + end interface + + interface acc_get_property_string + procedure :: acc_get_property_string_h + end interface + interface acc_async_test procedure :: acc_async_test_h end interface @@ -971,6 +1032,59 @@ function acc_get_device_num_h (d) acc_get_device_num_h = acc_get_device_num_l (d) end function +function acc_get_property_h (n, d, p) + use iso_c_binding, only: c_int + use openacc_internal, only: acc_get_property_l + use openacc_kinds + implicit none (type, external) + integer (acc_device_property) :: acc_get_property_h + integer, value :: n + integer (acc_device_kind), value :: d + integer (acc_device_property), value :: p + + integer (c_int) :: pint + + pint = int (p, c_int) + acc_get_property_h = acc_get_property_l (n, d, pint) +end function + +subroutine acc_get_property_string_h (n, d, p, s) + use iso_c_binding, only: c_char, c_int, c_ptr, c_f_pointer + use openacc_internal, only: acc_get_property_string_l + use openacc_kinds + implicit none (type, external) + integer, value :: n + integer (acc_device_kind), value :: d + integer (acc_device_property), value :: p + character (*) :: s + + integer (c_int) :: pint + type (c_ptr) :: cptr + integer :: clen + character (kind=c_char, len=1), pointer, contiguous :: sptr (:) + integer :: slen + integer :: i + + interface + function strlen (s) bind (C, name = "strlen") + use iso_c_binding, only: c_ptr, c_size_t + type (c_ptr), intent(in), value :: s + integer (c_size_t) :: strlen + end function strlen + end interface + + pint = int (p, c_int) + cptr = acc_get_property_string_l (n, d, pint) + clen = int (strlen (cptr)) + call c_f_pointer (cptr, sptr, [clen]) + + s = "" + slen = min (clen, len (s)) + do i = 1, slen + s (i:i) = sptr (i) + end do +end subroutine + function acc_async_test_h (a) use openacc_internal, only: acc_async_test_l logical acc_async_test_h diff --git a/libgomp/openacc.h b/libgomp/openacc.h index 42c861caabf7..49340b7fb6d4 100644 --- a/libgomp/openacc.h +++ b/libgomp/openacc.h @@ -59,9 +59,20 @@ typedef enum acc_device_t { _ACC_device_hwm, /* Ensure enumeration is layout compatible with int. */ _ACC_highest = __INT_MAX__, - _ACC_neg = -1 + _ACC_neg = -1, + acc_device_current = -3 } acc_device_t; +typedef enum acc_device_property_t { + /* Keep in sync with include/gomp-constants.h. */ + /* Start from 1 to catch uninitialized use. */ + acc_property_memory = 1, + acc_property_free_memory = 2, + acc_property_name = 0x10001, + acc_property_vendor = 0x10002, + acc_property_driver = 0x10003 +} acc_device_property_t; + typedef enum acc_async_t { /* Keep in sync with include/gomp-constants.h. */ acc_async_noval = -1, @@ -73,6 +84,10 @@ void acc_set_device_type (acc_device_t) __GOACC_NOTHROW; acc_device_t acc_get_device_type (void) __GOACC_NOTHROW; void acc_set_device_num (int, acc_device_t) __GOACC_NOTHROW; int acc_get_device_num (acc_device_t) __GOACC_NOTHROW; +size_t acc_get_property + (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW; +const char *acc_get_property_string + (int, acc_device_t, acc_device_property_t) __GOACC_NOTHROW; int acc_async_test (int) __GOACC_NOTHROW; int acc_async_test_all (void) __GOACC_NOTHROW; void acc_wait (int) __GOACC_NOTHROW; diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def index a16badcfa9de..cd91b39b1d27 100644 --- a/libgomp/plugin/cuda-lib.def +++ b/libgomp/plugin/cuda-lib.def @@ -8,6 +8,9 @@ CUDA_ONE_CALL (cuCtxSynchronize) CUDA_ONE_CALL (cuDeviceGet) CUDA_ONE_CALL (cuDeviceGetAttribute) CUDA_ONE_CALL (cuDeviceGetCount) +CUDA_ONE_CALL (cuDeviceGetName) +CUDA_ONE_CALL (cuDeviceTotalMem) +CUDA_ONE_CALL (cuDriverGetVersion) CUDA_ONE_CALL (cuEventCreate) CUDA_ONE_CALL (cuEventDestroy) CUDA_ONE_CALL (cuEventElapsedTime) @@ -35,6 +38,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync) CUDA_ONE_CALL (cuMemFree) CUDA_ONE_CALL (cuMemFreeHost) CUDA_ONE_CALL (cuMemGetAddressRange) +CUDA_ONE_CALL (cuMemGetInfo) CUDA_ONE_CALL (cuMemHostGetDevicePointer) CUDA_ONE_CALL (cuModuleGetFunction) CUDA_ONE_CALL (cuModuleGetGlobal) diff --git a/libgomp/plugin/plugin-hsa.c b/libgomp/plugin/plugin-hsa.c index 409e138aaca3..491ea5769b90 100644 --- a/libgomp/plugin/plugin-hsa.c +++ b/libgomp/plugin/plugin-hsa.c @@ -699,6 +699,32 @@ GOMP_OFFLOAD_get_num_devices (void) return hsa_context.agent_count; } +/* Part of the libgomp plugin interface. Return the value of property + PROP of agent number N. */ + +union gomp_device_property_value +GOMP_OFFLOAD_get_property (int n, int prop) +{ + union gomp_device_property_value nullval = { .val = 0 }; + + if (!init_hsa_context ()) + return nullval; + if (n >= hsa_context.agent_count) + { + GOMP_PLUGIN_error + ("Request for a property of a non-existing HSA device %i", n); + return nullval; + } + + switch (prop) + { + case GOMP_DEVICE_PROPERTY_VENDOR: + return (union gomp_device_property_value) { .ptr = "AMD" }; + default: + return nullval; + } +} + /* Part of the libgomp plugin interface. Initialize agent number N so that it can be used for computation. Return TRUE on success. */ diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c index 911d0f66a6e4..0e9f9ff69ba8 100644 --- a/libgomp/plugin/plugin-nvptx.c +++ b/libgomp/plugin/plugin-nvptx.c @@ -284,7 +284,7 @@ struct ptx_device bool map; bool concur; bool mkern; - int mode; + int mode; int clock_khz; int num_sms; int regs_per_block; @@ -293,6 +293,7 @@ struct ptx_device int max_threads_per_block; int max_threads_per_multiprocessor; int default_dims[GOMP_DIM_MAX]; + char* name; struct ptx_image_data *images; /* Images loaded on device. */ pthread_mutex_t image_lock; /* Lock for above list. */ @@ -304,6 +305,7 @@ struct ptx_device }; static struct ptx_device **ptx_devices; +static char cuda_driver_version[30]; static inline struct nvptx_thread * nvptx_thread (void) @@ -330,6 +332,12 @@ nvptx_init (void) CUDA_CALL (cuDeviceGetCount, &ndevs); ptx_devices = GOMP_PLUGIN_malloc_cleared (sizeof (struct ptx_device *) * ndevs); + + int v; + CUDA_CALL_ERET (NULL, cuDriverGetVersion, &v); + snprintf (cuda_driver_version, sizeof (cuda_driver_version) - 1, + "CUDA Driver %u.%u", v / 1000, v % 1000 / 10); + return true; } @@ -491,6 +499,10 @@ nvptx_open_device (int n) for (int i = 0; i != GOMP_DIM_MAX; i++) ptx_dev->default_dims[i] = 0; + const int max_name_len = 256; + ptx_dev->name = GOMP_PLUGIN_malloc(max_name_len); + CUDA_CALL_ERET (NULL, cuDeviceGetName, ptx_dev->name, max_name_len, dev); + ptx_dev->images = NULL; pthread_mutex_init (&ptx_dev->image_lock, NULL); @@ -520,6 +532,7 @@ nvptx_close_device (struct ptx_device *ptx_dev) if (!ptx_dev->ctx_shared) CUDA_CALL (cuCtxDestroy, ptx_dev->ctx); + free (ptx_dev->name); free (ptx_dev); return true; } @@ -1104,6 +1117,76 @@ GOMP_OFFLOAD_get_num_devices (void) return nvptx_get_num_devices (); } +union gomp_device_property_value +GOMP_OFFLOAD_get_property (int n, int prop) +{ + union gomp_device_property_value propval = { .val = 0 }; + + pthread_mutex_lock (&ptx_dev_lock); + + if (n >= nvptx_get_num_devices () || n < 0 || ptx_devices[n] == NULL) + { + pthread_mutex_unlock (&ptx_dev_lock); + return propval; + } + + struct ptx_device *ptx_dev = ptx_devices[n]; + switch (prop) + { + case GOMP_DEVICE_PROPERTY_MEMORY: + { + size_t total_mem; + + CUDA_CALL_ERET (propval, cuDeviceTotalMem, &total_mem, ptx_dev->dev); + propval.val = total_mem; + } + break; + case GOMP_DEVICE_PROPERTY_FREE_MEMORY: + { + size_t total_mem; + size_t free_mem; + CUdevice ctxdev; + + CUDA_CALL_ERET (propval, cuCtxGetDevice, &ctxdev); + if (ptx_dev->dev == ctxdev) + CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem); + else if (ptx_dev->ctx) + { + CUcontext old_ctx; + + CUDA_CALL_ERET (propval, cuCtxPushCurrent, ptx_dev->ctx); + CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem); + CUDA_CALL_ASSERT (cuCtxPopCurrent, &old_ctx); + } + else + { + CUcontext new_ctx; + + CUDA_CALL_ERET (propval, cuCtxCreate, &new_ctx, CU_CTX_SCHED_AUTO, + ptx_dev->dev); + CUDA_CALL_ERET (propval, cuMemGetInfo, &free_mem, &total_mem); + CUDA_CALL_ASSERT (cuCtxDestroy, new_ctx); + } + propval.val = free_mem; + } + break; + case GOMP_DEVICE_PROPERTY_NAME: + propval.ptr = ptx_dev->name; + break; + case GOMP_DEVICE_PROPERTY_VENDOR: + propval.ptr = "Nvidia"; + break; + case GOMP_DEVICE_PROPERTY_DRIVER: + propval.ptr = cuda_driver_version; + break; + default: + GOMP_PLUGIN_error("Unknown OpenACC device-property"); + } + + pthread_mutex_unlock (&ptx_dev_lock); + return propval; +} + bool GOMP_OFFLOAD_init_device (int n) { diff --git a/libgomp/target.c b/libgomp/target.c index 84d6daa76ca8..ffd689a9afe7 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -2752,6 +2752,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, DLSYM (get_caps); DLSYM (get_type); DLSYM (get_num_devices); + DLSYM (get_property); DLSYM (init_device); DLSYM (fini_device); DLSYM (load_image); diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c new file mode 100644 index 000000000000..b97eef7777ee --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-2.c @@ -0,0 +1,68 @@ +/* Test the `acc_get_property' and '`acc_get_property_string' library + functions on Nvidia devices by comparing property values with + those obtained through the CUDA API. */ +/* { dg-additional-sources acc-get-property-aux.c } */ +/* { dg-additional-options "-lcuda -lcudart" } */ +/* { dg-do run { target openacc_nvidia_accel_selected } } */ + +#include +#include +#include +#include +#include + +void expect_device_properties +(acc_device_t dev_type, int dev_num, + int expected_total_mem, int expected_free_mem, + const char* expected_vendor, const char* expected_name, + const char* expected_driver); + +int main () +{ + int dev_count; + cudaGetDeviceCount (&dev_count); + + for (int dev_num = 0; dev_num < dev_count; ++dev_num) + { + if (cudaSetDevice (dev_num) != cudaSuccess) + { + fprintf (stderr, "cudaSetDevice failed.\n"); + abort (); + } + + printf("Checking device %d\n", dev_num); + + const char *vendor = "Nvidia"; + size_t free_mem; + size_t total_mem; + if (cudaMemGetInfo(&free_mem, &total_mem) != cudaSuccess) + { + fprintf (stderr, "cudaMemGetInfo failed.\n"); + abort (); + } + + struct cudaDeviceProp p; + if (cudaGetDeviceProperties(&p, dev_num) != cudaSuccess) + { + fprintf (stderr, "cudaGetDeviceProperties failed.\n"); + abort (); + } + + int driver_version; + if (cudaDriverGetVersion(&driver_version) != cudaSuccess) + { + fprintf (stderr, "cudaDriverGetVersion failed.\n"); + abort (); + } + /* The version string should contain the version of the CUDA Toolkit + in the same MAJOR.MINOR format that is used by Nvidia. + The format string below is the same that is used by the deviceQuery + program, which belongs to Nvidia's CUDA samples, to print the version. */ + char *driver = malloc(sizeof(char) * 40); + snprintf (driver, 40, "CUDA Driver %u.%u", driver_version / 1000, + driver_version % 1000 / 10); + + expect_device_properties(acc_device_nvidia, dev_num, + total_mem, free_mem, vendor, p.name, driver); + } +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c new file mode 100644 index 000000000000..1a8dca6193b7 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-3.c @@ -0,0 +1,19 @@ +/* Test the `acc_get_property' and '`acc_get_property_string' library + functions for the host device. */ +/* { dg-additional-sources acc-get-property-aux.c } */ +/* { dg-do run } */ + +#include +#include + +void expect_device_properties +(acc_device_t dev_type, int dev_num, + int expected_total_mem, int expected_free_mem, + const char* expected_vendor, const char* expected_name, + const char* expected_driver); + +int main() +{ + printf ("Checking acc_device_host device properties\n"); + expect_device_properties (acc_device_host, 0, 0, 0, "GNU", "GOMP", "1.0"); +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c new file mode 100644 index 000000000000..5540b91f8427 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property-aux.c @@ -0,0 +1,60 @@ +/* Auxiliary functions for acc_get_property tests */ +/* { dg-do compile { target skip-all-targets } } */ + +#include +#include +#include +#include + +void expect_device_properties +(acc_device_t dev_type, int dev_num, + int expected_total_mem, int expected_free_mem, + const char* expected_vendor, const char* expected_name, + const char* expected_driver) +{ + const char *vendor = acc_get_property_string (dev_num, dev_type, + acc_property_vendor); + if (strcmp (vendor, expected_vendor)) + { + fprintf (stderr, "Expected acc_property_vendor to equal \"%s\", " + "but was \"%s\".\n", expected_vendor, vendor); + abort (); + } + + int total_mem = acc_get_property (dev_num, dev_type, + acc_property_memory); + if (total_mem != expected_total_mem) + { + fprintf (stderr, "Expected acc_property_memory to equal %d, " + "but was %d.\n", expected_total_mem, total_mem); + abort (); + + } + + int free_mem = acc_get_property (dev_num, dev_type, + acc_property_free_memory); + if (free_mem != expected_free_mem) + { + fprintf (stderr, "Expected acc_property_free_memory to equal %d, " + "but was %d.\n", expected_free_mem, free_mem); + abort (); + } + + const char *name = acc_get_property_string (dev_num, dev_type, + acc_property_name); + if (strcmp (name, expected_name)) + { + fprintf(stderr, "Expected acc_property_name to equal \"%s\", " + "but was \"%s\".\n", expected_name, name); + abort (); + } + + const char *driver = acc_get_property_string (dev_num, dev_type, + acc_property_driver); + if (strcmp (expected_driver, driver)) + { + fprintf (stderr, "Expected acc_property_driver to equal %s, " + "but was %s.\n", expected_driver, driver); + abort (); + } +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c new file mode 100644 index 000000000000..e9a86860f45d --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc-get-property.c @@ -0,0 +1,75 @@ +/* Test the `acc_get_property' and '`acc_get_property_string' library + functions by printing the results of those functions for all devices + of all device types mentioned in the OpenACC standard. + + See also acc-get-property.f90. */ +/* { dg-do run } */ + +#include +#include +#include +#include + +/* Print the values of the properties of all devices of the given type + and do basic device independent validation. */ + +void +print_device_properties(acc_device_t type) +{ + const char *s; + size_t v; + + int dev_count = acc_get_num_devices(type); + + for (int i = 0; i < dev_count; ++i) + { + printf(" Device %d:\n", i+1); + + s = acc_get_property_string (i, type, acc_property_vendor); + printf (" Vendor: %s\n", s); + if (s == NULL || *s == 0) + { + fprintf (stderr, "acc_property_vendor should not be null or empty.\n"); + abort (); + } + + v = acc_get_property (i, type, acc_property_memory); + printf (" Total memory: %zd\n", v); + + v = acc_get_property (i, type, acc_property_free_memory); + printf (" Free memory: %zd\n", v); + + s = acc_get_property_string (i, type, acc_property_name); + printf (" Name: %s\n", s); + if (s == NULL || *s == 0) + { + fprintf (stderr, "acc_property_name should not be null or empty.\n"); + abort (); + } + + s = acc_get_property_string (i, type, acc_property_driver); + printf (" Driver: %s\n", s); + if (s == NULL || *s == 0) + { + fprintf (stderr, "acc_property_string should not be null or empty.\n"); + abort (); + } + } +} + +int main () +{ + printf("acc_device_none:\n"); + /* For completness; not expected to print anything since there + should be no devices of this type. */ + print_device_properties(acc_device_none); + + printf("acc_device_default:\n"); + print_device_properties(acc_device_default); + + printf("acc_device_host:\n"); + print_device_properties(acc_device_host); + + printf("acc_device_not_host:\n"); + print_device_properties(acc_device_not_host); +} diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90 new file mode 100644 index 000000000000..71239cd0c7c2 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/acc-get-property.f90 @@ -0,0 +1,80 @@ +! Test the `acc_get_property' and '`acc_get_property_string' library +! functions by printing the results of those functions for all devices +! of all device types mentioned in the OpenACC standard. +! +! See also acc-get-property.c +! { dg-do run } + +program test + use openacc + implicit none + + print *, "acc_device_none:" + ! For completeness; not expected to print anything + call print_device_properties (acc_device_none) + + print *, "acc_device_default:" + call print_device_properties (acc_device_default) + + print *, "acc_device_host:" + call print_device_properties (acc_device_host) + + print *, "acc_device_not_host:" + call print_device_properties (acc_device_not_host) +end program test + +! Print the values of the properties of all devices of the given type +! and do basic device independent validation. +subroutine print_device_properties (device_type) + use openacc + implicit none + + integer, intent(in) :: device_type + + integer :: device_count + integer :: device + integer(acc_device_property) :: v + character*256 :: s + + device_count = acc_get_num_devices(device_type) + + do device = 0, device_count - 1 + print "(a, i0)", " Device ", device + + call acc_get_property_string (device, device_type, acc_property_vendor, s) + print "(a, a)", " Vendor: ", trim (s) + if (s == "") then + print *, "acc_property_vendor should not be empty." + stop 1 + end if + + v = acc_get_property (device, device_type, acc_property_memory) + print "(a, i0)", " Total memory: ", v + if (v < 0) then + print *, "acc_property_memory should not be negative." + stop 1 + end if + + v = acc_get_property (device, device_type, acc_property_free_memory) + print "(a, i0)", " Free memory: ", v + if (v < 0) then + print *, "acc_property_free_memory should not to be negative." + stop 1 + end if + + call acc_get_property_string (device, device_type, acc_property_name, s) + print "(a, a)", " Name: ", trim (s) + if (s == "") then + print *, "acc_property_name should not be empty." + stop 1 + end if + + call acc_get_property_string (device, device_type, acc_property_driver, s) + print "(a, a)", " Driver: ", trim (s) + if (s == "") then + print *, "acc_property_driver should not be empty." + stop 1 + end if + + end do +end subroutine print_device_properties diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp index d1678d0514e9..e3c60ad7f1fe 100644 --- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp +++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp @@ -174,6 +174,28 @@ GOMP_OFFLOAD_get_num_devices (void) return num_devices; } +extern "C" union gomp_device_property_value +GOMP_OFFLOAD_get_property (int n, int prop) +{ + union gomp_device_property_value nullval = { .val = 0 }; + + if (n >= num_devices) + { + GOMP_PLUGIN_error + ("Request for a property of a non-existing Intel MIC device %i", n); + return nullval; + } + + switch (prop) + { + case GOMP_DEVICE_PROPERTY_VENDOR: + /* TODO: "error: invalid conversion from 'const void*' to 'void*' [-fpermissive]" */ + return (union gomp_device_property_value) { .ptr = (char *) "Intel" }; + default: + return nullval; + } +} + static bool offload (const char *file, uint64_t line, int device, const char *name, int num_vars, VarDesc *vars, const void **async_data)