[gnome-builder] egg-counter: add vsdo fallback when on linux and no rdtscp instruction



commit d2223050d506da73f1690a157b3597e3efc16aab
Author: Christian Hergert <christian hergert me>
Date:   Thu Sep 17 03:36:33 2015 -0700

    egg-counter: add vsdo fallback when on linux and no rdtscp instruction
    
    This is basically as fast as rdtsp but more portable since it will work
    with Linux even on machines without rdtscp. If for some reason we don't
    have any of that (ARM Linux) we fallback to sched_getcpu().
    
    BSDs should continue to use atomics fallback. I would love to see that
    change though.

 configure.ac              |    4 ++
 contrib/egg/egg-counter.c |  111 +++++++++++++++++++++++++++++++++++++++++++++
 contrib/egg/egg-counter.h |   16 +++----
 3 files changed, 122 insertions(+), 9 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index b49e502..33add17 100644
--- a/configure.ac
+++ b/configure.ac
@@ -102,6 +102,10 @@ dnl ***********************************************************************
 dnl Enable high-performance counters
 dnl ***********************************************************************
 GB_ENABLE_RDTSCP
+AS_IF([test $enable_rdtscp = yes],[
+       CFLAGS="$CFLAGS -DEGG_HAVE_RDTSCP"
+])
+AC_CHECK_FUNCS([sched_getcpu])
 
 
 dnl ***********************************************************************
diff --git a/contrib/egg/egg-counter.c b/contrib/egg/egg-counter.c
index e1edfe0..f5ba438 100644
--- a/contrib/egg/egg-counter.c
+++ b/contrib/egg/egg-counter.c
@@ -16,10 +16,17 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
 #ifndef _GNU_SOURCE
 # define _GNU_SOURCE
 #endif
 
+#ifdef __linux__
+# include <dlfcn.h>
+#endif
 #include <glib/gprintf.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -96,6 +103,9 @@ struct _EggCounterArena
 
 G_LOCK_DEFINE_STATIC (reglock);
 
+static void _egg_counter_init_getcpu (void) __attribute__ ((constructor));
+static guint (*_egg_counter_getcpu_helper) (void);
+
 gint64
 egg_counter_get (EggCounter *counter)
 {
@@ -481,3 +491,104 @@ egg_counter_arena_register (EggCounterArena *arena,
 
   G_UNLOCK (reglock);
 }
+
+#ifdef __linux__
+static void *
+_egg_counter_find_getcpu_in_vdso (void)
+{
+  static const gchar *vdso_names[] = {
+    "linux-vdso.so.1",
+    "linux-vdso32.so.1",
+    "linux-vdso64.so.1",
+    NULL
+  };
+  static const gchar *sym_names[] = {
+    "__kernel_getcpu",
+    "__vdso_getcpu",
+    NULL
+  };
+  gint i;
+
+  for (i = 0; vdso_names [i]; i++)
+    {
+      void *lib;
+      gint j;
+
+      lib = dlopen (vdso_names [i], RTLD_NOW | RTLD_GLOBAL);
+      if (lib == NULL)
+        continue;
+
+      for (j = 0; sym_names [j]; j++)
+        {
+          void *sym;
+
+          sym = dlsym (lib, sym_names [j]);
+          if (!sym)
+            continue;
+
+          return sym;
+        }
+
+      dlclose (lib);
+    }
+
+  return NULL;
+}
+
+static guint (*_egg_counter_getcpu_vdso_raw) (int *cpu,
+                                              int *node,
+                                              void *tcache);
+
+static guint
+_egg_counter_getcpu_vdso_helper (void)
+{
+  int cpu;
+  _egg_counter_getcpu_vdso_raw (&cpu, NULL, NULL);
+  return cpu;
+}
+#endif
+
+static guint
+_egg_counter_getcpu_fallback (void)
+{
+  return 0;
+}
+
+#ifdef EGG_HAVE_RDTSCP
+static guint
+_egg_counter_getcpu_rdtscp (void)
+{
+  return egg_get_current_cpu_rdtscp ();
+}
+#endif
+
+static void
+_egg_counter_init_getcpu (void)
+{
+
+#ifdef EGG_HAVE_RDTSCP
+  _egg_counter_getcpu_helper = _egg_counter_getcpu_rdtscp;
+#endif
+
+#ifdef __linux__
+  _egg_counter_getcpu_vdso_raw = _egg_counter_find_getcpu_in_vdso ();
+
+  if (_egg_counter_getcpu_vdso_raw)
+    {
+      _egg_counter_getcpu_helper = _egg_counter_getcpu_vdso_helper;
+      return;
+    }
+#endif
+
+#ifdef HAVE_SCHED_GETCPU
+  _egg_counter_getcpu_helper = (guint (*) (void))sched_getcpu;
+#endif
+
+  _egg_counter_getcpu_helper = _egg_counter_getcpu_fallback;
+}
+
+guint
+egg_get_current_cpu_call (void)
+{
+  return _egg_counter_getcpu_helper ();
+}
diff --git a/contrib/egg/egg-counter.h b/contrib/egg/egg-counter.h
index ca27fe8..9448857 100644
--- a/contrib/egg/egg-counter.h
+++ b/contrib/egg/egg-counter.h
@@ -123,7 +123,7 @@
  *
  * We need to know if rdtscp is available at compile time. In an effort
  * to keep the headers as portable as possible (if that matters here?) we
- * require that you define HAVE_RDTSCP if the instruction is supported.
+ * require that you define EGG_HAVE_RDTSCP if the instruction is supported.
  *
  * An example for autoconf might be similar to the following:
  *
@@ -136,15 +136,15 @@
  *     [have_rdtscp=no])
  *   AC_MSG_RESULT([$have_rdtscp])
  *   AS_IF([test "$have_rdtscp" = "yes"],
- *         [CFLAGS="$CFLAGS -DHAVE_RDTSCP"])
+ *         [CFLAGS="$CFLAGS -DEGG_HAVE_RDTSCP"])
  */
 
 G_BEGIN_DECLS
 
-#ifdef HAVE_RDTSCP
+#ifdef EGG_HAVE_RDTSCP
 # include <x86intrin.h>
   static inline guint
-  egg_get_current_cpu (void)
+  egg_get_current_cpu_rdtscp (void)
   {
     /*
      * This extracts the IA32_TSC_AUX into the ecx register. On Linux,
@@ -155,12 +155,10 @@ G_BEGIN_DECLS
     __builtin_ia32_rdtscp (&aux);
     return aux & 0xFFF;
   }
+# define egg_get_current_cpu() egg_get_current_cpu_rdtscp()
 #elif defined(__linux__)
-# ifndef _GNU_SOURCE
-#  define _GNU_SOURCE
-# endif
-# include <sched.h>
-# define egg_get_current_cpu() sched_getcpu()
+# define egg_get_current_cpu() egg_get_current_cpu_call()
+extern guint egg_get_current_cpu_call (void);
 #else
 # define egg_get_current_cpu() 0
 # define EGG_COUNTER_REQUIRES_ATOMIC 1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]