rcuja: add multithread test
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 29 Aug 2012 05:13:24 +0000 (22:13 -0700)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 14 May 2013 14:22:23 +0000 (16:22 +0200)
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
rcuja/rcuja-internal.h
tests/test_urcu_ja.c

index 82ab158a7a95bd4f116987098c4e371040484190..6b8da15a1a6131b249c3f70e3d3a45b3df99716d 100644 (file)
@@ -159,7 +159,7 @@ struct cds_lfht *rcuja_create_ht(const struct rcu_flavor_struct *flavor);
 __attribute__((visibility("protected")))
 int rcuja_delete_ht(struct cds_lfht *ht);
 
-#define DEBUG
+//#define DEBUG
 
 #ifdef DEBUG
 #define dbg_printf(fmt, args...)     printf("[debug rcuja] " fmt, ## args)
index 5244754d7b364b0c34af5d924e215e0e1a85e60c..b3e6ed078fca822e23ec5f290762f5307af365ad 100644 (file)
@@ -52,6 +52,8 @@ unsigned long init_pool_size = DEFAULT_RAND_POOL,
        lookup_pool_size = DEFAULT_RAND_POOL,
        write_pool_size = DEFAULT_RAND_POOL;
 int validate_lookup;
+int sanity_test;
+unsigned int key_bits = 32;
 
 int count_pipe[2];
 
@@ -170,6 +172,8 @@ printf("        [not -u nor -s] Add entries (supports redundant keys).\n");
        printf("        [-N size] Write pool size.\n");
        printf("        [-O size] Init pool size.\n");
        printf("        [-V] Validate lookups of init values (use with filled init pool, same lookup range, with different write range).\n");
+       printf("        [-s] Do sanity test.\n");
+       printf("        [-B] Key bits for multithread test (default: 32).\n");
        printf("\n\n");
 }
 
@@ -508,19 +512,336 @@ int test_sparse_key(unsigned int bits, int nr_dup)
        return 0;
 }
 
+static
+int do_sanity_test(void)
+{
+       int i, j, ret;
 
-int main(int argc, char **argv)
+       printf("Sanity test start.\n");
+
+       for (i = 0; i < 3; i++) {
+               ret = test_8bit_key();
+               if (ret) {
+                       return ret;
+               }
+               rcu_quiescent_state();
+       }
+       ret = test_16bit_key();
+       if (ret) {
+               return ret;
+       }
+       rcu_quiescent_state();
+
+       /* key bits */
+       for (i = 8; i <= 64; i *= 2) {
+               /* nr of nodes per key */
+               for (j = 1; j < 4; j++) {
+                       ret = test_sparse_key(i, j);
+                       if (ret) {
+                               return ret;
+                       }
+                       rcu_quiescent_state();
+               }
+       }
+       printf("Sanity test end.\n");
+
+       return 0;
+}
+
+enum urcu_ja_addremove {
+       AR_RANDOM = 0,
+       AR_ADD = 1,
+       AR_REMOVE = -1,
+};     /* 1: add, -1 remove, 0: random */
+
+static enum urcu_ja_addremove addremove; /* 1: add, -1 remove, 0: random */
+
+static
+void test_ja_rw_sigusr1_handler(int signo)
+{
+       switch (addremove) {
+       case AR_ADD:
+               printf("Add/Remove: random.\n");
+               addremove = AR_RANDOM;
+               break;
+       case AR_RANDOM:
+               printf("Add/Remove: remove only.\n");
+               addremove = AR_REMOVE;
+               break;
+       case AR_REMOVE:
+               printf("Add/Remove: add only.\n");
+               addremove = AR_ADD;
+               break;
+       }
+}
+
+static
+void *test_ja_rw_thr_reader(void *_count)
+{
+       unsigned long long *count = _count;
+       struct cds_hlist_head head;
+       uint64_t key;
+
+       printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
+                       "reader", pthread_self(), (unsigned long) gettid());
+
+       set_affinity();
+
+       rcu_register_thread();
+
+       while (!test_go)
+       {
+       }
+       cmm_smp_mb();
+
+       for (;;) {
+               rcu_read_lock();
+
+               /* note: only looking up ulong keys */
+               key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset;
+               head = cds_ja_lookup(test_ja, key);
+               if (cds_hlist_empty(&head)) {
+                       if (validate_lookup) {
+                               printf("[ERROR] Lookup cannot find initial node.\n");
+                               exit(-1);
+                       }
+                       URCU_TLS(lookup_fail)++;
+               } else {
+                       URCU_TLS(lookup_ok)++;
+               }
+               debug_yield_read();
+               if (caa_unlikely(rduration))
+                       loop_sleep(rduration);
+               rcu_read_unlock();
+               URCU_TLS(nr_reads)++;
+               if (caa_unlikely(!test_duration_read()))
+                       break;
+               if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
+                       rcu_quiescent_state();
+       }
+
+       rcu_unregister_thread();
+
+       *count = URCU_TLS(nr_reads);
+       printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
+                       "reader", pthread_self(), (unsigned long) gettid());
+       printf_verbose("readid : %lx, lookupfail %lu, lookupok %lu\n",
+                       pthread_self(), URCU_TLS(lookup_fail),
+                       URCU_TLS(lookup_ok));
+       return ((void*)1);
+}
+
+static
+void *test_ja_rw_thr_writer(void *_count)
+{
+       struct wr_count *count = _count;
+       struct cds_hlist_head head;
+       uint64_t key;
+       int ret;
+
+       printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
+                       "writer", pthread_self(), (unsigned long) gettid());
+
+       set_affinity();
+
+       rcu_register_thread();
+
+       while (!test_go)
+       {
+       }
+       cmm_smp_mb();
+
+       for (;;) {
+               if ((addremove == AR_ADD || add_only)
+                               || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
+                       struct ja_test_node *node = malloc(sizeof(*node));
+
+                       /* note: only inserting ulong keys */
+                       key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
+                       ja_test_node_init(node, key);
+                       rcu_read_lock();
+                       ret = cds_ja_add(test_ja, key, &node->node);
+                       URCU_TLS(nr_add)++;
+                       rcu_read_unlock();
+                       if (ret) {
+                               fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+                                       ret, key);
+                               assert(0);
+                       }
+               } else {
+                       struct ja_test_node *node;
+
+                       /* May delete */
+                       /* note: only deleting ulong keys */
+                       key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
+
+                       rcu_read_lock();
+
+                       head = cds_ja_lookup(test_ja, key);
+                       node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
+                       if (node) {
+                               ret = cds_ja_del(test_ja, key, &node->node);
+                               if (ret) {
+                                       call_rcu(&node->node.head, free_node_cb);
+                                       URCU_TLS(nr_delnoent)++;
+                               } else {
+                                       URCU_TLS(nr_del)++;
+                               }
+                       } else {
+                               URCU_TLS(nr_delnoent)++;
+                       }
+               }
+
+               URCU_TLS(nr_writes)++;
+               if (caa_unlikely(!test_duration_write()))
+                       break;
+               if (caa_unlikely(wdelay))
+                       loop_sleep(wdelay);
+               if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
+                       rcu_quiescent_state();
+       }
+
+       rcu_unregister_thread();
+
+       printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
+                       "writer", pthread_self(), (unsigned long) gettid());
+       printf_verbose("info id %lx: nr_add %lu, nr_addexist %lu, nr_del %lu, "
+                       "nr_delnoent %lu\n", pthread_self(), URCU_TLS(nr_add),
+                       URCU_TLS(nr_addexist), URCU_TLS(nr_del),
+                       URCU_TLS(nr_delnoent));
+       count->update_ops = URCU_TLS(nr_writes);
+       count->add = URCU_TLS(nr_add);
+       count->add_exist = URCU_TLS(nr_addexist);
+       count->remove = URCU_TLS(nr_del);
+       return ((void*)2);
+}
+
+static
+int do_mt_populate_ja(void)
+{
+       struct cds_hlist_head head;
+       uint64_t key;
+       int ret;
+
+       if (!init_populate)
+               return 0;
+
+       printf("Starting rw test\n");
+
+       for (key = init_pool_offset; key < init_pool_offset + init_pool_size; key++) {
+               struct ja_test_node *node = malloc(sizeof(*node));
+
+               /* note: only inserting ulong keys */
+               key = (unsigned long) key;
+               ja_test_node_init(node, key);
+               rcu_read_lock();
+               ret = cds_ja_add(test_ja, key, &node->node);
+               URCU_TLS(nr_add)++;
+               URCU_TLS(nr_writes)++;
+               rcu_read_unlock();
+               if (ret) {
+                       fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+                               ret, key);
+                       assert(0);
+               }
+       }
+       return 0;
+}
+
+static
+int do_mt_test(void)
 {
-       int err;
        pthread_t *tid_reader, *tid_writer;
        void *tret;
+       int ret, i, err;
        unsigned long long *count_reader;
        struct wr_count *count_writer;
        unsigned long long tot_reads = 0, tot_writes = 0,
                tot_add = 0, tot_add_exist = 0, tot_remove = 0;
-       int i, j, a, ret;
        unsigned int remain;
+
+       tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
+       tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
+       count_reader = malloc(sizeof(*count_reader) * nr_readers);
+       count_writer = malloc(sizeof(*count_writer) * nr_writers);
+
+       printf("Allocating Judy Array for %u-bit keys\n", key_bits);
+       test_ja = cds_ja_new(key_bits);
+       if (!test_ja) {
+               printf("Error allocating judy array.\n");
+               ret = -1;
+               goto end;
+       }
+
+       do_mt_populate_ja();
+
+       next_aff = 0;
+
+       for (i = 0; i < nr_readers; i++) {
+               err = pthread_create(&tid_reader[i],
+                                    NULL, test_ja_rw_thr_reader,
+                                    &count_reader[i]);
+               if (err != 0)
+                       exit(1);
+       }
+       for (i = 0; i < nr_writers; i++) {
+               err = pthread_create(&tid_writer[i],
+                                    NULL, test_ja_rw_thr_writer,
+                                    &count_writer[i]);
+               if (err != 0)
+                       exit(1);
+       }
+
+       cmm_smp_mb();
+
+       test_go = 1;
+
+       rcu_thread_offline_qsbr();
+
+       remain = duration;
+       do {
+               remain = sleep(remain);
+       } while (remain > 0);
+
+       test_stop = 1;
+
+       for (i = 0; i < nr_readers; i++) {
+               err = pthread_join(tid_reader[i], &tret);
+               if (err != 0)
+                       exit(1);
+               tot_reads += count_reader[i];
+       }
+       for (i = 0; i < nr_writers; i++) {
+               err = pthread_join(tid_writer[i], &tret);
+               if (err != 0)
+                       exit(1);
+               tot_writes += count_writer[i].update_ops;
+               tot_add += count_writer[i].add;
+               tot_add_exist += count_writer[i].add_exist;
+               tot_remove += count_writer[i].remove;
+       }
+
+       ret = cds_ja_destroy(test_ja, free_node_cb);
+       if (ret) {
+               fprintf(stderr, "Error destroying judy array\n");
+               goto end;
+       }
+       rcu_thread_online_qsbr();
+
+       free(tid_reader);
+       free(tid_writer);
+       free(count_reader);
+       free(count_writer);
+       ret = 0;
+end:
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       int i, j, a, ret, err;
        uint64_t key;
+       struct sigaction act;
 
        if (argc < 4) {
                show_usage(argc, argv);
@@ -611,6 +932,12 @@ int main(int argc, char **argv)
                case 'V':
                        validate_lookup = 1;
                        break;
+               case 's':
+                       sanity_test = 1;
+                       break;
+               case 'B':
+                       key_bits = atol(argv[++i]);
+                       break;
                }
        }
 
@@ -629,10 +956,19 @@ int main(int argc, char **argv)
        printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
                        "main", pthread_self(), (unsigned long)gettid());
 
-       tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
-       tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
-       count_reader = malloc(sizeof(*count_reader) * nr_readers);
-       count_writer = malloc(sizeof(*count_writer) * nr_writers);
+       memset(&act, 0, sizeof(act));
+       ret = sigemptyset(&act.sa_mask);
+       if (ret == -1) {
+               perror("sigemptyset");
+               return -1;
+       }
+       act.sa_handler = test_ja_rw_sigusr1_handler;
+       act.sa_flags = SA_RESTART;
+       ret = sigaction(SIGUSR1, &act, NULL);
+       if (ret == -1) {
+               perror("sigaction");
+               return -1;
+       }
 
        err = create_all_cpu_call_rcu_data(0);
        if (err) {
@@ -641,35 +977,17 @@ int main(int argc, char **argv)
 
        rcu_register_thread();
 
-       printf("Test start.\n");
-
-       for (i = 0; i < 3; i++) {
-               ret = test_8bit_key();
+       if (sanity_test) {
+               ret = do_sanity_test();
                if (ret) {
-                       return ret;
+                       fprintf(stderr, "Error in sanity test\n");
                }
-               rcu_quiescent_state();
+       } else {
+               do_mt_test();
        }
-       ret = test_16bit_key();
-       if (ret) {
-               return ret;
-       }
-       rcu_quiescent_state();
 
-       /* key bits */
-       for (i = 8; i <= 64; i *= 2) {
-               /* nr of nodes per key */
-               for (j = 1; j < 4; j++) {
-                       ret = test_sparse_key(i, j);
-                       if (ret) {
-                               return ret;
-                       }
-                       rcu_quiescent_state();
-               }
-       }
-
-       printf("Test end.\n");
        rcu_unregister_thread();
+       free_all_cpu_call_rcu_data();
        return 0;
 
 #if 0
@@ -683,50 +1001,6 @@ int main(int argc, char **argv)
 
        rcu_thread_offline();
 
-       next_aff = 0;
-
-       for (i = 0; i < nr_readers; i++) {
-               err = pthread_create(&tid_reader[i],
-                                    NULL, get_thr_reader_cb(),
-                                    &count_reader[i]);
-               if (err != 0)
-                       exit(1);
-       }
-       for (i = 0; i < nr_writers; i++) {
-               err = pthread_create(&tid_writer[i],
-                                    NULL, get_thr_writer_cb(),
-                                    &count_writer[i]);
-               if (err != 0)
-                       exit(1);
-       }
-
-       cmm_smp_mb();
-
-       test_go = 1;
-
-       remain = duration;
-       do {
-               remain = sleep(remain);
-       } while (remain > 0);
-
-       test_stop = 1;
-
-       for (i = 0; i < nr_readers; i++) {
-               err = pthread_join(tid_reader[i], &tret);
-               if (err != 0)
-                       exit(1);
-               tot_reads += count_reader[i];
-       }
-       for (i = 0; i < nr_writers; i++) {
-               err = pthread_join(tid_writer[i], &tret);
-               if (err != 0)
-                       exit(1);
-               tot_writes += count_writer[i].update_ops;
-               tot_add += count_writer[i].add;
-               tot_add_exist += count_writer[i].add_exist;
-               tot_remove += count_writer[i].remove;
-       }
-
        /* teardown counter thread */
        act.sa_handler = SIG_IGN;
        act.sa_flags = SA_RESTART;
@@ -778,11 +1052,6 @@ int main(int argc, char **argv)
                tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
                (long long) tot_add + init_populate - tot_remove - count);
        rcu_unregister_thread();
-       free_all_cpu_call_rcu_data();
-       free(tid_reader);
-       free(tid_writer);
-       free(count_reader);
-       free(count_writer);
 #endif
        return 0;
 }
This page took 0.031783 seconds and 4 git commands to generate.