[RFC] Offloading Support in libgomp

Michael V. Zolotukhin michael.v.zolotukhin@gmail.com
Fri Sep 13 11:30:00 GMT 2013


Hi Jakub,
Here is the first patch for adding plugins support in libgomp - could you please
take a look at it?

I changed configure.ac to add dl-library, but I am not sure if I regenerated all
related to configure files properly.  I'd appreciate your help here, if I did
it wrong.

Any feedback is welcome too.

Thanks, Michael

---
 libgomp/configure    |  46 +++++++++++++++
 libgomp/configure.ac |   2 +
 libgomp/target.c     | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)

diff --git a/libgomp/configure b/libgomp/configure
index 238b1af..2086fdb 100755
--- a/libgomp/configure
+++ b/libgomp/configure
@@ -15046,6 +15046,52 @@ fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5
+$as_echo_n "checking for dlsym in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlsym+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlsym ();
+int
+main ()
+{
+return dlsym ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlsym=yes
+else
+  ac_cv_lib_dl_dlsym=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlsym" >&5
+$as_echo "$ac_cv_lib_dl_dlsym" >&6; }
+if test "x$ac_cv_lib_dl_dlsym" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+  LIBS="-ldl $LIBS"
+
+fi
+
+
 # Check for functions needed.
 for ac_func in getloadavg clock_gettime strtoull
 do :
diff --git a/libgomp/configure.ac b/libgomp/configure.ac
index d87ed29..1c78239 100644
--- a/libgomp/configure.ac
+++ b/libgomp/configure.ac
@@ -193,6 +193,8 @@ AC_LINK_IFELSE(
    [],
    [AC_MSG_ERROR([Pthreads are required to build libgomp])])])
 
+AC_CHECK_LIB(dl, dlsym)
+
 # Check for functions needed.
 AC_CHECK_FUNCS(getloadavg clock_gettime strtoull)
 
diff --git a/libgomp/target.c b/libgomp/target.c
index 0a874d4..73f656c 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -28,6 +28,45 @@
 #include "libgomp.h"
 #include <stdlib.h>
 #include <string.h>
+#include <dirent.h>
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+static void gomp_target_init (void);
+
+/* This structure describes accelerator device.
+   It contains name of the corresponding libgomp plugin, function handlers for
+   interaction with the device, ID-number of the device, and information about
+   mapped memory.  */
+struct gomp_device_descr
+{
+  /* This is the ID number of device.  It could be specified in DEVICE-clause of
+     TARGET construct.  */
+  int id;
+
+  /* Plugin file name.  */
+  char plugin_name[PATH_MAX];
+
+  /* Plugin file handler.  */
+  void *plugin_handle;
+
+  /* Function handlers.  */
+  bool (*device_available_func) (void);
+
+  /* Information about mapping.  Not implemented yet.  */
+  /* SplayTree map_info;  */
+};
+
+/* Array of descriptors of all available devices.  */
+static struct gomp_device_descr *devices;
+
+/* Total number of available devices.  */
+static int num_devices;
+
+static pthread_once_t gomp_is_initialized = PTHREAD_ONCE_INIT;
+
 
 static int
 resolve_device (int device)
@@ -49,6 +88,7 @@ GOMP_target (int device, void (*fn) (void *), const char *fnname,
 	     size_t mapnum, void **hostaddrs, size_t *sizes,
 	     unsigned char *kinds)
 {
+  (void) pthread_once (&gomp_is_initialized, gomp_target_init);
   if (resolve_device (device) == -1)
     {
       fn (hostaddrs);
@@ -60,6 +100,7 @@ void
 GOMP_target_data (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
 		  unsigned char *kinds)
 {
+  (void) pthread_once (&gomp_is_initialized, gomp_target_init);
   if (resolve_device (device) == -1)
     return;
 }
@@ -73,6 +114,7 @@ void
 GOMP_target_update (int device, size_t mapnum, void **hostaddrs, size_t *sizes,
 		    unsigned char *kinds)
 {
+  (void) pthread_once (&gomp_is_initialized, gomp_target_init);
   if (resolve_device (device) == -1)
     return;
 }
@@ -81,3 +123,116 @@ void
 GOMP_teams (unsigned int num_teams, unsigned int thread_limit)
 {
 }
+
+
+#ifdef HAVE_DLFCN_H
+/* This function checks if the given string FNAME matches
+   "libgomp-plugin-*.so.1".  */
+static bool
+gomp_check_plugin_file_name (const char *fname)
+{
+  const char *prefix = "libgomp-plugin-";
+  const char *suffix = ".so.1";
+  if (!fname)
+    return false;
+  if (strncmp (fname, prefix, strlen (prefix)) != 0)
+    return false;
+  if (strncmp (fname + strnlen (fname, NAME_MAX + 1) - strlen (suffix),
+	       suffix,
+	       strlen (suffix)) != 0)
+    return false;
+  return true;
+}
+
+/* This function tries to load plugin for DEVICE.  Name of plugin should be
+   stored in PLUGIN_NAME field.
+   Plugin handle and handles of the found functions are stored in the
+   corresponding fields of DEVICE.
+   The function returns TRUE on success and FALSE otherwise.  */
+static bool
+gomp_load_plugin_for_device (struct gomp_device_descr *device)
+{
+  if (!device || !device->plugin_name)
+    return false;
+
+  device->plugin_handle = dlopen (device->plugin_name, RTLD_LAZY);
+  if (!device->plugin_handle)
+    return false;
+
+  /* Clear any existing error.  */
+  dlerror ();
+
+  /* Check if all required functions are available in the plugin and store
+     their handlers.
+     TODO: check for other routines as well.  */
+  *(void **) (&device->device_available_func) = dlsym (device->plugin_handle,
+						       "device_available");
+  if (dlerror () != NULL)
+    {
+      dlclose (device->plugin_handle);
+      return false;
+    }
+
+  return true;
+}
+
+/* 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
+   it should implement a certain set of functions.
+   Result of this function is properly initialized variable NUM_DEVICES and
+   array DEVICES, containing all plugins and their callback handles.  */
+static void
+gomp_find_available_plugins (void)
+{
+  char *plugin_path = NULL;
+  DIR *dir = NULL;
+  struct dirent *ent;
+
+  num_devices = 0;
+  devices = NULL;
+
+  plugin_path = getenv ("LIBGOMP_PLUGIN_PATH");
+  if (!plugin_path)
+    return;
+
+  dir = opendir (plugin_path);
+  if (!dir)
+    return;
+
+  while ((ent = readdir (dir)) != NULL)
+    {
+      struct gomp_device_descr current_device;
+      if (!gomp_check_plugin_file_name (ent->d_name))
+	continue;
+      strncpy (current_device.plugin_name, plugin_path, PATH_MAX);
+      strcat (current_device.plugin_name, "/");
+      strcat (current_device.plugin_name, ent->d_name);
+      if (!gomp_load_plugin_for_device (&current_device))
+	continue;
+      devices = realloc (devices, (num_devices + 1)
+				  * sizeof (struct gomp_device_descr));
+
+      devices[num_devices] = current_device;
+      devices[num_devices].id = num_devices + 1;
+      num_devices++;
+    }
+  closedir (dir);
+}
+
+/* This function initializes runtime needed for offloading.
+   It loads plugins, sets up a connection with devices, etc.  */
+static void
+gomp_target_init (void)
+{
+  gomp_find_available_plugins ();
+}
+
+#else /* HAVE_DLFCN_H */
+/* If dlfcn.h is unavailable we always fallback to host execution.
+   GOMP_target* routines are just stubs for this case.  */
+static void
+gomp_target_init (void)
+{
+}
+#endif /* HAVE_DLFCN_H */
-- 
1.8.3.1



More information about the Gcc mailing list