From: Mathieu Desnoyers Date: Tue, 21 Aug 2012 21:38:27 +0000 (-0400) Subject: rcuja: extend tests, more fixes X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=582a6ade5032f98b788f1d8ddae97d44acf46715;p=userspace-rcu.git rcuja: extend tests, more fixes Signed-off-by: Mathieu Desnoyers --- diff --git a/rcuja/rcuja-shadow-nodes.c b/rcuja/rcuja-shadow-nodes.c index 89b4c45..d6e4ff5 100644 --- a/rcuja/rcuja-shadow-nodes.c +++ b/rcuja/rcuja-shadow-nodes.c @@ -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); diff --git a/rcuja/rcuja.c b/rcuja/rcuja.c index a651c7e..7511395 100644 --- a/rcuja/rcuja.c +++ b/rcuja/rcuja.c @@ -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; diff --git a/tests/test_urcu_ja.c b/tests/test_urcu_ja.c index 1f67b01..7c6190d 100644 --- a/tests/test_urcu_ja.c +++ b/tests/test_urcu_ja.c @@ -23,6 +23,7 @@ #define _GNU_SOURCE #include "test_urcu_ja.h" #include +#include 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