tests: use thread-id.h wrapper
[urcu.git] / tests / test_urcu_hash.c
index 3578cc9b2b121bb57dd916dd1a3d3811e86cd420..9416224d8af115491d689ff4328078482591d78c 100644 (file)
 #define _GNU_SOURCE
 #include "test_urcu_hash.h"
 
-unsigned int __thread rand_lookup;
-unsigned long __thread nr_add;
-unsigned long __thread nr_addexist;
-unsigned long __thread nr_del;
-unsigned long __thread nr_delnoent;
-unsigned long __thread lookup_fail;
-unsigned long __thread lookup_ok;
+enum test_hash {
+       TEST_HASH_RW,
+       TEST_HASH_UNIQUE,
+};
+
+struct test_hash_cb {
+       void (*sigusr1)(int signo);
+       void (*sigusr2)(int signo);
+       void *(*thr_reader)(void *_count);
+       void *(*thr_writer)(void *_count);
+       int (*populate_hash)(void);
+};
+
+static
+struct test_hash_cb test_hash_cb[] = {
+       [TEST_HASH_RW] = {
+               test_hash_rw_sigusr1_handler,
+               test_hash_rw_sigusr2_handler,
+               test_hash_rw_thr_reader,
+               test_hash_rw_thr_writer,
+               test_hash_rw_populate_hash,
+       },
+       [TEST_HASH_UNIQUE] = {
+               test_hash_unique_sigusr1_handler,
+               test_hash_unique_sigusr2_handler,
+               test_hash_unique_thr_reader,
+               test_hash_unique_thr_writer,
+               test_hash_unique_populate_hash,
+       },
+
+};
+
+static enum test_hash test_choice = TEST_HASH_RW;
+
+void (*get_sigusr1_cb(void))(int)
+{
+       return test_hash_cb[test_choice].sigusr1;
+}
+
+void (*get_sigusr2_cb(void))(int)
+{
+       return test_hash_cb[test_choice].sigusr2;
+}
+
+void *(*get_thr_reader_cb(void))(void *)
+{
+       return test_hash_cb[test_choice].thr_reader;
+}
+
+void *(*get_thr_writer_cb(void))(void *)
+{
+       return test_hash_cb[test_choice].thr_writer;
+}
+
+int (*get_populate_hash_cb(void))(void)
+{
+       return test_hash_cb[test_choice].populate_hash;
+}
+
+DEFINE_URCU_TLS(unsigned int, rand_lookup);
+DEFINE_URCU_TLS(unsigned long, nr_add);
+DEFINE_URCU_TLS(unsigned long, nr_addexist);
+DEFINE_URCU_TLS(unsigned long, nr_del);
+DEFINE_URCU_TLS(unsigned long, nr_delnoent);
+DEFINE_URCU_TLS(unsigned long, lookup_fail);
+DEFINE_URCU_TLS(unsigned long, lookup_ok);
 
 struct cds_lfht *test_ht;
 
@@ -55,6 +114,7 @@ unsigned long init_pool_size = DEFAULT_RAND_POOL,
        lookup_pool_size = DEFAULT_RAND_POOL,
        write_pool_size = DEFAULT_RAND_POOL;
 int validate_lookup;
+unsigned long nr_hash_chains;  /* 0: normal table, other: number of hash chains */
 
 int count_pipe[2];
 
@@ -66,8 +126,8 @@ int use_affinity = 0;
 
 pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
 
-unsigned long long __thread nr_writes;
-unsigned long long __thread nr_reads;
+DEFINE_URCU_TLS(unsigned long long, nr_writes);
+DEFINE_URCU_TLS(unsigned long long, nr_reads);
 
 unsigned int nr_readers;
 unsigned int nr_writers;
@@ -76,9 +136,10 @@ static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 void set_affinity(void)
 {
+#if HAVE_SCHED_SETAFFINITY
        cpu_set_t mask;
-       int cpu;
-       int ret;
+       int cpu, ret;
+#endif /* HAVE_SCHED_SETAFFINITY */
 
        if (!use_affinity)
                return;
@@ -100,7 +161,7 @@ void set_affinity(void)
 #if SCHED_SETAFFINITY_ARGS == 2
        sched_setaffinity(0, &mask);
 #else
-        sched_setaffinity(0, sizeof(mask), &mask);
+       sched_setaffinity(0, sizeof(mask), &mask);
 #endif
 #endif /* HAVE_SCHED_SETAFFINITY */
 }
@@ -127,7 +188,7 @@ void rcu_copy_mutex_unlock(void)
 }
 
 unsigned long test_compare(const void *key1, size_t key1_len,
-                           const void *key2, size_t key2_len)
+                          const void *key2, size_t key2_len)
 {
        if (caa_unlikely(key1_len != key2_len))
                return -1;
@@ -140,8 +201,8 @@ unsigned long test_compare(const void *key1, size_t key1_len,
 
 void *thr_count(void *arg)
 {
-       printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
-                       "counter", pthread_self(), (unsigned long)gettid());
+       printf_verbose("thread_begin %s, tid %lu\n",
+                       "counter", urcu_get_thread_id());
 
        rcu_register_thread();
 
@@ -205,7 +266,9 @@ void test_delete_all_nodes(struct cds_lfht *ht)
 
 void show_usage(int argc, char **argv)
 {
-       printf("Usage : %s nr_readers nr_writers duration (s)\n", argv[0]);
+       printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
+               argv[0]);
+       printf("OPTIONS:\n");
 #ifdef DEBUG_YIELD
        printf("        [-r] [-w] (yield reader and/or writer)\n");
 #endif
@@ -229,13 +292,16 @@ printf("        [not -u nor -s] Add entries (supports redundant keys).\n");
        printf("        [-M size] Lookup pool size.\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("\n\n");
+       printf("        [-V] Validate lookups of init values.\n");
+       printf("                (use with filled init pool, same lookup range,\n");
+       printf("                with different write range)\n");
+       printf("        [-U] Uniqueness test.\n");
+       printf("        [-C] Number of hash chains.\n");
+       printf("\n");
 }
 
 int main(int argc, char **argv)
 {
-       int err;
        pthread_t *tid_reader, *tid_writer;
        pthread_t tid_count;
        void *tret;
@@ -245,31 +311,37 @@ int main(int argc, char **argv)
                tot_add = 0, tot_add_exist = 0, tot_remove = 0;
        unsigned long count;
        long approx_before, approx_after;
-       int i, a, ret;
+       int i, a, ret, err, mainret = 0;
        struct sigaction act;
        unsigned int remain;
+       unsigned int nr_readers_created = 0, nr_writers_created = 0;
+       long long nr_leaked;
 
        if (argc < 4) {
                show_usage(argc, argv);
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        err = sscanf(argv[1], "%u", &nr_readers);
        if (err != 1) {
                show_usage(argc, argv);
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        err = sscanf(argv[2], "%u", &nr_writers);
        if (err != 1) {
                show_usage(argc, argv);
-               return -1;
+               mainret = 1;
+               goto end;
        }
        
        err = sscanf(argv[3], "%lu", &duration);
        if (err != 1) {
                show_usage(argc, argv);
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        for (i = 4; i < argc; i++) {
@@ -287,7 +359,8 @@ int main(int argc, char **argv)
                case 'a':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        a = atoi(argv[++i]);
                        cpu_affinities[next_aff++] = a;
@@ -297,14 +370,16 @@ int main(int argc, char **argv)
                case 'c':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        rduration = atol(argv[++i]);
                        break;
                case 'd':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        wdelay = atol(argv[++i]);
                        break;
@@ -314,21 +389,24 @@ int main(int argc, char **argv)
                case 'h':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        init_hash_size = atol(argv[++i]);
                        break;
                case 'm':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        min_hash_alloc_size = atol(argv[++i]);
                        break;
                case 'n':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        max_hash_buckets_size = atol(argv[++i]);
                        break;
@@ -358,7 +436,8 @@ int main(int argc, char **argv)
                case 'B':
                        if (argc < i + 2) {
                                show_usage(argc, argv);
-                               return -1;
+                               mainret = 1;
+                               goto end;
                        }
                        i++;
                        if (!strcmp("order", argv[i]))
@@ -367,9 +446,10 @@ int main(int argc, char **argv)
                                memory_backend = &cds_lfht_mm_chunk;
                        else if (!strcmp("mmap", argv[i]))
                                memory_backend = &cds_lfht_mm_mmap;
-                        else {
+                       else {
                                printf("Please specify memory backend with order|chunk|mmap.\n");
-                               exit(-1);
+                               mainret = 1;
+                               goto end;
                        }
                        break;
                case 'R':
@@ -393,7 +473,12 @@ int main(int argc, char **argv)
                case 'V':
                        validate_lookup = 1;
                        break;
-
+               case 'U':
+                       test_choice = TEST_HASH_UNIQUE;
+                       break;
+               case 'C':
+                       nr_hash_chains = atol(argv[++i]);
+                       break;
                }
        }
 
@@ -401,53 +486,47 @@ int main(int argc, char **argv)
        if (init_hash_size && init_hash_size & (init_hash_size - 1)) {
                printf("Error: Initial number of buckets (%lu) is not a power of 2.\n",
                        init_hash_size);
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        if (min_hash_alloc_size && min_hash_alloc_size & (min_hash_alloc_size - 1)) {
                printf("Error: Minimum number of allocated buckets (%lu) is not a power of 2.\n",
                        min_hash_alloc_size);
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        if (max_hash_buckets_size && max_hash_buckets_size & (max_hash_buckets_size - 1)) {
                printf("Error: Maximum number of buckets (%lu) is not a power of 2.\n",
                        max_hash_buckets_size);
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        memset(&act, 0, sizeof(act));
        ret = sigemptyset(&act.sa_mask);
        if (ret == -1) {
                perror("sigemptyset");
-               return -1;
+               mainret = 1;
+               goto end;
        }
-       act.sa_handler = test_hash_rw_sigusr1_handler;
+       act.sa_handler = get_sigusr1_cb();
        act.sa_flags = SA_RESTART;
        ret = sigaction(SIGUSR1, &act, NULL);
        if (ret == -1) {
                perror("sigaction");
-               return -1;
-       }
-
-       ret = pipe(count_pipe);
-       if (ret == -1) {
-               perror("pipe");
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
-       /* spawn counter thread */
-       err = pthread_create(&tid_count, NULL, thr_count,
-                            NULL);
-       if (err != 0)
-               exit(1);
-
-       act.sa_handler = test_hash_rw_sigusr2_handler;
+       act.sa_handler = get_sigusr2_cb();
        act.sa_flags = SA_RESTART;
        ret = sigaction(SIGUSR2, &act, NULL);
        if (ret == -1) {
                perror("sigaction");
-               return -1;
+               mainret = 1;
+               goto end;
        }
 
        printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
@@ -466,13 +545,31 @@ int main(int argc, char **argv)
                lookup_pool_offset, lookup_pool_size);
        printf_verbose("Update pool size offset %lu size %lu.\n",
                write_pool_offset, write_pool_size);
-       printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
-                       "main", pthread_self(), (unsigned long)gettid());
+       printf_verbose("Number of hash chains: %lu.\n",
+               nr_hash_chains);
+       printf_verbose("thread %-6s, tid %lu\n",
+                       "main", urcu_get_thread_id());
 
        tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
+       if (!tid_reader) {
+               mainret = 1;
+               goto end;
+       }
        tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
+       if (!tid_writer) {
+               mainret = 1;
+               goto end_free_tid_reader;
+       }
        count_reader = malloc(sizeof(*count_reader) * nr_readers);
+       if (!count_reader) {
+               mainret = 1;
+               goto end_free_tid_writer;
+       }
        count_writer = malloc(sizeof(*count_writer) * nr_writers);
+       if (!count_writer) {
+               mainret = 1;
+               goto end_free_count_reader;
+       }
 
        err = create_all_cpu_call_rcu_data(0);
        if (err) {
@@ -491,32 +588,64 @@ int main(int argc, char **argv)
                                (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
                                CDS_LFHT_ACCOUNTING, NULL);
        }
+       if (!test_ht) {
+               printf("Error allocating hash table.\n");
+               mainret = 1;
+               goto end_free_call_rcu_data;
+       }
 
        /*
         * Hash Population needs to be seen as a RCU reader
         * thread from the point of view of resize.
         */
        rcu_register_thread();
-       ret = test_hash_rw_populate_hash();
+       ret = (get_populate_hash_cb())();
        assert(!ret);
 
        rcu_thread_offline();
 
        next_aff = 0;
 
+       ret = pipe(count_pipe);
+       if (ret == -1) {
+               perror("pipe");
+               mainret = 1;
+               goto end_online;
+       }
+
+       /* spawn counter thread */
+       err = pthread_create(&tid_count, NULL, thr_count,
+                            NULL);
+       if (err != 0) {
+               errno = err;
+               mainret = 1;
+               perror("pthread_create");
+               goto end_close_pipe;
+       }
+
        for (i = 0; i < nr_readers; i++) {
                err = pthread_create(&tid_reader[i],
-                                    NULL, test_hash_rw_thr_reader,
+                                    NULL, get_thr_reader_cb(),
                                     &count_reader[i]);
-               if (err != 0)
-                       exit(1);
+               if (err != 0) {
+                       errno = err;
+                       mainret = 1;
+                       perror("pthread_create");
+                       goto end_pthread_join;
+               }
+               nr_readers_created++;
        }
        for (i = 0; i < nr_writers; i++) {
                err = pthread_create(&tid_writer[i],
-                                    NULL, test_hash_rw_thr_writer,
+                                    NULL, get_thr_writer_cb(),
                                     &count_writer[i]);
-               if (err != 0)
-                       exit(1);
+               if (err != 0) {
+                       errno = err;
+                       mainret = 1;
+                       perror("pthread_create");
+                       goto end_pthread_join;
+               }
+               nr_writers_created++;
        }
 
        cmm_smp_mb();
@@ -530,16 +659,23 @@ int main(int argc, char **argv)
 
        test_stop = 1;
 
-       for (i = 0; i < nr_readers; i++) {
+end_pthread_join:
+       for (i = 0; i < nr_readers_created; i++) {
                err = pthread_join(tid_reader[i], &tret);
-               if (err != 0)
-                       exit(1);
+               if (err != 0) {
+                       errno = err;
+                       mainret = 1;
+                       perror("pthread_join");
+               }
                tot_reads += count_reader[i];
        }
-       for (i = 0; i < nr_writers; i++) {
+       for (i = 0; i < nr_writers_created; i++) {
                err = pthread_join(tid_writer[i], &tret);
-               if (err != 0)
-                       exit(1);
+               if (err != 0) {
+                       errno = err;
+                       mainret = 1;
+                       perror("pthread_join");
+               }
                tot_writes += count_writer[i].update_ops;
                tot_add += count_writer[i].add;
                tot_add_exist += count_writer[i].add_exist;
@@ -551,8 +687,8 @@ int main(int argc, char **argv)
        act.sa_flags = SA_RESTART;
        ret = sigaction(SIGUSR2, &act, NULL);
        if (ret == -1) {
+               mainret = 1;
                perror("sigaction");
-               return -1;
        }
        {
                char msg[1] = { 0x42 };
@@ -563,10 +699,22 @@ int main(int argc, char **argv)
                } while (ret == -1L && errno == EINTR);
        }
        err = pthread_join(tid_count, &tret);
-       if (err != 0)
-               exit(1);
+       if (err != 0) {
+               errno = err;
+               mainret = 1;
+               perror("pthread_join");
+       }
 
+end_close_pipe:
+       for (i = 0; i < 2; i++) {
+               err = close(count_pipe[i]);
+               if (err) {
+                       mainret = 1;
+                       perror("close pipe");
+               }
+       }
        fflush(stdout);
+end_online:
        rcu_thread_online();
        rcu_read_lock();
        printf("Counting nodes... ");
@@ -584,13 +732,17 @@ int main(int argc, char **argv)
                printf("Approximation after node accounting: %ld nodes.\n",
                        approx_after);
        }
+
        ret = cds_lfht_destroy(test_ht, NULL);
-       if (ret)
+       if (ret) {
                printf_verbose("final delete aborted\n");
-       else
+               mainret = 1;
+       } else {
                printf_verbose("final delete success\n");
+       }
        printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
               tot_writes);
+       nr_leaked = (long long) tot_add + init_populate - tot_remove - count;
        printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
                "nr_writers %3u "
                "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
@@ -598,12 +750,25 @@ int main(int argc, char **argv)
                argv[0], duration, nr_readers, rduration,
                nr_writers, wdelay, tot_reads, tot_writes,
                tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
-               (long long) tot_add + init_populate - tot_remove - count);
+               nr_leaked);
+       if (nr_leaked != 0) {
+               mainret = 1;
+               printf("WARNING: %lld nodes were leaked!\n", nr_leaked);
+       }
+
        rcu_unregister_thread();
+end_free_call_rcu_data:
        free_all_cpu_call_rcu_data();
-       free(tid_reader);
-       free(tid_writer);
-       free(count_reader);
        free(count_writer);
-       return 0;
+end_free_count_reader:
+       free(count_reader);
+end_free_tid_writer:
+       free(tid_writer);
+end_free_tid_reader:
+       free(tid_reader);
+end:
+       if (!mainret)
+               exit(EXIT_SUCCESS);
+       else
+               exit(EXIT_FAILURE);
 }
This page took 0.029441 seconds and 4 git commands to generate.