diff mbox

[RFC,gomp4] Offloading: Add device initialization and host->target function mapping

Message ID 20131226133740.GA34098@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Verbin Dec. 26, 2013, 1:37 p.m. UTC
Ping.
(Patch is slightly updated)

On 20 Dec 21:18, Ilya Verbin wrote:
> Hi Jakub,
> 
> Could you please take a look at this patch for libgomp?
> 
> It adds new function GOMP_register_lib, that should be called from every
> exec/lib with target regions (that was done in patch [1]).  This function
> maintains the array of pointers to the target shared library descriptors.
> 
> Also this patch adds target device initialization into GOMP_target and
> GOMP_target_data.  At first, it calls "device_init" function from the plugin.
> This function takes array of target-images as input, and returns the array of
> target-side addresses.  Currently, it always uses the first target-image from
> the descriptor, this should be generalized later.  Then libgomp reads the tables
> from host-side exec/libs.  After that, it inserts host->target address mapping
> into the splay tree.
> 
> [1] http://gcc.gnu.org/ml/gcc-patches/2013-12/msg01486.html
> 
> Thanks,
>     -- Ilya

    -- Ilya

---
 libgomp/libgomp.map |    1 +
 libgomp/target.c    |  154 ++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 146 insertions(+), 9 deletions(-)

Comments

Ilya Verbin Jan. 15, 2014, 3:09 p.m. UTC | #1
Ping.
diff mbox

Patch

diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index 2b64d05..792047f 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -208,6 +208,7 @@  GOMP_3.0 {
 
 GOMP_4.0 {
   global:
+	GOMP_register_lib;
 	GOMP_barrier_cancel;
 	GOMP_cancel;
 	GOMP_cancellation_point;
diff --git a/libgomp/target.c b/libgomp/target.c
index d84a1fa..7677c28 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -84,6 +84,19 @@  struct splay_tree_key_s {
   bool copy_from;
 };
 
+enum library_descr {
+  DESCR_TABLE_START,
+  DESCR_TABLE_END,
+  DESCR_IMAGE_START,
+  DESCR_IMAGE_END
+};
+
+/* Array of pointers to target shared library descriptors.  */
+static void **libraries;
+
+/* Total number of target shared libraries.  */
+static int num_libraries;
+
 /* Array of descriptors of all available devices.  */
 static struct gomp_device_descr *devices;
 
@@ -117,11 +130,16 @@  struct gomp_device_descr
      TARGET construct.  */
   int id;
 
+  /* Set to true when device is initialized.  */
+  bool is_initialized;
+
   /* Plugin file handler.  */
   void *plugin_handle;
 
   /* Function handlers.  */
-  bool (*device_available_func) (void);
+  bool (*device_available_func) (int);
+  void (*device_init_func) (void **, int *, int, void ***, int *);
+  void (*device_run_func) (void *, uintptr_t);
 
   /* Splay tree containing information about mapped memory regions.  */
   struct splay_tree_s dev_splay_tree;
@@ -466,6 +484,89 @@  gomp_update (struct gomp_device_descr *devicep, size_t mapnum,
   gomp_mutex_unlock (&devicep->dev_env_lock);
 }
 
+void
+GOMP_register_lib (const void *openmp_target)
+{
+  libraries = realloc (libraries, (num_libraries + 1) * sizeof (void *));
+
+  if (libraries == NULL)
+    return;
+
+  libraries[num_libraries] = (void *) openmp_target;
+
+  num_libraries++;
+}
+
+static void
+gomp_init_device (struct gomp_device_descr *devicep)
+{
+  void **target_images = malloc (num_libraries * sizeof (void *));
+  int *target_img_sizes = malloc (num_libraries * sizeof (int));
+  if (target_images == NULL || target_img_sizes == NULL)
+    gomp_fatal ("Can not allocate memory");
+
+  /* Collect target images from the library descriptors and calculate the total
+     size of host address table.  */
+  int i, host_table_size = 0;
+  for (i = 0; i < num_libraries; i++)
+    {
+      void **lib = libraries[i];
+      void **host_table_start = lib[DESCR_TABLE_START];
+      void **host_table_end = lib[DESCR_TABLE_END];
+      /* FIXME: Select the proper target image.  */
+      target_images[i] = lib[DESCR_IMAGE_START];
+      target_img_sizes[i] = lib[DESCR_IMAGE_END] - lib[DESCR_IMAGE_START];
+      host_table_size += host_table_end - host_table_start;
+    }
+
+  /* Initialize the target device and receive the address table from target.  */
+  void **target_table = NULL;
+  int target_table_size = 0;
+  devicep->device_init_func (target_images, target_img_sizes, num_libraries,
+			     &target_table, &target_table_size);
+  free (target_images);
+  free (target_img_sizes);
+
+  if (host_table_size != target_table_size)
+    gomp_fatal ("Can't map target objects");
+
+  /* Initialize the mapping data structure.  */
+  void **target_entry = target_table;
+  for (i = 0; i < num_libraries; i++)
+    {
+      void **lib = libraries[i];
+      void **host_table_start = lib[DESCR_TABLE_START];
+      void **host_table_end = lib[DESCR_TABLE_END];
+      void **host_entry;
+      for (host_entry = host_table_start; host_entry < host_table_end;
+	   host_entry += 2, target_entry += 2)
+	{
+	  struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt));
+	  tgt->refcount = 1;
+	  tgt->array = gomp_malloc (sizeof (*tgt->array));
+	  tgt->tgt_start = (uintptr_t) *target_entry;
+	  tgt->tgt_end = tgt->tgt_start + *((uint64_t *) target_entry + 1);
+	  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 = (uintptr_t) *host_entry;
+	  k->host_end = k->host_start + *((uint64_t *) host_entry + 1);
+	  k->tgt = tgt;
+	  node->left = NULL;
+	  node->right = NULL;
+	  splay_tree_insert (&devicep->dev_splay_tree, node);
+	}
+    }
+
+  free (libraries);
+  num_libraries = 0;
+  free (target_table);
+  target_table_size = 0;
+  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.
@@ -482,7 +583,8 @@  GOMP_target (int device, void (*fn) (void *), const void *openmp_target,
 	     unsigned char *kinds)
 {
   struct gomp_device_descr *devicep = resolve_device (device);
-  if (devicep == NULL)
+  if (openmp_target == NULL || devicep == NULL
+      || !devicep->device_available_func (devicep->id))
     {
       /* Host fallback.  */
       struct gomp_thread old_thr, *thr = gomp_thread ();
@@ -499,7 +601,18 @@  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);
+
+  splay_tree_node node = gomp_malloc (sizeof (*node));
+  splay_tree_key k = &node->key;
+  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)
+    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;
@@ -509,10 +622,11 @@  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);
+  devicep->device_run_func ((void *) tgt_fn->tgt->tgt_start,
+			    tgt_vars->tgt_start);
   gomp_free_thread (thr);
   *thr = old_thr;
-  gomp_unmap_vars (tgt);
+  gomp_unmap_vars (tgt_vars);
 }
 
 void
@@ -520,7 +634,8 @@  GOMP_target_data (int device, const void *openmp_target, size_t mapnum,
 		  void **hostaddrs, size_t *sizes, unsigned char *kinds)
 {
   struct gomp_device_descr *devicep = resolve_device (device);
-  if (devicep == NULL)
+  if (openmp_target == NULL || devicep == NULL
+      || !devicep->device_available_func (devicep->id))
     {
       /* Host fallback.  */
       struct gomp_task_icv *icv = gomp_icv (false);
@@ -538,6 +653,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);
@@ -562,9 +680,13 @@  GOMP_target_update (int device, const void *openmp_target, size_t mapnum,
 		    void **hostaddrs, size_t *sizes, unsigned char *kinds)
 {
   struct gomp_device_descr *devicep = resolve_device (device);
-  if (devicep == NULL)
+  if (openmp_target == NULL || devicep == NULL
+      || !devicep->device_available_func (devicep->id))
     return;
 
+  if (!devicep->is_initialized)
+    gomp_fatal ("Target device wasn't initialized");
+
   gomp_update (devicep, mapnum, hostaddrs, sizes, kinds);
 }
 
@@ -619,8 +741,7 @@  gomp_load_plugin_for_device (struct gomp_device_descr *device,
   dlerror ();
 
   /* Check if all required functions are available in the plugin and store
-     their handlers.
-     TODO: check for other routines as well.  */
+     their handlers.  */
   device->device_available_func = dlsym (device->plugin_handle,
 					 "device_available");
   if (dlerror () != NULL)
@@ -629,6 +750,20 @@  gomp_load_plugin_for_device (struct gomp_device_descr *device,
       return false;
     }
 
+  device->device_init_func = dlsym (device->plugin_handle, "device_init");
+  if (dlerror () != NULL)
+    {
+      dlclose (device->plugin_handle);
+      return false;
+    }
+
+  device->device_run_func = dlsym (device->plugin_handle, "device_run");
+  if (dlerror () != NULL)
+    {
+      dlclose (device->plugin_handle);
+      return false;
+    }
+
   return true;
 }
 
@@ -680,6 +815,7 @@  gomp_find_available_plugins (void)
 
       devices[num_devices] = current_device;
       devices[num_devices].id = num_devices + 1;
+      devices[num_devices].is_initialized = false;
       devices[num_devices].dev_splay_tree.root = NULL;
       gomp_mutex_init (&devices[num_devices].dev_env_lock);
       num_devices++;