Hi Bernd, Here is updated patch for libgomp. It assumes that there is a constructor with a call to GOMP_offload_register in every target image, created by mkoffload tool. How does this look?
--- libgomp/libgomp.map | 1 + libgomp/plugin-host.c | 58 ++++++++++++++++- libgomp/target.c | 170 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 213 insertions(+), 16 deletions(-) diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index d8631a6..e43cb42 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -208,6 +208,7 @@ GOMP_3.0 { GOMP_4.0 { global: + GOMP_offload_register; GOMP_barrier_cancel; GOMP_cancel; GOMP_cancellation_point; diff --git a/libgomp/plugin-host.c b/libgomp/plugin-host.c index 5354ebe..ec0c78c 100644 --- a/libgomp/plugin-host.c +++ b/libgomp/plugin-host.c @@ -33,14 +33,53 @@ #include <stdlib.h> #include <string.h> -bool -device_available (void) +const int TARGET_TYPE_HOST = 0; + +int +get_type (void) { #ifdef DEBUG printf ("libgomp plugin: %s:%s\n", __FILE__, __FUNCTION__); #endif - return true; + return TARGET_TYPE_HOST; +} + +int +get_num_devices (void) +{ +#ifdef DEBUG + printf ("libgomp plugin: %s:%s\n", __FILE__, __FUNCTION__); +#endif + + return 1; +} + +void +offload_register (void *host_table, void *target_data) +{ +#ifdef DEBUG + printf ("libgomp plugin: %s:%s (%p, %p)\n", __FILE__, __FUNCTION__, + host_table, target_data); +#endif +} + +void +device_init (void) +{ +#ifdef DEBUG + printf ("libgomp plugin: %s:%s\n", __FILE__, __FUNCTION__); +#endif +} + +int +device_get_table (void *table) +{ +#ifdef DEBUG + printf ("libgomp plugin: %s:%s (%p)\n", __FILE__, __FUNCTION__, table); +#endif + + return 0; } void * @@ -82,3 +121,16 @@ void *device_host2dev (void *dest, const void *src, size_t n) return memcpy (dest, src, n); } + +void +device_run (void *fn_ptr, void *vars) +{ +#ifdef DEBUG + printf ("libgomp plugin: %s:%s (%p, %p)\n", __FILE__, __FUNCTION__, fn_ptr, + vars); +#endif + + void (*fn)(void *) = (void (*)(void *)) fn_ptr; + + fn (vars); +} diff --git a/libgomp/target.c b/libgomp/target.c index dbe6e28..8be9ea1 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -87,6 +87,26 @@ struct splay_tree_key_s { bool copy_from; }; +enum target_type { + TARGET_TYPE_HOST, + TARGET_TYPE_INTEL_MIC +}; + +/* This structure describes an offload image. + It contains type of the target, pointer to host table descriptor, and pointer + to target data. */ +struct offload_image_descr { + int type; + void *host_table; + void *target_data; +}; + +/* Array of descriptors of offload images. */ +static struct offload_image_descr *offload_images; + +/* Total number of offload images. */ +static int num_offload_images; + /* Array of descriptors of all available devices. */ static struct gomp_device_descr *devices; @@ -120,15 +140,26 @@ struct gomp_device_descr TARGET construct. */ int id; + /* This is the TYPE of device. */ + int type; + + /* Set to true when device is initialized. */ + bool is_initialized; + /* Plugin file handler. */ void *plugin_handle; /* Function handlers. */ - bool (*device_available_func) (void); + int (*get_type_func) (void); + int (*get_num_devices_func) (void); + void (*offload_register_func) (void *, void *); + void (*device_init_func) (void); + int (*device_get_table_func) (void *); void *(*device_alloc_func) (size_t); void (*device_free_func) (void *); - void *(*device_dev2host_func)(void *, const void *, size_t); - void *(*device_host2dev_func)(void *, const void *, size_t); + void *(*device_dev2host_func) (void *, const void *, size_t); + void *(*device_host2dev_func) (void *, const void *, size_t); + void (*device_run_func) (void *, void *); /* Splay tree containing information about mapped memory regions. */ struct splay_tree_s dev_splay_tree; @@ -137,6 +168,13 @@ struct gomp_device_descr gomp_mutex_t dev_env_lock; }; +struct mapping_table { + uintptr_t host_start; + uintptr_t host_end; + uintptr_t tgt_start; + uintptr_t tgt_end; +}; + attribute_hidden int gomp_get_num_devices (void) { @@ -474,6 +512,63 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, gomp_mutex_unlock (&devicep->dev_env_lock); } +/* This function should be called from every offload image. It gets the + descriptor of the host func and var tables HOST_TABLE, TYPE of the target, + and TARGET_DATA needed by target plugin (target tables, etc.) */ +void +GOMP_offload_register (void *host_table, int type, void *target_data) +{ + offload_images = realloc (offload_images, + (num_offload_images + 1) + * sizeof (struct offload_image_descr)); + + if (offload_images == NULL) + return; + + offload_images[num_offload_images].type = type; + offload_images[num_offload_images].host_table = host_table; + offload_images[num_offload_images].target_data = target_data; + + num_offload_images++; +} + +static void +gomp_init_device (struct gomp_device_descr *devicep) +{ + /* Initialize the target device. */ + devicep->device_init_func (); + + /* Get address mapping table for device. */ + struct mapping_table *table = NULL; + int num_entries = devicep->device_get_table_func (&table); + + /* Insert host-target address mapping into dev_splay_tree. */ + int i; + for (i = 0; i < num_entries; i++) + { + struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt)); + tgt->refcount = 1; + tgt->array = gomp_malloc (sizeof (*tgt->array)); + tgt->tgt_start = table[i].tgt_start; + tgt->tgt_end = table[i].tgt_end; + tgt->to_free = NULL; + tgt->list_count = 0; + tgt->device_descr = devicep; + splay_tree_node node = tgt->array; + splay_tree_key k = &node->key; + k->host_start = table[i].host_start; + k->host_end = table[i].host_end; + k->tgt_offset = 0; + k->tgt = tgt; + node->left = NULL; + node->right = NULL; + splay_tree_insert (&devicep->dev_splay_tree, node); + } + + free (table); + devicep->is_initialized = true; +} + /* Called when encountering a target directive. If DEVICE is -1, it means use device-var ICV. If it is -2 (or any other value larger than last available hw device, use host fallback. @@ -507,7 +602,17 @@ GOMP_target (int device, void (*fn) (void *), const void *openmp_target, return; } - struct target_mem_desc *tgt + if (!devicep->is_initialized) + gomp_init_device (devicep); + + struct splay_tree_key_s k; + k.host_start = (uintptr_t) fn; + k.host_end = k.host_start + 1; + splay_tree_key tgt_fn = splay_tree_lookup (&devicep->dev_splay_tree, &k); + if (tgt_fn == NULL && devicep->type != TARGET_TYPE_HOST) + gomp_fatal ("Target function wasn't mapped"); + + struct target_mem_desc *tgt_vars = gomp_map_vars (devicep, mapnum, hostaddrs, sizes, kinds, true); struct gomp_thread old_thr, *thr = gomp_thread (); old_thr = *thr; @@ -517,10 +622,14 @@ GOMP_target (int device, void (*fn) (void *), const void *openmp_target, thr->place = old_thr.place; thr->ts.place_partition_len = gomp_places_list_len; } - fn ((void *) tgt->tgt_start); + if (devicep->type == TARGET_TYPE_HOST) + devicep->device_run_func (fn, (void *) tgt_vars->tgt_start); + else + devicep->device_run_func ((void *) tgt_fn->tgt->tgt_start, + (void *) tgt_vars->tgt_start); gomp_free_thread (thr); *thr = old_thr; - gomp_unmap_vars (tgt); + gomp_unmap_vars (tgt_vars); } void @@ -546,6 +655,9 @@ GOMP_target_data (int device, const void *openmp_target, size_t mapnum, return; } + if (!devicep->is_initialized) + gomp_init_device (devicep); + struct target_mem_desc *tgt = gomp_map_vars (devicep, mapnum, hostaddrs, sizes, kinds, false); struct gomp_task_icv *icv = gomp_icv (true); @@ -573,6 +685,9 @@ GOMP_target_update (int device, const void *openmp_target, size_t mapnum, if (devicep == NULL) return; + if (!devicep->is_initialized) + gomp_init_device (devicep); + gomp_update (devicep, mapnum, hostaddrs, sizes, kinds); } @@ -639,11 +754,16 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, goto out; \ } \ while (0) - DLSYM (device_available); + DLSYM (get_type); + DLSYM (get_num_devices); + DLSYM (offload_register); + DLSYM (device_init); + DLSYM (device_get_table); DLSYM (device_alloc); DLSYM (device_free); DLSYM (device_dev2host); DLSYM (device_host2dev); + DLSYM (device_run); #undef DLSYM out: @@ -656,6 +776,21 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, return err == NULL; } +/* This function finds OFFLOAD_IMAGES corresponding to DEVICE type, and + registers them in the plugin. */ +static void +gomp_register_images_for_device (struct gomp_device_descr *device) +{ + int i; + for (i = 0; i < num_offload_images; i++) + { + struct offload_image_descr *image = &offload_images[i]; + + if (device->type == image->type || device->type == TARGET_TYPE_HOST) + device->offload_register_func (image->host_table, image->target_data); + } +} + /* This functions scans folder, specified in environment variable LIBGOMP_PLUGIN_PATH, and loads all suitable libgomp plugins from this folder. For a plugin to be suitable, its name should be "libgomp-plugin-*.so.1" and @@ -701,16 +836,25 @@ gomp_find_available_plugins (void) goto out; } - devices[num_devices] = current_device; - devices[num_devices].id = num_devices + 1; - devices[num_devices].dev_splay_tree.root = NULL; - gomp_mutex_init (&devices[num_devices].dev_env_lock); - num_devices++; + /* FIXME: Properly handle multiple devices of the same type. */ + if (current_device.get_num_devices_func () >= 1) + { + current_device.id = num_devices + 1; + current_device.type = current_device.get_type_func (); + current_device.is_initialized = false; + current_device.dev_splay_tree.root = NULL; + gomp_register_images_for_device (¤t_device); + devices[num_devices] = current_device; + gomp_mutex_init (&devices[num_devices].dev_env_lock); + num_devices++; + } } - out: +out: if (dir) closedir (dir); + free (offload_images); + num_offload_images = 0; } /* This function initializes runtime needed for offloading. -- 1.7.1 -- Ilya