rcuja: extend tests, more fixes
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 21 Aug 2012 21:38:27 +0000 (17:38 -0400)
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-shadow-nodes.c
rcuja/rcuja.c
tests/test_urcu_ja.c

index 89b4c4517adfe1d6619b8a6a003f431ded283510..d6e4ff5db5212cbdda78eab45d6876a55bb862bd 100644 (file)
@@ -294,6 +294,7 @@ void free_shadow_node_and_node_and_lock(struct rcu_head *head)
 {
        struct cds_ja_shadow_node *shadow_node =
                caa_container_of(head, struct cds_ja_shadow_node, head);
+       assert(!shadow_node->is_root);
        free(shadow_node->node);
        free(shadow_node->lock);
        free(shadow_node);
@@ -337,7 +338,8 @@ int rcuja_shadow_clear(struct cds_lfht *ht,
         */
        ret = cds_lfht_del(ht, lookup_node);
        if (!ret) {
-               if (flags & RCUJA_SHADOW_CLEAR_FREE_NODE) {
+               if ((flags & RCUJA_SHADOW_CLEAR_FREE_NODE)
+                               && !shadow_node->is_root) {
                        if (flags & RCUJA_SHADOW_CLEAR_FREE_LOCK) {
                                flavor->update_call_rcu(&shadow_node->head,
                                        free_shadow_node_and_node_and_lock);
@@ -386,10 +388,24 @@ void rcuja_shadow_prune(struct cds_lfht *ht,
        
                ret = cds_lfht_del(ht, &shadow_node->ht_node);
                if (!ret) {
-                       assert((flags & RCUJA_SHADOW_CLEAR_FREE_NODE)
-                               && (flags & RCUJA_SHADOW_CLEAR_FREE_LOCK));
-                       flavor->update_call_rcu(&shadow_node->head,
-                               free_shadow_node_and_node_and_lock);
+                       if ((flags & RCUJA_SHADOW_CLEAR_FREE_NODE)
+                                       && !shadow_node->is_root) {
+                               if (flags & RCUJA_SHADOW_CLEAR_FREE_LOCK) {
+                                       flavor->update_call_rcu(&shadow_node->head,
+                                               free_shadow_node_and_node_and_lock);
+                               } else {
+                                       flavor->update_call_rcu(&shadow_node->head,
+                                               free_shadow_node_and_node);
+                               }
+                       } else {
+                               if (flags & RCUJA_SHADOW_CLEAR_FREE_LOCK) {
+                                       flavor->update_call_rcu(&shadow_node->head,
+                                               free_shadow_node_and_lock);
+                               } else {
+                                       flavor->update_call_rcu(&shadow_node->head,
+                                               free_shadow_node);
+                               }
+                       }
                }
                lockret = pthread_mutex_unlock(shadow_node->lock);
                assert(!lockret);
index a651c7e2174c2829e7c725760a483446029077c7..75113954ccdb9dee09193a41321002b623bd6cfd 100644 (file)
@@ -71,7 +71,8 @@ struct cds_ja_type {
 #define JA_PTR_MASK    (~JA_TYPE_MASK)
 
 #define JA_ENTRY_PER_NODE      256UL
-#define JA_BITS_PER_BYTE       3
+#define JA_LOG2_BITS_PER_BYTE  3U
+#define JA_BITS_PER_BYTE       (1U << JA_LOG2_BITS_PER_BYTE)
 
 #define JA_MAX_DEPTH   9       /* Maximum depth, including leafs */
 
@@ -411,7 +412,9 @@ struct cds_ja_inode_flag *ja_pigeon_node_get_nth(const struct cds_ja_type *type,
 
        assert(type->type_class == RCU_JA_PIGEON);
        child_node_flag = &((struct cds_ja_inode_flag **) node->u.data)[n];
-       if (caa_unlikely(child_node_flag_ptr))
+       dbg_printf("ja_pigeon_node_get_nth child_node_flag_ptr %p\n",
+               child_node_flag);
+       if (caa_unlikely(child_node_flag_ptr) && *child_node_flag)
                *child_node_flag_ptr = child_node_flag;
        return rcu_dereference(*child_node_flag);
 }
@@ -601,7 +604,8 @@ int ja_node_recompact_add(struct cds_ja *ja,
        }
 
 retry:         /* for fallback */
-       dbg_printf("Recompact to type %d\n", new_type_index);
+       dbg_printf("Recompact from type %d to type %d\n",
+                       old_type_index, new_type_index);
        new_type = &ja_types[new_type_index];
        new_node = alloc_cds_ja_node(new_type);
        if (!new_node)
@@ -767,6 +771,8 @@ struct cds_hlist_head *cds_ja_lookup(struct cds_ja *ja, uint64_t key)
                iter_key = (uint8_t) (key >> (JA_BITS_PER_BYTE * (tree_depth - i - 1)));
                node_flag = ja_node_get_nth(node_flag, NULL,
                        iter_key);
+               dbg_printf("cds_ja_lookup iter key lookup %u finds node_flag %p\n",
+                               (unsigned int) iter_key, node_flag);
                if (!ja_node_ptr(node_flag))
                        return NULL;
        }
@@ -807,7 +813,8 @@ int ja_attach_node(struct cds_ja *ja,
        struct cds_ja_inode_flag *created_nodes[JA_MAX_DEPTH];
        int nr_created_nodes = 0;
 
-       dbg_printf("Attach node at level %u\n", level);
+       dbg_printf("Attach node at level %u (node %p, node_flag %p)\n",
+               level, node, node_flag);
 
        assert(node);
        shadow_node = rcuja_shadow_lookup_lock(ja->ht, node);
@@ -954,6 +961,8 @@ retry:
        for (i = 1; i < tree_depth; i++) {
                uint8_t iter_key;
 
+               dbg_printf("cds_ja_add iter node_flag_ptr %p node_flag %p\n",
+                               *node_flag_ptr, node_flag);
                if (!ja_node_ptr(node_flag)) {
                        ret = ja_attach_node(ja, node_flag_ptr,
                                        parent_node_flag, parent2_node_flag,
@@ -969,6 +978,8 @@ retry:
                node_flag = ja_node_get_nth(node_flag,
                        &node_flag_ptr,
                        iter_key);
+               dbg_printf("cds_ja_add iter key lookup %u finds node_flag %p node_flag_ptr %p\n",
+                               (unsigned int) iter_key, node_flag, *node_flag_ptr);
        }
 
        /*
@@ -976,6 +987,8 @@ retry:
         * level, or chain it if key is already present.
         */
        if (!ja_node_ptr(node_flag)) {
+               dbg_printf("cds_ja_add last node_flag_ptr %p node_flag %p\n",
+                               *node_flag_ptr, node_flag);
                ret = ja_attach_node(ja, node_flag_ptr, parent_node_flag,
                                parent2_node_flag, key, i, new_node);
        } else {
@@ -1019,7 +1032,7 @@ struct cds_ja *_cds_ja_new(unsigned int key_bits,
 
        /* ja->root is NULL */
        /* tree_depth 0 is for pointer to root node */
-       ja->tree_depth = (key_bits >> JA_BITS_PER_BYTE) + 1;
+       ja->tree_depth = (key_bits >> JA_LOG2_BITS_PER_BYTE) + 1;
        assert(ja->tree_depth <= JA_MAX_DEPTH);
        ja->ht = rcuja_create_ht(flavor);
        if (!ja->ht)
@@ -1035,6 +1048,7 @@ struct cds_ja *_cds_ja_new(unsigned int key_bits,
                ret = -ENOMEM;
                goto ht_node_error;
        }
+       root_shadow_node->is_root = 1;
 
        return ja;
 
index 1f67b017ef38874efebd9932a47aab20cbbd6042..7c6190daa485429ab896e7db58b2db5c87895dd7 100644 (file)
@@ -23,6 +23,7 @@
 #define _GNU_SOURCE
 #include "test_urcu_ja.h"
 #include <inttypes.h>
+#include <stdint.h>
 
 DEFINE_URCU_TLS(unsigned int, rand_lookup);
 DEFINE_URCU_TLS(unsigned long, nr_add);
@@ -172,6 +173,234 @@ printf("        [not -u nor -s] Add entries (supports redundant keys).\n");
        printf("\n\n");
 }
 
+
+static
+int test_8bit_key(void)
+{
+       int ret;
+       uint64_t key;
+
+       /* Test with 8-bit key */
+       test_ja = cds_ja_new(8);
+       if (!test_ja) {
+               printf("Error allocating judy array.\n");
+               return -1;
+       }
+
+       /* Add keys */
+       printf("Test #1: add keys (8-bit).\n");
+       for (key = 0; key < 200; key++) {
+               struct ja_test_node *node =
+                       calloc(sizeof(*node), 1);
+
+               ja_test_node_init(node, key);
+               rcu_read_lock();
+               ret = cds_ja_add(test_ja, key, &node->node);
+               rcu_read_unlock();
+               if (ret) {
+                       fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+                               ret, key);
+                       assert(0);
+               }
+       }
+       printf("OK\n");
+
+       printf("Test #2: successful key lookup (8-bit).\n");
+       for (key = 0; key < 200; key++) {
+               struct cds_hlist_head *head;
+
+               rcu_read_lock();
+               head = cds_ja_lookup(test_ja, key);
+               if (!head) {
+                       fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
+                       assert(0);
+               }
+               rcu_read_unlock();
+       }
+       printf("OK\n");
+       printf("Test #3: unsuccessful key lookup (8-bit).\n");
+       for (key = 200; key < 240; key++) {
+               struct cds_hlist_head *head;
+
+               rcu_read_lock();
+               head = cds_ja_lookup(test_ja, key);
+               if (head) {
+                       fprintf(stderr,
+                               "Error unexpected lookup node %" PRIu64 "\n",
+                               key);
+                       assert(0);
+               }
+               rcu_read_unlock();
+       }
+       printf("OK\n");
+
+       ret = cds_ja_destroy(test_ja);
+       if (ret) {
+               fprintf(stderr, "Error destroying judy array\n");
+               return -1;
+       }
+       return 0;
+}
+
+static
+int test_16bit_key(void)
+{
+       int ret;
+       uint64_t key;
+
+       /* Test with 16-bit key */
+       test_ja = cds_ja_new(16);
+       if (!test_ja) {
+               printf("Error allocating judy array.\n");
+               return -1;
+       }
+
+       /* Add keys */
+       printf("Test #1: add keys (16-bit).\n");
+       //for (key = 0; key < 10000; key++) {
+       for (key = 0; key < 65536; key+=256) {
+               struct ja_test_node *node =
+                       calloc(sizeof(*node), 1);
+
+               ja_test_node_init(node, key);
+               rcu_read_lock();
+               ret = cds_ja_add(test_ja, key, &node->node);
+               rcu_read_unlock();
+               if (ret) {
+                       fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+                               ret, key);
+                       assert(0);
+               }
+       }
+       printf("OK\n");
+
+       printf("Test #2: successful key lookup (16-bit).\n");
+       //for (key = 0; key < 10000; key++) {
+       for (key = 0; key < 65536; key+=256) {
+               struct cds_hlist_head *head;
+
+               rcu_read_lock();
+               head = cds_ja_lookup(test_ja, key);
+               if (!head) {
+                       fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
+                       assert(0);
+               }
+               rcu_read_unlock();
+       }
+       printf("OK\n");
+       printf("Test #3: unsuccessful key lookup (16-bit).\n");
+       for (key = 11000; key <= 11002; key++) {
+               struct cds_hlist_head *head;
+
+               rcu_read_lock();
+               head = cds_ja_lookup(test_ja, key);
+               if (head) {
+                       fprintf(stderr,
+                               "Error unexpected lookup node %" PRIu64 "\n",
+                               key);
+                       assert(0);
+               }
+               rcu_read_unlock();
+       }
+       printf("OK\n");
+
+       ret = cds_ja_destroy(test_ja);
+       if (ret) {
+               fprintf(stderr, "Error destroying judy array\n");
+               return -1;
+       }
+       return 0;
+}
+
+static
+int test_sparse_key(unsigned int bits)
+{
+       int ret;
+       uint64_t key, max_key;
+       int zerocount;
+
+       if (bits == 64)
+               max_key = UINT64_MAX;
+       else
+               max_key = (1ULL << bits) - 1;
+
+       printf("Sparse key test begins for %u-bit keys\n", bits);
+       /* Test with 16-bit key */
+       test_ja = cds_ja_new(bits);
+       if (!test_ja) {
+               printf("Error allocating judy array.\n");
+               return -1;
+       }
+
+       /* Add keys */
+       printf("Test #1: add keys (%u-bit).\n", bits);
+       zerocount = 0;
+       for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
+               struct ja_test_node *node =
+                       calloc(sizeof(*node), 1);
+
+               ja_test_node_init(node, key);
+               rcu_read_lock();
+               ret = cds_ja_add(test_ja, key, &node->node);
+               rcu_read_unlock();
+               if (ret) {
+                       fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
+                               ret, key);
+                       assert(0);
+               }
+               if (key == 0)
+                       zerocount++;
+       }
+       printf("OK\n");
+
+       printf("Test #2: successful key lookup (%u-bit).\n", bits);
+       zerocount = 0;
+       for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
+               struct cds_hlist_head *head;
+
+               rcu_read_lock();
+               head = cds_ja_lookup(test_ja, key);
+               if (!head) {
+                       fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
+                       assert(0);
+               }
+               rcu_read_unlock();
+               if (key == 0)
+                       zerocount++;
+       }
+       printf("OK\n");
+       if (bits > 8) {
+               printf("Test #3: unsuccessful key lookup (%u-bit).\n", bits);
+               zerocount = 0;
+               for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
+                       struct cds_hlist_head *head;
+
+                       rcu_read_lock();
+                       head = cds_ja_lookup(test_ja, key + 42);
+                       if (head) {
+                               fprintf(stderr,
+                                       "Error unexpected lookup node %" PRIu64 "\n",
+                                       key + 42);
+                               assert(0);
+                       }
+                       rcu_read_unlock();
+                       if (key == 0)
+                               zerocount++;
+               }
+               printf("OK\n");
+       }
+
+       ret = cds_ja_destroy(test_ja);
+       if (ret) {
+               fprintf(stderr, "Error destroying judy array\n");
+               return -1;
+       }
+       printf("Test ends\n");
+
+       return 0;
+}
+
+
 int main(int argc, char **argv)
 {
        int err;
@@ -302,66 +531,49 @@ int main(int argc, char **argv)
                printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
        }
 
-       /* Test with 8-bit key */
-       test_ja = cds_ja_new(8);
-       if (!test_ja) {
-               printf("Error allocating judy array.\n");
-               return -1;
-       }
+       rcu_register_thread();
 
-       /* Add keys */
-       printf("Test #1: add keys (8-bit).\n");
-       for (key = 0; key < 200; key++) {
-               struct ja_test_node *node =
-                       calloc(sizeof(*node), 1);
+       printf("Test start.\n");
 
-               ja_test_node_init(node, key);
-               rcu_read_lock();
-               ret = cds_ja_add(test_ja, key, &node->node);
-               rcu_read_unlock();
+       for (i = 0; i < 3; i++) {
+               ret = test_8bit_key();
                if (ret) {
-                       fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
-                               ret, key);
-                       assert(0);
+                       return ret;
                }
+               rcu_quiescent_state();
        }
-       printf("OK\n");
+       ret = test_16bit_key();
+       if (ret) {
+               return ret;
+       }
+       rcu_quiescent_state();
 
-       printf("Test #2: successful key lookup (8-bit).\n");
-       for (key = 0; key < 200; key++) {
-               struct cds_hlist_head *head;
+       ret = test_sparse_key(8);
+       if (ret) {
+               return ret;
+       }
+       rcu_quiescent_state();
 
-               rcu_read_lock();
-               head = cds_ja_lookup(test_ja, key);
-               if (!head) {
-                       fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
-                       assert(0);
-               }
-               rcu_read_unlock();
+       ret = test_sparse_key(16);
+       if (ret) {
+               return ret;
        }
-       printf("OK\n");
-       printf("Test #3: unsuccessful key lookup (8-bit).\n");
-       for (key = 200; key < 240; key++) {
-               struct cds_hlist_head *head;
+       rcu_quiescent_state();
 
-               rcu_read_lock();
-               head = cds_ja_lookup(test_ja, key);
-               if (head) {
-                       fprintf(stderr,
-                               "Error unexpected lookup node %" PRIu64 "\n",
-                               key);
-                       assert(0);
-               }
-               rcu_read_unlock();
+       ret = test_sparse_key(32);
+       if (ret) {
+               return ret;
        }
-       printf("OK\n");
+       rcu_quiescent_state();
 
-       ret = cds_ja_destroy(test_ja);
+       ret = test_sparse_key(64);
        if (ret) {
-               fprintf(stderr, "Error destroying judy array\n");
-               return -1;
+               return ret;
        }
+       rcu_quiescent_state();
+
        printf("Test end.\n");
+       rcu_unregister_thread();
        return 0;
 
 #if 0
This page took 0.031803 seconds and 4 git commands to generate.