optimise bitlocks with new atomic operations
authorRyan Lortie <desrt@desrt.ca>
Sat, 28 May 2011 20:41:59 +0000 (16:41 -0400)
committerRyan Lortie <desrt@desrt.ca>
Sat, 28 May 2011 21:39:12 +0000 (17:39 -0400)
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
glib/tests/Makefile.am
glib/tests/bitlock.c [new file with mode: 0644]

index 72e0d6e..4e91e9a 100644 (file)
@@ -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);
index 29e706e..39816e5 100644 (file)
@@ -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 (file)
index 0000000..694fe6d
--- /dev/null
@@ -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 ();
+}