Hi, this patch adds full support for the OpenACC 2.6 acc_get_property and acc_get_property_string functions to the libgomp GCN plugin. This replaces the existing stub in libgomp/plugin-gcn.c.
Andrew: The value returned for acc_property_memory ("size of device memory in bytes" according to the spec) is the HSA_REGION_INFO_SIZE of the agent's data_region. This has been adapted from a previous incomplete implementation that we had on the OG9 branch. Does that sound reasonable? I have tested the patch with amdgcn and nvptx offloading. Ok to commit this to the main branch? Best regards, Frederik
From 6f1855281c38993a088f9b4af020a786f8e05fe9 Mon Sep 17 00:00:00 2001 From: Frederik Harwath <frede...@codesourcery.com> Date: Tue, 28 Jan 2020 08:01:00 +0100 Subject: [PATCH] Add OpenACC acc_get_property support for AMD GCN Add full support for the OpenACC 2.6 acc_get_property and acc_get_property_string functions to the libgomp GCN plugin. libgomp/ * plugin-gcn.c (struct agent_info): Add fields "name" and "vendor_name" ... (GOMP_OFFLOAD_init_device): ... and init from here. (struct hsa_context_info): Add field "driver_version_s" ... (init_hsa_contest): ... and init from here. (GOMP_OFFLOAD_openacc_get_property): Replace stub with a proper implementation. * testsuite/libgomp.oacc-c-c++-common/acc_get_property.c: Enable test execution for amdgcn and host offloading targets. * testsuite/libgomp.oacc-fortran/acc_get_property.f90: Likewise. * testsuite/libgomp.oacc-c-c++-common/acc_get_property-aux.c (expect_device_properties): Split function into ... (expect_device_string_properties): ... this new function ... (expect_device_memory): ... and this new function. * testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c: Add test. --- libgomp/plugin/plugin-gcn.c | 63 +++++++-- .../acc_get_property-aux.c | 60 +++++--- .../acc_get_property-gcn.c | 132 ++++++++++++++++++ .../acc_get_property.c | 5 +- .../libgomp.oacc-fortran/acc_get_property.f90 | 2 - 5 files changed, 224 insertions(+), 38 deletions(-) create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c index 7854c142f05..0a09daaa0a4 100644 --- a/libgomp/plugin/plugin-gcn.c +++ b/libgomp/plugin/plugin-gcn.c @@ -425,7 +425,10 @@ struct agent_info /* The instruction set architecture of the device. */ gcn_isa device_isa; - + /* Name of the agent. */ + char name[64]; + /* Name of the vendor of the agent. */ + char vendor_name[64]; /* Command queues of the agent. */ hsa_queue_t *sync_queue; struct goacc_asyncqueue *async_queues, *omp_async_queue; @@ -544,6 +547,8 @@ struct hsa_context_info int agent_count; /* Array of agent_info structures describing the individual HSA agents. */ struct agent_info *agents; + /* Driver version string. */ + char driver_version_s[30]; }; /* Format of the on-device heap. @@ -1513,6 +1518,15 @@ init_hsa_context (void) GOMP_PLUGIN_error ("Failed to list all HSA runtime agents"); } + uint16_t minor, major; + status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MINOR, &minor); + if (status != HSA_STATUS_SUCCESS) + GOMP_PLUGIN_error ("Failed to obtain HSA runtime minor version"); + status = hsa_fns.hsa_system_get_info_fn (HSA_SYSTEM_INFO_VERSION_MAJOR, &major); + if (status != HSA_STATUS_SUCCESS) + GOMP_PLUGIN_error ("Failed to obtain HSA runtime major version"); + sprintf (hsa_context.driver_version_s, "HSA Runtime %d.%d", major, minor); + hsa_context.initialized = true; return true; } @@ -3410,15 +3424,19 @@ GOMP_OFFLOAD_init_device (int n) return hsa_error ("Error requesting maximum queue size of the GCN agent", status); - char buf[64]; status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_NAME, - &buf); + &agent->name); if (status != HSA_STATUS_SUCCESS) return hsa_error ("Error querying the name of the agent", status); - agent->device_isa = isa_code (buf); + agent->device_isa = isa_code (agent->name); if (agent->device_isa < 0) - return hsa_error ("Unknown GCN agent architecture.", HSA_STATUS_ERROR); + return hsa_error ("Unknown GCN agent architecture", HSA_STATUS_ERROR); + + status = hsa_fns.hsa_agent_get_info_fn (agent->id, HSA_AGENT_INFO_VENDOR_NAME, + &agent->vendor_name); + if (status != HSA_STATUS_SUCCESS) + return hsa_error ("Error querying the vendor name of the agent", status); status = hsa_fns.hsa_queue_create_fn (agent->id, queue_size, HSA_QUEUE_TYPE_MULTI, @@ -4115,12 +4133,37 @@ GOMP_OFFLOAD_openacc_async_dev2host (int device, void *dst, const void *src, union goacc_property_value GOMP_OFFLOAD_openacc_get_property (int device, enum goacc_property prop) { - /* Stub. Check device and return default value for unsupported properties. */ - /* TODO: Implement this function. */ - get_agent_info (device); + struct agent_info *agent = get_agent_info (device); + + union goacc_property_value propval = { .val = 0 }; + + switch (prop) + { + case GOACC_PROPERTY_FREE_MEMORY: + /* Not supported. */ + break; + case GOACC_PROPERTY_MEMORY: + { + size_t size; + hsa_region_t region = agent->data_region; + hsa_status_t status = + hsa_fns.hsa_region_get_info_fn (region, HSA_REGION_INFO_SIZE, &size); + if (status == HSA_STATUS_SUCCESS) + propval.val = size; + break; + } + case GOACC_PROPERTY_NAME: + propval.ptr = agent->name; + break; + case GOACC_PROPERTY_VENDOR: + propval.ptr = agent->vendor_name; + break; + case GOACC_PROPERTY_DRIVER: + propval.ptr = hsa_context.driver_version_s; + break; + } - union goacc_property_value nullval = { .val = 0 }; - return nullval; + return propval; } /* Set up plugin-specific thread-local-data (host-side). */ 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 index 6bb01250148..6a4a499eb21 100644 --- 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 @@ -6,10 +6,11 @@ #include <stdio.h> #include <string.h> -void expect_device_properties + +void expect_device_string_properties (acc_device_t dev_type, int dev_num, - size_t expected_memory, const char* expected_vendor, - const char* expected_name, const char* expected_driver) + 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); @@ -20,26 +21,6 @@ void expect_device_properties abort (); } - size_t total_mem = acc_get_property (dev_num, dev_type, - acc_property_memory); - if (total_mem != expected_memory) - { - fprintf (stderr, "Expected acc_property_memory to equal %zu, " - "but was %zu.\n", expected_memory, total_mem); - abort (); - - } - - size_t free_mem = acc_get_property (dev_num, dev_type, - acc_property_free_memory); - if (free_mem > total_mem) - { - fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory" - ", but free memory was %zu and total memory was %zu.\n", - free_mem, total_mem); - abort (); - } - const char *name = acc_get_property_string (dev_num, dev_type, acc_property_name); if (strcmp (name, expected_name)) @@ -75,6 +56,39 @@ void expect_device_properties "but was %s.\n", s); abort (); } +} + +void expect_device_memory +(acc_device_t dev_type, int dev_num, size_t expected_total_memory) +{ + + size_t total_mem = acc_get_property (dev_num, dev_type, + acc_property_memory); + + if (total_mem != expected_total_memory) + { + fprintf (stderr, "Expected acc_property_memory to equal %zu, " + "but was %zu.\n", expected_total_memory, total_mem); + abort (); + } + size_t free_mem = acc_get_property (dev_num, dev_type, + acc_property_free_memory); + if (free_mem > total_mem) + { + fprintf (stderr, "Expected acc_property_free_memory <= acc_property_memory" + ", but free memory was %zu and total memory was %zu.\n", + free_mem, total_mem); + abort (); + } +} +void expect_device_properties +(acc_device_t dev_type, int dev_num, + size_t expected_total_memory, const char* expected_vendor, + const char* expected_name, const char* expected_driver) +{ + expect_device_string_properties (dev_type, dev_num, expected_vendor, + expected_name, expected_driver); + expect_device_memory (dev_type, dev_num, expected_total_memory); } diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c new file mode 100644 index 00000000000..305bb1af365 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property-gcn.c @@ -0,0 +1,132 @@ +/* Test the `acc_get_property' and `acc_get_property_string' library + functions on amdgcn devices by comparing property values with + those obtained through the HSA API. */ +/* { dg-additional-sources acc_get_property-aux.c } */ +/* { dg-additional-options "-ldl" } */ +/* { dg-do run { target openacc_amdgcn_accel_selected } } */ + +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <openacc.h> + +#ifndef __cplusplus +typedef int bool; +#endif +#include <hsa.h> + + +void expect_device_string_properties +(acc_device_t dev_type, int dev_num, + const char* expected_vendor, const char* expected_name, + const char* expected_driver); + +hsa_status_t (*hsa_agent_get_info_fn) (hsa_agent_t agent, + hsa_agent_info_t attribute, + void *value); +hsa_status_t (*hsa_system_get_info_fn) (hsa_system_info_t attribute, + void *value); +hsa_status_t (*hsa_iterate_agents_fn) +(hsa_status_t (*callback)(hsa_agent_t agent, void *data), void *data); +hsa_status_t (*hsa_init_fn) (void); + +char* support_cpu_devices; + +void test_setup () +{ + char* env_runtime; + char* hsa_runtime_lib; + void *handle; + +#define DLSYM_FN(function) \ + function##_fn = (typeof(function##_fn))dlsym (handle, #function); \ + if (function##_fn == NULL) \ + { \ + fprintf (stderr, "Could not get symbol " #function ".\n"); \ + abort (); \ + } + + env_runtime = getenv ("HSA_RUNTIME_LIB"); + hsa_runtime_lib = env_runtime ? env_runtime : (char*)"libhsa-runtime64.so"; + + handle = dlopen (hsa_runtime_lib, RTLD_LAZY); + if (!handle) + { + fprintf (stderr, "Could not load %s.\n", hsa_runtime_lib); + abort (); + } + + DLSYM_FN (hsa_agent_get_info) + DLSYM_FN (hsa_system_get_info) + DLSYM_FN (hsa_iterate_agents) + DLSYM_FN (hsa_init) + + hsa_init_fn (); + + support_cpu_devices = getenv ("GCN_SUPPORT_CPU_DEVICES"); +} + +static hsa_status_t check_agent_properties +(hsa_agent_t agent, void *dev_num_arg) +{ + + char name[64]; + char vendor_name[64]; + uint16_t minor; + uint16_t major; + char driver[30]; + + hsa_status_t status; + hsa_device_type_t device_type; + int* dev_num = (int*)dev_num_arg; + +#define AGENT_GET_INFO(info_type, val) \ + status = hsa_agent_get_info_fn (agent, info_type, &val); \ + if (status != HSA_STATUS_SUCCESS) \ + { \ + fprintf (stderr, "Failed to obtain " #info_type ".\n"); \ + abort (); \ + } +#define SYSTEM_GET_INFO(info_type, val) \ + status = hsa_system_get_info_fn (info_type, &val); \ + if (status != HSA_STATUS_SUCCESS) \ + { \ + fprintf (stderr, "Failed to obtain " #info_type ".\n"); \ + abort (); \ + } + + AGENT_GET_INFO (HSA_AGENT_INFO_DEVICE, device_type) + + /* Skip unsupported device types. Mimic the GCN plugin's behavior. */ + if (!(device_type == HSA_DEVICE_TYPE_GPU + || (support_cpu_devices && device_type == HSA_DEVICE_TYPE_CPU))) + return HSA_STATUS_SUCCESS; + + AGENT_GET_INFO (HSA_AGENT_INFO_NAME, name) + AGENT_GET_INFO (HSA_AGENT_INFO_VENDOR_NAME, vendor_name) + + SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MINOR, minor) + SYSTEM_GET_INFO (HSA_SYSTEM_INFO_VERSION_MAJOR, major) + + sprintf (driver, "HSA Runtime %d.%d", major, minor); + + expect_device_string_properties(acc_device_radeon, *dev_num, + vendor_name, name, driver); + + (*dev_num)++; + + return status; +} + +int main() +{ + int dev_num = 0; + test_setup (); + + hsa_status_t status = + hsa_iterate_agents_fn (&check_agent_properties, &dev_num); + + return status; +} 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 index 388c66c1319..1984ad3a28d 100644 --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/acc_get_property.c @@ -3,8 +3,7 @@ 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. */ +/* { dg-do run } */ #include <openacc.h> #include <stdlib.h> @@ -20,7 +19,7 @@ print_device_properties(acc_device_t type) const char *s; size_t v; - int dev_count = acc_get_num_devices(type); + int dev_count = acc_get_num_devices (type); for (int i = 0; i < dev_count; ++i) { diff --git a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 index ce695475ae4..80ae292f41f 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/acc_get_property.f90 @@ -3,8 +3,6 @@ ! 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 -- 2.17.1