Enhance test cases
authorMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Tue, 10 Feb 2009 18:57:53 +0000 (13:57 -0500)
committerMathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Tue, 10 Feb 2009 18:57:53 +0000 (13:57 -0500)
New -n (to disable sleep in writer)
Now use a random delay for -w and -r.
Add -DDEBUG_FULL_MB option to use mb() in the reader rather than the
signal-based alternative.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Makefile
test_urcu.c
urcu.c
urcu.h

index 4b5f24efe94ccc05895e591bfbf8b8904269245a..2a044676efe94bb7f76a920da25b86302eb498dd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,10 @@
 
-CFLAGS=-Wall -O2
+CFLAGS=-Wall -O2 -g
+LDFLAGS=-lpthread
+
 #debug
 #CFLAGS=-Wall -g
-LDFLAGS=-lpthread
+#CFLAGS+=-DDEBUG_FULL_MB
 
 SRC_DEP=`echo $^ | sed 's/[^ ]*.h//g'`
 
index b92a7d74de5c23fd55d5959e8e5f514d314ef090..73fbc4e204e13b032a5830e9149974f32ff7cd19 100644 (file)
@@ -40,6 +40,8 @@ struct test_array {
        int a;
 };
 
+static int no_writer_delay;
+
 static struct test_array *test_rcu_pointer;
 
 static unsigned long duration;
@@ -86,6 +88,42 @@ void rcu_copy_mutex_unlock(void)
        }
 }
 
+/*
+ * malloc/free are reusing memory areas too quickly, which does not let us
+ * test races appropriately. Use a large circular array for allocations.
+ * ARRAY_SIZE is larger than NR_WRITE, which insures we never run over our tail.
+ */
+#define ARRAY_SIZE (1048576 * NR_WRITE)
+#define ARRAY_POISON 0xDEADBEEF
+static int array_index;
+static struct test_array test_array[ARRAY_SIZE];
+
+static struct test_array *test_array_alloc(void)
+{
+       struct test_array *ret;
+       int index;
+
+       rcu_copy_mutex_lock();
+       index = array_index % ARRAY_SIZE;
+       assert(test_array[index].a == ARRAY_POISON ||
+               test_array[index].a == 0);
+       ret = &test_array[index];
+       array_index++;
+       if (array_index == ARRAY_SIZE)
+               array_index = 0;
+       rcu_copy_mutex_unlock();
+       return ret;
+}
+
+static void test_array_free(struct test_array *ptr)
+{
+       if (!ptr)
+               return;
+       rcu_copy_mutex_lock();
+       ptr->a = ARRAY_POISON;
+       rcu_copy_mutex_unlock();
+}
+
 void *thr_reader(void *arg)
 {
        struct test_array *local_ptr;
@@ -98,6 +136,7 @@ void *thr_reader(void *arg)
        for (;;) {
                rcu_read_lock();
                local_ptr = rcu_dereference(test_rcu_pointer);
+               debug_yield_read();
                if (local_ptr)
                        assert(local_ptr->a == 8);
                rcu_read_unlock();
@@ -121,7 +160,7 @@ void *thr_writer(void *arg)
                        "writer", pthread_self(), (unsigned long)gettid());
 
        for (;;) {
-               new = malloc(sizeof(struct test_array));
+               new = test_array_alloc();
                rcu_copy_mutex_lock();
                old = test_rcu_pointer;
                if (old)
@@ -132,10 +171,11 @@ void *thr_writer(void *arg)
                /* can be done after unlock */
                if (old)
                        old->a = 0;
-               free(old);
+               test_array_free(old);
                if (!test_duration())
                        break;
-               usleep(1);
+               if (!no_writer_delay)
+                       usleep(1);
        }
 
        printf("thread_end %s, thread id : %lx, tid %lu\n",
@@ -149,6 +189,7 @@ void show_usage(int argc, char **argv)
 #ifdef DEBUG_YIELD
        printf(" [-r] [-w] (yield reader and/or writer)");
 #endif
+       printf(" [-n] (disable writer delay)");
        printf("\n");
 }
 
@@ -170,20 +211,23 @@ int main(int argc, char **argv)
                return -1;
        }
 
-#ifdef DEBUG_YIELD
        for (i = 2; i < argc; i++) {
                if (argv[i][0] != '-')
                        continue;
                switch (argv[i][1]) {
+#ifdef DEBUG_YIELD
                case 'r':
                        yield_active |= YIELD_READ;
                        break;
                case 'w':
                        yield_active |= YIELD_WRITE;
                        break;
+#endif
+               case 'n':
+                       no_writer_delay = 1;
+                       break;
                }
        }
-#endif
 
        printf("running test for %lu seconds.\n", duration);
        start_time = time(NULL);
@@ -211,7 +255,7 @@ int main(int argc, char **argv)
                if (err != 0)
                        exit(1);
        }
-       free(test_rcu_pointer);
+       test_array_free(test_rcu_pointer);
 
        return 0;
 }
diff --git a/urcu.c b/urcu.c
index d4a06844885cde3da2d03092e3e9c45a939e0438..ac1a4d6c9314499d339fdd2a939479ec96deed5f 100644 (file)
--- a/urcu.c
+++ b/urcu.c
@@ -74,6 +74,12 @@ static void switch_next_urcu_qparity(void)
        urcu_gp_ctr ^= RCU_GP_CTR_BIT;
 }
 
+#ifdef DEBUG_FULL_MB
+static void force_mb_all_threads(void)
+{
+       mb();
+}
+#else
 static void force_mb_all_threads(void)
 {
        struct reader_data *index;
@@ -102,6 +108,7 @@ static void force_mb_all_threads(void)
        mb();   /* read sig_done before ending the barrier */
        debug_yield_write();
 }
+#endif
 
 void wait_for_quiescent_state(void)
 {
@@ -217,6 +224,7 @@ void urcu_unregister_thread(void)
        internal_urcu_unlock();
 }
 
+#ifndef DEBUG_FULL_MB
 void sigurcu_handler(int signo, siginfo_t *siginfo, void *context)
 {
        mb();
@@ -249,3 +257,4 @@ void __attribute__((destructor)) urcu_exit(void)
        assert(act.sa_sigaction == sigurcu_handler);
        free(reader_data);
 }
+#endif
diff --git a/urcu.h b/urcu.h
index 277b7d2f45ae565610e4db9ee89457174fafa667..03764ab33dbe241b643b72ef9cbfd6757662fa3b 100644 (file)
--- a/urcu.h
+++ b/urcu.h
@@ -121,10 +121,19 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
 #include <sched.h>
 #include <time.h>
 #include <pthread.h>
+#include <unistd.h>
 
 #define YIELD_READ     (1 << 0)
 #define YIELD_WRITE    (1 << 1)
 
+/* Updates without DEBUG_FULL_MB are much slower. Account this in the delay */
+#ifdef DEBUG_FULL_MB
+/* maximum sleep delay, in us */
+#define MAX_SLEEP 50
+#else
+#define MAX_SLEEP 30000
+#endif
+
 extern unsigned int yield_active;
 extern unsigned int __thread rand_yield;
 
@@ -132,14 +141,14 @@ static inline void debug_yield_read(void)
 {
        if (yield_active & YIELD_READ)
                if (rand_r(&rand_yield) & 0x1)
-                       sched_yield();
+                       usleep(rand_r(&rand_yield) % MAX_SLEEP);
 }
 
 static inline void debug_yield_write(void)
 {
        if (yield_active & YIELD_WRITE)
                if (rand_r(&rand_yield) & 0x1)
-                       sched_yield();
+                       usleep(rand_r(&rand_yield) % MAX_SLEEP);
 }
 
 static inline void debug_yield_init(void)
@@ -161,6 +170,18 @@ static inline void debug_yield_init(void)
 }
 #endif
 
+#ifdef DEBUG_FULL_MB
+static inline void read_barrier()
+{
+       mb();
+}
+#else
+static inline void read_barrier()
+{
+       barrier();
+}
+#endif
+
 /*
  * The trick here is that RCU_GP_CTR_BIT must be a multiple of 8 so we can use a
  * full 8-bits, 16-bits or 32-bits bitmask for the lower order bits.
@@ -209,14 +230,14 @@ static inline void rcu_read_lock(void)
         * Increment active readers count before accessing the pointer.
         * See force_mb_all_threads().
         */
-       barrier();
+       read_barrier();
        debug_yield_read();
 }
 
 static inline void rcu_read_unlock(void)
 {
        debug_yield_read();
-       barrier();
+       read_barrier();
        debug_yield_read();
        /*
         * Finish using rcu before decrementing the pointer.
This page took 0.02955 seconds and 4 git commands to generate.