Build and run regression and unit tests as C++ programs
[urcu.git] / tests / regression / rcutorture.h
index a2411d76403dc9dc051109bfef369ce56ed9a404..639fcfc19cb2bfe33f765629dd233af04e35267d 100644 (file)
  */
 
 #include <stdlib.h>
+#include "tap.h"
+
+#define NR_TESTS       1
 
 DEFINE_PER_THREAD(long long, n_reads_pt);
 DEFINE_PER_THREAD(long long, n_updates_pt);
 
+enum callrcu_type {
+       CALLRCU_GLOBAL,
+       CALLRCU_PERCPU,
+       CALLRCU_PERTHREAD,
+};
+
+static enum callrcu_type callrcu_type = CALLRCU_GLOBAL;
+
 long long n_reads = 0LL;
 long n_updates = 0L;
 int nthreadsrunning;
@@ -102,13 +113,13 @@ volatile int goflag __attribute__((__aligned__(CAA_CACHE_LINE_SIZE)))
 #endif
 
 #ifndef mark_rcu_quiescent_state
-#define mark_rcu_quiescent_state() do ; while (0)
+#define mark_rcu_quiescent_state() do {} while (0)
 #endif /* #ifdef mark_rcu_quiescent_state */
 
 #ifndef put_thread_offline
-#define put_thread_offline()           do ; while (0)
-#define put_thread_online()            do ; while (0)
-#define put_thread_online_delay()      do ; while (0)
+#define put_thread_offline()           do {} while (0)
+#define put_thread_online()            do {} while (0)
+#define put_thread_online_delay()      do {} while (0)
 #else /* #ifndef put_thread_offline */
 #define put_thread_online_delay()      synchronize_rcu()
 #endif /* #else #ifndef put_thread_offline */
@@ -117,9 +128,9 @@ volatile int goflag __attribute__((__aligned__(CAA_CACHE_LINE_SIZE)))
  * Performance test.
  */
 
+static
 void *rcu_read_perf_test(void *arg)
 {
-       struct call_rcu_data *crdp;
        int i;
        int me = (long)arg;
        long long n_reads_local = 0;
@@ -143,25 +154,22 @@ void *rcu_read_perf_test(void *arg)
        }
        __get_thread_var(n_reads_pt) += n_reads_local;
        put_thread_offline();
-       crdp = get_thread_call_rcu_data();
-       set_thread_call_rcu_data(NULL);
-       call_rcu_data_free(crdp);
        rcu_unregister_thread();
 
        return (NULL);
 }
 
-void *rcu_update_perf_test(void *arg)
+static
+void *rcu_update_perf_test(void *arg __attribute__((unused)))
 {
        long long n_updates_local = 0;
 
-       if ((random() & 0xf00) == 0) {
+       if (callrcu_type == CALLRCU_PERTHREAD) {
                struct call_rcu_data *crdp;
 
                crdp = create_call_rcu_data(0, -1);
                if (crdp != NULL) {
-                       fprintf(stderr,
-                               "Using per-thread call_rcu() worker.\n");
+                       diag("Successfully using per-thread call_rcu() worker.");
                        set_thread_call_rcu_data(crdp);
                }
        }
@@ -173,9 +181,17 @@ void *rcu_update_perf_test(void *arg)
                n_updates_local++;
        }
        __get_thread_var(n_updates_pt) += n_updates_local;
+       if (callrcu_type == CALLRCU_PERTHREAD) {
+               struct call_rcu_data *crdp;
+
+               crdp = get_thread_call_rcu_data();
+               set_thread_call_rcu_data(NULL);
+               call_rcu_data_free(crdp);
+       }
        return NULL;
 }
 
+static
 void perftestinit(void)
 {
        init_per_thread(n_reads_pt, 0LL);
@@ -183,7 +199,8 @@ void perftestinit(void)
        uatomic_set(&nthreadsrunning, 0);
 }
 
-void perftestrun(int nthreads, int nreaders, int nupdaters)
+static
+int perftestrun(int nthreads, int nreaders, int nupdaters)
 {
        int t;
        int duration = 1;
@@ -202,21 +219,22 @@ void perftestrun(int nthreads, int nreaders, int nupdaters)
                n_reads += per_thread(n_reads_pt, t);
                n_updates += per_thread(n_updates_pt, t);
        }
-       printf("n_reads: %lld  n_updates: %ld  nreaders: %d  nupdaters: %d duration: %d\n",
+       diag("n_reads: %lld  n_updates: %ld  nreaders: %d  nupdaters: %d duration: %d",
               n_reads, n_updates, nreaders, nupdaters, duration);
-       printf("ns/read: %g  ns/update: %g\n",
+       diag("ns/read: %g  ns/update: %g",
               ((duration * 1000*1000*1000.*(double)nreaders) /
                (double)n_reads),
               ((duration * 1000*1000*1000.*(double)nupdaters) /
                (double)n_updates));
        if (get_cpu_call_rcu_data(0)) {
-               fprintf(stderr, "Deallocating per-CPU call_rcu threads.\n");
+               diag("Deallocating per-CPU call_rcu threads.\n");
                free_all_cpu_call_rcu_data();
        }
-       exit(0);
+       return 0;
 }
 
-void perftest(int nreaders, int cpustride)
+static
+int perftest(int nreaders, int cpustride)
 {
        int i;
        long arg;
@@ -228,10 +246,11 @@ void perftest(int nreaders, int cpustride)
        }
        arg = (long)(i * cpustride);
        create_thread(rcu_update_perf_test, (void *)arg);
-       perftestrun(i + 1, nreaders, 1);
+       return perftestrun(i + 1, nreaders, 1);
 }
 
-void rperftest(int nreaders, int cpustride)
+static
+int rperftest(int nreaders, int cpustride)
 {
        int i;
        long arg;
@@ -242,10 +261,11 @@ void rperftest(int nreaders, int cpustride)
                arg = (long)(i * cpustride);
                create_thread(rcu_read_perf_test, (void *)arg);
        }
-       perftestrun(i, nreaders, 0);
+       return perftestrun(i, nreaders, 0);
 }
 
-void uperftest(int nupdaters, int cpustride)
+static
+int uperftest(int nupdaters, int cpustride)
 {
        int i;
        long arg;
@@ -256,7 +276,7 @@ void uperftest(int nupdaters, int cpustride)
                arg = (long)(i * cpustride);
                create_thread(rcu_update_perf_test, (void *)arg);
        }
-       perftestrun(i, 0, nupdaters);
+       return perftestrun(i, 0, nupdaters);
 }
 
 /*
@@ -270,7 +290,7 @@ struct rcu_stress {
        int mbtest;
 };
 
-struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0 } };
+struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0, 0 } };
 struct rcu_stress *rcu_stress_current;
 int rcu_stress_idx = 0;
 
@@ -279,7 +299,8 @@ DEFINE_PER_THREAD(long long [RCU_STRESS_PIPE_LEN + 1], rcu_stress_count);
 
 int garbage = 0;
 
-void *rcu_read_stress_test(void *arg)
+static
+void *rcu_read_stress_test(void *arg __attribute__((unused)))
 {
        int i;
        int itercnt = 0;
@@ -322,23 +343,36 @@ void *rcu_read_stress_test(void *arg)
 static pthread_mutex_t call_rcu_test_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t call_rcu_test_cond = PTHREAD_COND_INITIALIZER;
 
-void rcu_update_stress_test_rcu(struct rcu_head *head)
+static
+void rcu_update_stress_test_rcu(struct rcu_head *head __attribute__((unused)))
 {
-       if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) {
-               perror("pthread_mutex_lock");
-               exit(-1);
+       int ret;
+
+       ret = pthread_mutex_lock(&call_rcu_test_mutex);
+       if (ret) {
+               errno = ret;
+               diag("pthread_mutex_lock: %s",
+                       strerror(errno));
+               abort();
        }
-       if (pthread_cond_signal(&call_rcu_test_cond) != 0) {
-               perror("pthread_cond_signal");
-               exit(-1);
+       ret = pthread_cond_signal(&call_rcu_test_cond);
+       if (ret) {
+               errno = ret;
+               diag("pthread_cond_signal: %s",
+                       strerror(errno));
+               abort();
        }
-       if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) {
-               perror("pthread_mutex_unlock");
-               exit(-1);
+       ret = pthread_mutex_unlock(&call_rcu_test_mutex);
+       if (ret) {
+               errno = ret;
+               diag("pthread_mutex_unlock: %s",
+                       strerror(errno));
+               abort();
        }
 }
 
-void *rcu_update_stress_test(void *arg)
+static
+void *rcu_update_stress_test(void *arg __attribute__((unused)))
 {
        int i;
        struct rcu_stress *p;
@@ -363,35 +397,63 @@ void *rcu_update_stress_test(void *arg)
                if (n_updates & 0x1)
                        synchronize_rcu();
                else {
-                       if (pthread_mutex_lock(&call_rcu_test_mutex) != 0) {
-                               perror("pthread_mutex_lock");
-                               exit(-1);
+                       int ret;
+
+                       ret = pthread_mutex_lock(&call_rcu_test_mutex);
+                       if (ret) {
+                               errno = ret;
+                               diag("pthread_mutex_lock: %s",
+                                       strerror(errno));
+                               abort();
                        }
+                       rcu_register_thread();
                        call_rcu(&rh, rcu_update_stress_test_rcu);
-                       if (pthread_cond_wait(&call_rcu_test_cond,
-                                             &call_rcu_test_mutex) != 0) {
-                               perror("pthread_cond_wait");
-                               exit(-1);
+                       rcu_unregister_thread();
+                       /*
+                        * Our MacOS X test machine with the following
+                        * config:
+                        * 15.6.0 Darwin Kernel Version 15.6.0
+                        * root:xnu-3248.60.10~1/RELEASE_X86_64
+                        * appears to have issues with liburcu-signal
+                        * signal being delivered on top of
+                        * pthread_cond_wait. It seems to make the
+                        * thread continue, and therefore corrupt the
+                        * rcu_head. Work around this issue by
+                        * unregistering the RCU read-side thread
+                        * immediately after call_rcu (call_rcu needs
+                        * us to be registered RCU readers).
+                        */
+                       ret = pthread_cond_wait(&call_rcu_test_cond,
+                                       &call_rcu_test_mutex);
+                       if (ret) {
+                               errno = ret;
+                               diag("pthread_cond_signal: %s",
+                                       strerror(errno));
+                               abort();
                        }
-                       if (pthread_mutex_unlock(&call_rcu_test_mutex) != 0) {
-                               perror("pthread_mutex_unlock");
-                               exit(-1);
+                       ret = pthread_mutex_unlock(&call_rcu_test_mutex);
+                       if (ret) {
+                               errno = ret;
+                               diag("pthread_mutex_unlock: %s",
+                                       strerror(errno));
+                               abort();
                        }
                }
                n_updates++;
        }
+
        return NULL;
 }
 
-void *rcu_fake_update_stress_test(void *arg)
+static
+void *rcu_fake_update_stress_test(void *arg __attribute__((unused)))
 {
-       if ((random() & 0xf00) == 0) {
+       if (callrcu_type == CALLRCU_PERTHREAD) {
                struct call_rcu_data *crdp;
 
                crdp = create_call_rcu_data(0, -1);
                if (crdp != NULL) {
-                       fprintf(stderr,
-                               "Using per-thread call_rcu() worker.\n");
+                       diag("Successfully using per-thread call_rcu() worker.");
                        set_thread_call_rcu_data(crdp);
                }
        }
@@ -401,10 +463,18 @@ void *rcu_fake_update_stress_test(void *arg)
                synchronize_rcu();
                (void) poll(NULL, 0, 1);
        }
+       if (callrcu_type == CALLRCU_PERTHREAD) {
+               struct call_rcu_data *crdp;
+
+               crdp = get_thread_call_rcu_data();
+               set_thread_call_rcu_data(NULL);
+               call_rcu_data_free(crdp);
+       }
        return NULL;
 }
 
-void stresstest(int nreaders)
+static
+int stresstest(int nreaders)
 {
        int i;
        int t;
@@ -435,31 +505,39 @@ void stresstest(int nreaders)
        wait_all_threads();
        for_each_thread(t)
                n_reads += per_thread(n_reads_pt, t);
-       printf("n_reads: %lld  n_updates: %ld  n_mberror: %d\n",
+       diag("n_reads: %lld  n_updates: %ld  n_mberror: %d",
               n_reads, n_updates, n_mberror);
-       printf("rcu_stress_count:");
+       rdiag_start();
+       rdiag("rcu_stress_count:");
        for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) {
                sum = 0LL;
                for_each_thread(t) {
                        sum += per_thread(rcu_stress_count, t)[i];
                }
-               printf(" %lld", sum);
+               rdiag(" %lld", sum);
        }
-       printf("\n");
+       rdiag_end();
        if (get_cpu_call_rcu_data(0)) {
-               fprintf(stderr, "Deallocating per-CPU call_rcu threads.\n");
+               diag("Deallocating per-CPU call_rcu threads.");
                free_all_cpu_call_rcu_data();
        }
-       exit(0);
+       if (!n_mberror)
+               return 0;
+       else
+               return -1;
 }
 
 /*
  * Mainprogram.
  */
 
-void usage(int argc, char *argv[])
+static
+void usage(char *argv[]) __attribute__((noreturn));
+
+static
+void usage(char *argv[])
 {
-       fprintf(stderr, "Usage: %s [nreaders [ perf | stress ] ]\n", argv[0]);
+       diag("Usage: %s nreaders [ perf | rperf | uperf | stress ] [ stride ] [ callrcu_global | callrcu_percpu | callrcu_perthread ]\n", argv[0]);
        exit(-1);
 }
 
@@ -468,13 +546,40 @@ int main(int argc, char *argv[])
        int nreaders = 1;
        int cpustride = 1;
 
+       plan_tests(NR_TESTS);
+
        smp_init();
        //rcu_init();
-       srandom(time(NULL));
-       if (random() & 0x100) {
-               fprintf(stderr, "Allocating per-CPU call_rcu threads.\n");
+       if (argc > 4) {
+               const char *callrcu_str = argv[4];;
+
+               if (strcmp(callrcu_str, "callrcu_global") == 0) {
+                       callrcu_type = CALLRCU_GLOBAL;
+               } else if (strcmp(callrcu_str, "callrcu_percpu") == 0) {
+                       callrcu_type = CALLRCU_PERCPU;
+               } else if (strcmp(callrcu_str, "callrcu_perthread") == 0) {
+                       callrcu_type = CALLRCU_PERTHREAD;
+               } else {
+                       usage(argv);
+                       goto end;
+               }
+       }
+
+       switch (callrcu_type) {
+       case CALLRCU_GLOBAL:
+               diag("Using global per-process call_rcu thread.");
+               break;
+       case CALLRCU_PERCPU:
+               diag("Using per-CPU call_rcu threads.");
                if (create_all_cpu_call_rcu_data(0))
-                       perror("create_all_cpu_call_rcu_data");
+                       diag("create_all_cpu_call_rcu_data: %s",
+                               strerror(errno));
+               break;
+       case CALLRCU_PERTHREAD:
+               diag("Using per-thread call_rcu() worker.");
+               break;
+       default:
+               abort();
        }
 
 #ifdef DEBUG_YIELD
@@ -483,21 +588,41 @@ int main(int argc, char *argv[])
 #endif
 
        if (argc > 1) {
+               if (strcmp(argv[1], "-h") == 0
+                               || strcmp(argv[1], "--help") == 0) {
+                       usage(argv);
+                       goto end;
+               }
                nreaders = strtoul(argv[1], NULL, 0);
-               if (argc == 2)
-                       perftest(nreaders, cpustride);
+               if (argc == 2) {
+                       ok(!perftest(nreaders, cpustride),
+                               "perftest readers: %d, stride: %d",
+                               nreaders, cpustride);
+                       goto end;
+               }
                if (argc > 3)
                        cpustride = strtoul(argv[3], NULL, 0);
                if (strcmp(argv[2], "perf") == 0)
-                       perftest(nreaders, cpustride);
+                       ok(!perftest(nreaders, cpustride),
+                               "perftest readers: %d, stride: %d",
+                               nreaders, cpustride);
                else if (strcmp(argv[2], "rperf") == 0)
-                       rperftest(nreaders, cpustride);
+                       ok(!rperftest(nreaders, cpustride),
+                               "rperftest readers: %d, stride: %d",
+                               nreaders, cpustride);
                else if (strcmp(argv[2], "uperf") == 0)
-                       uperftest(nreaders, cpustride);
+                       ok(!uperftest(nreaders, cpustride),
+                               "uperftest readers: %d, stride: %d",
+                               nreaders, cpustride);
                else if (strcmp(argv[2], "stress") == 0)
-                       stresstest(nreaders);
-               usage(argc, argv);
+                       ok(!stresstest(nreaders),
+                               "stresstest readers: %d, stride: %d",
+                               nreaders, cpustride);
+               else
+                       usage(argv);
+       } else {
+               usage(argv);
        }
-       perftest(nreaders, cpustride);
-       return 0;
+end:
+       return exit_status();
 }
This page took 0.029326 seconds and 4 git commands to generate.