[glib] optimise bitlocks with new atomic operations



commit d09443fe20753fc44afd6ac25463ac52861701cb
Author: Ryan Lortie <desrt desrt ca>
Date:   Sat May 28 16:41:59 2011 -0400

    optimise bitlocks with new atomic operations
    
    Add a performance test for bitlocks.
    
    Make use of the new g_atomic_int_{and,or} to avoid having to do the
    usual compare-and-exchange loop.
    
    On a test machine, the change increases performance from approximately
    20 million uncontended acquire/releases per second to 31 million.

 glib/gbitlock.c        |   27 ++++++++-------------------
 glib/tests/Makefile.am |    3 +++
 glib/tests/bitlock.c   |   39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 19 deletions(-)
---
diff --git a/glib/gbitlock.c b/glib/gbitlock.c
index 72e0d6e..4e91e9a 100644
--- a/glib/gbitlock.c
+++ b/glib/gbitlock.c
@@ -205,11 +205,12 @@ void
 g_bit_lock (volatile gint *address,
             gint           lock_bit)
 {
+  guint mask = 1u << lock_bit;
   guint v;
 
  retry:
-  v = g_atomic_int_get (address);
-  if (v & (1u << lock_bit))
+  v = g_atomic_int_or (address, mask);
+  if (v & mask)
     /* already locked */
     {
       guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
@@ -220,9 +221,6 @@ g_bit_lock (volatile gint *address,
 
       goto retry;
     }
-
-  if (!g_atomic_int_compare_and_exchange (address, v, v | (1u << lock_bit)))
-    goto retry;
 }
 
 /**
@@ -250,18 +248,12 @@ gboolean
 g_bit_trylock (volatile gint *address,
                gint           lock_bit)
 {
+  guint mask = 1u << lock_bit;
   guint v;
 
- retry:
-  v = g_atomic_int_get (address);
-  if (v & (1u << lock_bit))
-    /* already locked */
-    return FALSE;
-
-  if (!g_atomic_int_compare_and_exchange (address, v, v | (1u << lock_bit)))
-    goto retry;
+  v = g_atomic_int_or (address, mask);
 
-  return TRUE;
+  return ~v & mask;
 }
 
 /**
@@ -284,12 +276,9 @@ g_bit_unlock (volatile gint *address,
               gint           lock_bit)
 {
   guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
-  guint v;
+  guint mask = 1u << lock_bit;
 
- retry:
-  v = g_atomic_int_get (address);
-  if (!g_atomic_int_compare_and_exchange (address, v, v & ~(1u << lock_bit)))
-    goto retry;
+  g_atomic_int_and (address, ~mask);
 
   if (g_atomic_int_get (&g_bit_lock_contended[class]))
     g_futex_wake (address);
diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am
index 29e706e..39816e5 100644
--- a/glib/tests/Makefile.am
+++ b/glib/tests/Makefile.am
@@ -181,6 +181,9 @@ noinst_PROGRAMS += atomic
 atomic_CFLAGS = -Wstrict-aliasing=2 $(INCLUDES)
 atomic_LDADD = $(progs_ldadd)
 
+TEST_PROGS    += bitlock
+bitlock_LDADD  = $(progs_ldadd)
+
 # some testing of gtester funcitonality
 XMLLINT=xmllint
 gtester-xmllint-check: # check testreport xml with xmllint if present
diff --git a/glib/tests/bitlock.c b/glib/tests/bitlock.c
new file mode 100644
index 0000000..694fe6d
--- /dev/null
+++ b/glib/tests/bitlock.c
@@ -0,0 +1,39 @@
+#include <glib.h>
+
+#define ITERATIONS 100000000
+
+static void
+test_bitlocks (void)
+{
+  guint64 start = g_get_monotonic_time ();
+  gint lock = 0;
+  gint i;
+
+  for (i = 0; i < ITERATIONS; i++)
+    {
+      g_bit_lock (&lock, 0);
+      g_bit_unlock (&lock, 0);
+    }
+
+  {
+    gdouble elapsed;
+    gdouble rate;
+
+    elapsed = g_get_monotonic_time () - start;
+    elapsed /= 1000000;
+    rate = ITERATIONS / elapsed;
+
+    g_test_maximized_result (rate, "iterations per second");
+  }
+}
+
+int
+main (int argc, char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+
+  if (g_test_perf ())
+    g_test_add_func ("/bitlock/performance/uncontended", test_bitlocks);
+
+  return g_test_run ();
+}



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