static unsigned int add_ratio = 50;
static uint64_t key_mul = 1ULL;
+static int add_unique, add_replace;
+
static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
+static int leak_detection;
+static unsigned long test_nodes_allocated, test_nodes_freed;
+
void set_affinity(void)
{
cpu_set_t mask;
}
}
-void free_node_cb(struct rcu_head *head)
+static
+struct ja_test_node *node_alloc(void)
+{
+ struct ja_test_node *node;
+
+ node = calloc(sizeof(*node), 1);
+ if (leak_detection && node)
+ uatomic_inc(&test_nodes_allocated);
+ return node;
+}
+
+static
+void free_test_node(struct ja_test_node *node)
{
- struct ja_test_node *node =
- caa_container_of(head, struct ja_test_node, node.head);
poison_free(node);
+ if (leak_detection)
+ uatomic_inc(&test_nodes_freed);
+}
+
+static
+void free_test_node_cb(struct rcu_head *head)
+{
+ struct ja_test_node *node =
+ caa_container_of(head, struct ja_test_node, head);
+ free_test_node(node);
+}
+
+static
+void rcu_free_test_node(struct ja_test_node *test_node)
+{
+ call_rcu(&test_node->head, free_test_node_cb);
+}
+
+static
+void free_node(struct cds_ja_node *node)
+{
+ struct ja_test_node *test_node = to_test_node(node);
+
+ free_test_node(test_node);
}
#if 0
printf(" [-c duration] (reader C.S. duration (in loops))\n");
printf(" [-v] (verbose output)\n");
printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
+ printf(" [-u] Add unique keys.\n");
+ printf(" [-s] Replace existing keys.\n");
printf(" [not -u nor -s] Add entries (supports redundant keys).\n");
printf(" [-r ratio] Add ratio (in %% of add+removal).\n");
printf(" [-k] Populate init nodes.\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(" [-t] Do sanity test.\n");
printf(" [-B] Key bits for multithread test (default: 32).\n");
printf(" [-m factor] Key multiplication factor.\n");
+ printf(" [-l] Memory leak detection.\n");
printf("\n\n");
}
+static
+int test_free_all_nodes(struct cds_ja *ja)
+{
+ uint64_t key;
+ struct cds_ja_node *ja_node;
+ int ret = 0;
+
+ rcu_read_lock();
+ cds_ja_for_each_key_rcu(test_ja, key, ja_node) {
+ struct cds_ja_node *tmp_node;
+
+ cds_ja_for_each_duplicate_safe_rcu(ja_node, tmp_node) {
+ ret = cds_ja_del(test_ja, key, ja_node);
+ if (ret) {
+ fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
+ goto end;
+ }
+ /* Alone using Judy array, OK to free now */
+ free_node(ja_node);
+ }
+ }
+end:
+ rcu_read_unlock();
+ return ret;
+}
static
int test_8bit_key(void)
{
- int ret;
+ int ret, i;
uint64_t key;
+ uint64_t ka[] = { 5, 17, 100, 222 };
+ uint64_t ka_test_offset = 5;
+ struct cds_ja_node *ja_node;
/* Test with 8-bit key */
test_ja = cds_ja_new(8);
/* 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);
+ struct ja_test_node *node = node_alloc();
ja_test_node_init(node, key);
rcu_read_lock();
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 (cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (!ja_node) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
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 (!cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (ja_node) {
fprintf(stderr,
"Error unexpected lookup node %" PRIu64 "\n",
key);
printf("OK\n");
printf("Test #4: remove keys (8-bit).\n");
for (key = 0; key < 200; key++) {
- struct cds_hlist_head head;
struct ja_test_node *node;
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) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (!ja_node) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
+ node = caa_container_of(ja_node, struct ja_test_node, node);
ret = cds_ja_del(test_ja, key, &node->node);
if (ret) {
fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
assert(0);
}
- call_rcu(&node->node.head, free_node_cb);
- head = cds_ja_lookup(test_ja, key);
- if (!cds_hlist_empty(&head)) {
- fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
+ rcu_free_test_node(node);
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (ja_node) {
+ fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, ja_node);
assert(0);
}
rcu_read_unlock();
}
printf("OK\n");
- ret = cds_ja_destroy(test_ja, free_node_cb);
+ printf("Test #5: lookup below/above equal (8-bit).\n");
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node = node_alloc();
+
+ key = ka[i];
+ 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);
+ }
+ }
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node;
+ uint64_t result_key;
+
+ key = ka[i] + ka_test_offset;
+ rcu_read_lock();
+ ja_node = cds_ja_lookup_below_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup below equal. Cannot find expected key %" PRIu64" below or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup below equal. Expecting key %" PRIu64 " below or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node;
+ uint64_t result_key;
+
+ key = ka[i] - ka_test_offset;
+ rcu_read_lock();
+ ja_node = cds_ja_lookup_above_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup above equal. Cannot find expected key %" PRIu64" below or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup above equal. Expecting key %" PRIu64 " below or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node;
+ uint64_t result_key;
+
+ key = ka[i]; /* without offset */
+ rcu_read_lock();
+ ja_node = cds_ja_lookup_below_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup below equal. Cannot find expected key %" PRIu64" below or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup below equal. Expecting key %" PRIu64 " below or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+
+ ja_node = cds_ja_lookup_above_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup above equal. Cannot find expected key %" PRIu64" below or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup above equal. Expecting key %" PRIu64 " below or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+
+ printf("OK\n");
+
+ ret = test_free_all_nodes(test_ja);
+ if (ret) {
+ fprintf(stderr, "Error freeing all nodes\n");
+ return -1;
+ }
+
+ ret = cds_ja_destroy(test_ja);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
return -1;
static
int test_16bit_key(void)
{
- int ret;
+ int ret, i;
uint64_t key;
+ uint64_t ka[] = { 105, 206, 4000, 4111, 59990, 65435 };
+ uint64_t ka_test_offset = 100;
+ struct cds_ja_node *ja_node;
/* Test with 16-bit key */
test_ja = cds_ja_new(16);
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);
+ struct ja_test_node *node = node_alloc();
ja_test_node_init(node, key);
rcu_read_lock();
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;
+ struct cds_ja_node *ja_node;
rcu_read_lock();
- head = cds_ja_lookup(test_ja, key);
- if (cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (!ja_node) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
printf("OK\n");
printf("Test #3: unsuccessful key lookup (16-bit).\n");
for (key = 11000; key <= 11002; key++) {
- struct cds_hlist_head head;
+ struct cds_ja_node *ja_node;
rcu_read_lock();
- head = cds_ja_lookup(test_ja, key);
- if (!cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (ja_node) {
fprintf(stderr,
"Error unexpected lookup node %" PRIu64 "\n",
key);
printf("Test #4: remove keys (16-bit).\n");
for (key = 0; key < 10000; key++) {
//for (key = 0; key < 65536; key+=256) {
- struct cds_hlist_head head;
struct ja_test_node *node;
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) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (!ja_node) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
+ node = caa_container_of(ja_node, struct ja_test_node, node);
ret = cds_ja_del(test_ja, key, &node->node);
if (ret) {
fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
assert(0);
}
- call_rcu(&node->node.head, free_node_cb);
- head = cds_ja_lookup(test_ja, key);
- if (!cds_hlist_empty(&head)) {
- fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
+ rcu_free_test_node(node);
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (ja_node) {
+ fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, ja_node);
assert(0);
}
rcu_read_unlock();
}
printf("OK\n");
- ret = cds_ja_destroy(test_ja, free_node_cb);
+ printf("Test #5: lookup below/above equal (16-bit).\n");
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node = node_alloc();
+
+ key = ka[i];
+ 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);
+ }
+ }
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node;
+ uint64_t result_key;
+
+ key = ka[i] + ka_test_offset;
+ rcu_read_lock();
+ ja_node = cds_ja_lookup_below_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup below equal. Cannot find expected key %" PRIu64" below or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup below equal. Expecting key %" PRIu64 " below or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node;
+ uint64_t result_key;
+
+ key = ka[i] - ka_test_offset;
+ rcu_read_lock();
+ ja_node = cds_ja_lookup_above_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup above equal. Cannot find expected key %" PRIu64" above or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup above equal. Expecting key %" PRIu64 " above or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+
+ for (i = 0; i < CAA_ARRAY_SIZE(ka); i++) {
+ struct ja_test_node *node;
+ uint64_t result_key;
+
+ key = ka[i]; /* without offset */
+ rcu_read_lock();
+ ja_node = cds_ja_lookup_below_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup below equal. Cannot find expected key %" PRIu64" below or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup below equal. Expecting key %" PRIu64 " below or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+
+ ja_node = cds_ja_lookup_above_equal(test_ja, key, &result_key);
+ if (!ja_node) {
+ fprintf(stderr, "Error lookup above equal. Cannot find expected key %" PRIu64" above or equal to %" PRIu64 ".\n",
+ ka[i], key);
+ assert(0);
+ }
+ node = caa_container_of(ja_node, struct ja_test_node, node);
+ if (node->key != ka[i] || result_key != ka[i]) {
+ fprintf(stderr, "Error lookup above equal. Expecting key %" PRIu64 " above or equal to %" PRIu64 ", but found %" PRIu64 "/%" PRIu64" instead.\n",
+ ka[i], key, node->key, result_key);
+ assert(0);
+ }
+ rcu_read_unlock();
+ }
+
+ printf("OK\n");
+
+ ret = test_free_all_nodes(test_ja);
+ if (ret) {
+ fprintf(stderr, "Error freeing all nodes\n");
+ return -1;
+ }
+
+ ret = cds_ja_destroy(test_ja);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
return -1;
{
uint64_t key, max_key;
int zerocount, i, ret;
+ struct cds_ja_node *ja_node;
if (bits == 64)
max_key = UINT64_MAX;
for (i = 0; i < nr_dup; i++) {
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);
+ struct ja_test_node *node = node_alloc();
ja_test_node_init(node, key);
rcu_read_lock();
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;
struct ja_test_node *node;
- struct cds_hlist_node *pos;
int count = 0;
rcu_read_lock();
- head = cds_ja_lookup(test_ja, key);
- if (cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (!ja_node) {
fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
assert(0);
}
- cds_hlist_for_each_entry_rcu(node, pos, &head, node.list) {
+ cds_ja_for_each_duplicate_rcu(ja_node) {
count++;
}
if (count != nr_dup) {
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 (!cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key + 42);
+ if (ja_node) {
fprintf(stderr,
"Error unexpected lookup node %" PRIu64 "\n",
key + 42);
}
printf("OK\n");
}
- printf("Test #4: remove keys (16-bit).\n");
+ printf("Test #4: remove keys (%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;
- struct ja_test_node *node;
- struct cds_hlist_node *pos;
int count = 0;
rcu_read_lock();
- head = cds_ja_lookup(test_ja, key);
+ ja_node = cds_ja_lookup(test_ja, key);
-
- cds_hlist_for_each_entry_rcu(node, pos, &head, node.list) {
- struct cds_hlist_head testhead;
+ cds_ja_for_each_duplicate_rcu(ja_node) {
+ struct cds_ja_node *test_ja_node;
+ struct ja_test_node *node;
count++;
- if (!node) {
- fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
- assert(0);
- }
+ node = caa_container_of(ja_node,
+ struct ja_test_node, node);
ret = cds_ja_del(test_ja, key, &node->node);
if (ret) {
fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
assert(0);
}
- call_rcu(&node->node.head, free_node_cb);
- testhead = cds_ja_lookup(test_ja, key);
- if (count < nr_dup && cds_hlist_empty(&testhead)) {
+ rcu_free_test_node(node);
+ test_ja_node = cds_ja_lookup(test_ja, key);
+ if (count < nr_dup && !test_ja_node) {
fprintf(stderr, "Error: no node found after deletion of some nodes of a key\n");
assert(0);
}
}
- head = cds_ja_lookup(test_ja, key);
- if (!cds_hlist_empty(&head)) {
- fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (ja_node) {
+ fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, ja_node);
assert(0);
}
rcu_read_unlock();
}
printf("OK\n");
- ret = cds_ja_destroy(test_ja, free_node_cb);
+ ret = test_free_all_nodes(test_ja);
+ if (ret) {
+ fprintf(stderr, "Error freeing all nodes\n");
+ return -1;
+ }
+
+ ret = cds_ja_destroy(test_ja);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
return -1;
void *test_ja_rw_thr_reader(void *_count)
{
unsigned long long *count = _count;
- struct cds_hlist_head head;
+ struct cds_ja_node *ja_node;
uint64_t key;
- printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
- "reader", pthread_self(), (unsigned long) gettid());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
set_affinity();
/* note: only looking up ulong keys */
key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset;
key *= key_mul;
- head = cds_ja_lookup(test_ja, key);
- if (cds_hlist_empty(&head)) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ if (!ja_node) {
if (validate_lookup) {
printf("[ERROR] Lookup cannot find initial node.\n");
exit(-1);
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("thread_end %s, tid %lu\n",
+ "reader", urcu_get_thread_id());
printf_verbose("readid : %lx, lookupfail %lu, lookupok %lu\n",
pthread_self(), URCU_TLS(lookup_fail),
URCU_TLS(lookup_ok));
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());
+ printf_verbose("thread_begin %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
+
+ URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
set_affinity();
for (;;) {
if ((addremove == AR_ADD)
|| (addremove == AR_RANDOM && is_add())) {
- struct ja_test_node *node = malloc(sizeof(*node));
+ struct ja_test_node *node = node_alloc();
+ struct cds_ja_node *ret_node;
/* note: only inserting ulong keys */
key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
key *= key_mul;
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);
+ if (add_unique) {
+ ret_node = cds_ja_add_unique(test_ja, key, &node->node);
+ if (ret_node != &node->node) {
+ free_test_node(node);
+ URCU_TLS(nr_addexist)++;
+ } else {
+ URCU_TLS(nr_add)++;
+ }
+ } else if (add_replace) {
+ assert(0); /* not implemented yet. */
+ } else {
+ ret = cds_ja_add(test_ja, key, &node->node);
+ if (ret) {
+ fprintf(stderr, "Error in cds_ja_add: %d\n", ret);
+ free_test_node(node);
+ } else {
+ URCU_TLS(nr_add)++;
+ }
}
+ rcu_read_unlock();
} else {
+ struct cds_ja_node *ja_node;
struct ja_test_node *node;
/* May delete */
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) {
+ ja_node = cds_ja_lookup(test_ja, key);
+ /* Remove first entry */
+ if (ja_node) {
+ node = caa_container_of(ja_node,
+ struct ja_test_node, node);
ret = cds_ja_del(test_ja, key, &node->node);
if (!ret) {
- call_rcu(&node->node.head, free_node_cb);
+ rcu_free_test_node(node);
URCU_TLS(nr_del)++;
} else {
URCU_TLS(nr_delnoent)++;
rcu_unregister_thread();
- printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
- "writer", pthread_self(), (unsigned long) gettid());
+ printf_verbose("thread_end %s, tid %lu\n",
+ "writer", urcu_get_thread_id());
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),
static
int do_mt_populate_ja(void)
{
- struct cds_hlist_head head;
uint64_t iter;
int ret;
printf("Starting rw test\n");
for (iter = init_pool_offset; iter < init_pool_offset + init_pool_size; iter++) {
- struct ja_test_node *node = malloc(sizeof(*node));
+ struct ja_test_node *node = node_alloc();
uint64_t key;
/* note: only inserting ulong keys */
URCU_TLS(nr_add)++;
URCU_TLS(nr_writes)++;
rcu_read_unlock();
+ /* Hash table resize only occurs in call_rcu thread */
+ if (!(iter % 100))
+ rcu_quiescent_state();
if (ret) {
fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
ret, key);
tot_add_exist += count_writer[i].add_exist;
tot_remove += count_writer[i].remove;
}
+ rcu_thread_online_qsbr();
+
+ ret = test_free_all_nodes(test_ja);
+ if (ret) {
+ fprintf(stderr, "Error freeing all nodes\n");
+ return -1;
+ }
- ret = cds_ja_destroy(test_ja, free_node_cb);
+ ret = cds_ja_destroy(test_ja);
if (ret) {
fprintf(stderr, "Error destroying judy array\n");
goto end;
}
- rcu_thread_online_qsbr();
free(tid_reader);
free(tid_writer);
return ret;
}
+static
+int check_memory_leaks(void)
+{
+ unsigned long na, nf;
+
+ na = uatomic_read(&test_nodes_allocated);
+ nf = uatomic_read(&test_nodes_freed);
+ if (na != nf) {
+ fprintf(stderr, "Memory leak of %ld test nodes detected. Allocated: %lu, freed: %lu\n",
+ na - nf, na, nf);
+ return -1;
+ }
+ return 0;
+}
+
int main(int argc, char **argv)
{
int i, j, a, ret, err;
case 'V':
validate_lookup = 1;
break;
- case 's':
+ case 't':
sanity_test = 1;
break;
case 'B':
case 'm':
key_mul = atoll(argv[++i]);
break;
+ case 'u':
+ add_unique = 1;
+ break;
+ case 's':
+ add_replace = 1;
+ break;
+ case 'l':
+ leak_detection = 1;
+ break;
}
}
printf_verbose("Writer delay : %lu loops.\n", wdelay);
printf_verbose("Reader duration : %lu loops.\n", rduration);
printf_verbose("Add ratio: %u%%.\n", add_ratio);
+ printf_verbose("Mode:%s%s.\n",
+ " add/remove",
+ add_unique ? " uniquify" : ( add_replace ? " replace" : " insert"));
printf_verbose("Key multiplication factor: %" PRIu64 ".\n", key_mul);
printf_verbose("Init pool size offset %lu size %lu.\n",
init_pool_offset, init_pool_size);
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());
+ if (validate_lookup)
+ printf_verbose("Validating lookups.\n");
+ if (leak_detection)
+ printf_verbose("Memory leak dection activated.\n");
+ printf_verbose("thread %-6s, tid %lu\n",
+ "main", urcu_get_thread_id());
memset(&act, 0, sizeof(act));
ret = sigemptyset(&act.sa_mask);
if (sanity_test) {
ret = do_sanity_test();
- if (ret) {
- fprintf(stderr, "Error in sanity test\n");
- }
} else {
- do_mt_test();
+ ret = do_mt_test();
}
- rcu_unregister_thread();
- free_all_cpu_call_rcu_data();
- return 0;
-
-#if 0
- /*
- * Hash Population needs to be seen as a RCU reader
- * thread from the point of view of resize.
- */
- rcu_register_thread();
- ret = (get_populate_hash_cb())();
- assert(!ret);
+ /* Wait for in-flight call_rcu free to complete for leak detection */
+ rcu_barrier();
- rcu_thread_offline();
+ ret |= check_memory_leaks();
- /* teardown counter thread */
- act.sa_handler = SIG_IGN;
- act.sa_flags = SA_RESTART;
- ret = sigaction(SIGUSR2, &act, NULL);
- if (ret == -1) {
- perror("sigaction");
- return -1;
- }
- {
- char msg[1] = { 0x42 };
- ssize_t ret;
-
- do {
- ret = write(count_pipe[1], msg, 1); /* wakeup thread */
- } while (ret == -1L && errno == EINTR);
- }
+ rcu_unregister_thread();
+ free_all_cpu_call_rcu_data();
- fflush(stdout);
- rcu_thread_online();
- rcu_read_lock();
- printf("Counting nodes... ");
- cds_lfht_count_nodes(test_ht, &approx_before, &count, &approx_after);
- printf("done.\n");
- test_delete_all_nodes(test_ht);
- rcu_read_unlock();
- rcu_thread_offline();
- if (count) {
- printf("Approximation before node accounting: %ld nodes.\n",
- approx_before);
- printf("Nodes deleted from hash table before destroy: "
- "%lu nodes.\n",
- count);
- printf("Approximation after node accounting: %ld nodes.\n",
- approx_after);
+ if (ret) {
+ printf("Test ended with error: %d\n", ret);
}
- ret = cds_lfht_destroy(test_ht, NULL);
- if (ret)
- printf_verbose("final delete aborted\n");
- else
- printf_verbose("final delete success\n");
- printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
- tot_writes);
- printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
- "nr_writers %3u "
- "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
- "nr_add %12llu nr_add_fail %12llu nr_remove %12llu nr_leaked %12lld\n",
- 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);
- rcu_unregister_thread();
-#endif
- return 0;
+ return ret;
}