rcuja test: use poison_free
[urcu.git] / tests / test_urcu_ja.c
CommitLineData
44151f89
MD
1/*
2 * test_urcu_ja.c
3 *
4 * Userspace RCU library - test program
5 *
6 * Copyright 2009-2012 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#define _GNU_SOURCE
24#include "test_urcu_ja.h"
a2a7ff59 25#include <inttypes.h>
582a6ade 26#include <stdint.h>
44151f89
MD
27
28DEFINE_URCU_TLS(unsigned int, rand_lookup);
29DEFINE_URCU_TLS(unsigned long, nr_add);
30DEFINE_URCU_TLS(unsigned long, nr_addexist);
31DEFINE_URCU_TLS(unsigned long, nr_del);
32DEFINE_URCU_TLS(unsigned long, nr_delnoent);
33DEFINE_URCU_TLS(unsigned long, lookup_fail);
34DEFINE_URCU_TLS(unsigned long, lookup_ok);
35
36struct cds_ja *test_ja;
37
38volatile int test_go, test_stop;
39
40unsigned long wdelay;
41
42unsigned long duration;
43
44/* read-side C.S. duration, in loops */
45unsigned long rduration;
46
47unsigned long init_populate;
48int add_only;
49
50unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
51unsigned long init_pool_size = DEFAULT_RAND_POOL,
52 lookup_pool_size = DEFAULT_RAND_POOL,
53 write_pool_size = DEFAULT_RAND_POOL;
54int validate_lookup;
1a0c0717
MD
55int sanity_test;
56unsigned int key_bits = 32;
44151f89
MD
57
58int count_pipe[2];
59
60int verbose_mode;
61
62unsigned int cpu_affinities[NR_CPUS];
63unsigned int next_aff = 0;
64int use_affinity = 0;
65
66pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
67
68DEFINE_URCU_TLS(unsigned long long, nr_writes);
69DEFINE_URCU_TLS(unsigned long long, nr_reads);
70
71unsigned int nr_readers;
72unsigned int nr_writers;
73
74static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
75
76void set_affinity(void)
77{
78 cpu_set_t mask;
79 int cpu;
80 int ret;
81
82 if (!use_affinity)
83 return;
84
85#if HAVE_SCHED_SETAFFINITY
86 ret = pthread_mutex_lock(&affinity_mutex);
87 if (ret) {
88 perror("Error in pthread mutex lock");
89 exit(-1);
90 }
91 cpu = cpu_affinities[next_aff++];
92 ret = pthread_mutex_unlock(&affinity_mutex);
93 if (ret) {
94 perror("Error in pthread mutex unlock");
95 exit(-1);
96 }
97 CPU_ZERO(&mask);
98 CPU_SET(cpu, &mask);
99#if SCHED_SETAFFINITY_ARGS == 2
100 sched_setaffinity(0, &mask);
101#else
102 sched_setaffinity(0, sizeof(mask), &mask);
103#endif
104#endif /* HAVE_SCHED_SETAFFINITY */
105}
106
107void rcu_copy_mutex_lock(void)
108{
109 int ret;
110 ret = pthread_mutex_lock(&rcu_copy_mutex);
111 if (ret) {
112 perror("Error in pthread mutex lock");
113 exit(-1);
114 }
115}
116
117void rcu_copy_mutex_unlock(void)
118{
119 int ret;
120
121 ret = pthread_mutex_unlock(&rcu_copy_mutex);
122 if (ret) {
123 perror("Error in pthread mutex unlock");
124 exit(-1);
125 }
126}
127
44151f89
MD
128void free_node_cb(struct rcu_head *head)
129{
130 struct ja_test_node *node =
3d8fe307 131 caa_container_of(head, struct ja_test_node, node.head);
a7542b7f 132 poison_free(node);
44151f89
MD
133}
134
3d8fe307 135#if 0
44151f89
MD
136static
137void test_delete_all_nodes(struct cds_lfht *ht)
138{
139 struct cds_lfht_iter iter;
140 struct lfht_test_node *node;
141 unsigned long count = 0;
142
143 cds_lfht_for_each_entry(ht, &iter, node, node) {
144 int ret;
145
146 ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
147 assert(!ret);
148 call_rcu(&node->head, free_node_cb);
149 count++;
150 }
151 printf("deleted %lu nodes.\n", count);
152}
153#endif
154
155void show_usage(int argc, char **argv)
156{
157 printf("Usage : %s nr_readers nr_writers duration (s)\n", argv[0]);
158#ifdef DEBUG_YIELD
159 printf(" [-r] [-w] (yield reader and/or writer)\n");
160#endif
161 printf(" [-d delay] (writer period (us))\n");
162 printf(" [-c duration] (reader C.S. duration (in loops))\n");
163 printf(" [-v] (verbose output)\n");
164 printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
165printf(" [not -u nor -s] Add entries (supports redundant keys).\n");
166 printf(" [-i] Add only (no removal).\n");
167 printf(" [-k nr_nodes] Number of nodes to insert initially.\n");
168 printf(" [-R offset] Lookup pool offset.\n");
169 printf(" [-S offset] Write pool offset.\n");
170 printf(" [-T offset] Init pool offset.\n");
171 printf(" [-M size] Lookup pool size.\n");
172 printf(" [-N size] Write pool size.\n");
173 printf(" [-O size] Init pool size.\n");
174 printf(" [-V] Validate lookups of init values (use with filled init pool, same lookup range, with different write range).\n");
1a0c0717
MD
175 printf(" [-s] Do sanity test.\n");
176 printf(" [-B] Key bits for multithread test (default: 32).\n");
44151f89
MD
177 printf("\n\n");
178}
179
582a6ade
MD
180
181static
182int test_8bit_key(void)
183{
184 int ret;
185 uint64_t key;
186
187 /* Test with 8-bit key */
188 test_ja = cds_ja_new(8);
189 if (!test_ja) {
190 printf("Error allocating judy array.\n");
191 return -1;
192 }
193
194 /* Add keys */
195 printf("Test #1: add keys (8-bit).\n");
196 for (key = 0; key < 200; key++) {
197 struct ja_test_node *node =
198 calloc(sizeof(*node), 1);
199
200 ja_test_node_init(node, key);
201 rcu_read_lock();
202 ret = cds_ja_add(test_ja, key, &node->node);
203 rcu_read_unlock();
204 if (ret) {
205 fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
206 ret, key);
207 assert(0);
208 }
209 }
210 printf("OK\n");
211
212 printf("Test #2: successful key lookup (8-bit).\n");
213 for (key = 0; key < 200; key++) {
af3cbd45 214 struct cds_hlist_head head;
582a6ade
MD
215
216 rcu_read_lock();
217 head = cds_ja_lookup(test_ja, key);
af3cbd45 218 if (cds_hlist_empty(&head)) {
582a6ade
MD
219 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
220 assert(0);
221 }
222 rcu_read_unlock();
223 }
224 printf("OK\n");
225 printf("Test #3: unsuccessful key lookup (8-bit).\n");
226 for (key = 200; key < 240; key++) {
af3cbd45 227 struct cds_hlist_head head;
582a6ade
MD
228
229 rcu_read_lock();
230 head = cds_ja_lookup(test_ja, key);
af3cbd45 231 if (!cds_hlist_empty(&head)) {
582a6ade
MD
232 fprintf(stderr,
233 "Error unexpected lookup node %" PRIu64 "\n",
234 key);
235 assert(0);
236 }
237 rcu_read_unlock();
238 }
239 printf("OK\n");
3d8fe307
MD
240 printf("Test #4: remove keys (8-bit).\n");
241 for (key = 0; key < 200; key++) {
242 struct cds_hlist_head head;
243 struct ja_test_node *node;
244
245 rcu_read_lock();
246 head = cds_ja_lookup(test_ja, key);
247 node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
248 if (!node) {
249 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
250 assert(0);
251 }
252 ret = cds_ja_del(test_ja, key, &node->node);
253 if (ret) {
254 fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
255 assert(0);
256 }
257 call_rcu(&node->node.head, free_node_cb);
4d6ef45e
MD
258 head = cds_ja_lookup(test_ja, key);
259 if (!cds_hlist_empty(&head)) {
260 fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
261 assert(0);
262 }
3d8fe307
MD
263 rcu_read_unlock();
264 }
265 printf("OK\n");
582a6ade 266
3d8fe307 267 ret = cds_ja_destroy(test_ja, free_node_cb);
582a6ade
MD
268 if (ret) {
269 fprintf(stderr, "Error destroying judy array\n");
270 return -1;
271 }
272 return 0;
273}
274
275static
276int test_16bit_key(void)
277{
278 int ret;
279 uint64_t key;
280
281 /* Test with 16-bit key */
282 test_ja = cds_ja_new(16);
283 if (!test_ja) {
284 printf("Error allocating judy array.\n");
285 return -1;
286 }
287
288 /* Add keys */
289 printf("Test #1: add keys (16-bit).\n");
4d6ef45e
MD
290 for (key = 0; key < 10000; key++) {
291 //for (key = 0; key < 65536; key+=256) {
582a6ade
MD
292 struct ja_test_node *node =
293 calloc(sizeof(*node), 1);
294
295 ja_test_node_init(node, key);
296 rcu_read_lock();
297 ret = cds_ja_add(test_ja, key, &node->node);
298 rcu_read_unlock();
299 if (ret) {
300 fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
301 ret, key);
302 assert(0);
303 }
304 }
305 printf("OK\n");
306
307 printf("Test #2: successful key lookup (16-bit).\n");
4d6ef45e
MD
308 for (key = 0; key < 10000; key++) {
309 //for (key = 0; key < 65536; key+=256) {
af3cbd45 310 struct cds_hlist_head head;
582a6ade
MD
311
312 rcu_read_lock();
313 head = cds_ja_lookup(test_ja, key);
af3cbd45 314 if (cds_hlist_empty(&head)) {
582a6ade
MD
315 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
316 assert(0);
317 }
318 rcu_read_unlock();
319 }
320 printf("OK\n");
321 printf("Test #3: unsuccessful key lookup (16-bit).\n");
322 for (key = 11000; key <= 11002; key++) {
af3cbd45 323 struct cds_hlist_head head;
582a6ade
MD
324
325 rcu_read_lock();
326 head = cds_ja_lookup(test_ja, key);
af3cbd45 327 if (!cds_hlist_empty(&head)) {
582a6ade
MD
328 fprintf(stderr,
329 "Error unexpected lookup node %" PRIu64 "\n",
330 key);
331 assert(0);
332 }
333 rcu_read_unlock();
334 }
335 printf("OK\n");
4d6ef45e
MD
336 printf("Test #4: remove keys (16-bit).\n");
337 for (key = 0; key < 10000; key++) {
338 //for (key = 0; key < 65536; key+=256) {
339 struct cds_hlist_head head;
340 struct ja_test_node *node;
341
342 rcu_read_lock();
343 head = cds_ja_lookup(test_ja, key);
344 node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
345 if (!node) {
346 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
347 assert(0);
348 }
349 ret = cds_ja_del(test_ja, key, &node->node);
350 if (ret) {
351 fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
352 assert(0);
353 }
354 call_rcu(&node->node.head, free_node_cb);
355 head = cds_ja_lookup(test_ja, key);
356 if (!cds_hlist_empty(&head)) {
357 fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
358 assert(0);
359 }
360 rcu_read_unlock();
361 }
362 printf("OK\n");
582a6ade 363
3d8fe307 364 ret = cds_ja_destroy(test_ja, free_node_cb);
582a6ade
MD
365 if (ret) {
366 fprintf(stderr, "Error destroying judy array\n");
367 return -1;
368 }
369 return 0;
370}
371
6fdf58e8
MD
372/*
373 * nr_dup is number of nodes per key.
374 */
582a6ade 375static
6fdf58e8 376int test_sparse_key(unsigned int bits, int nr_dup)
582a6ade 377{
582a6ade 378 uint64_t key, max_key;
6fdf58e8 379 int zerocount, i, ret;
582a6ade
MD
380
381 if (bits == 64)
382 max_key = UINT64_MAX;
383 else
384 max_key = (1ULL << bits) - 1;
385
386 printf("Sparse key test begins for %u-bit keys\n", bits);
387 /* Test with 16-bit key */
388 test_ja = cds_ja_new(bits);
389 if (!test_ja) {
390 printf("Error allocating judy array.\n");
391 return -1;
392 }
393
394 /* Add keys */
395 printf("Test #1: add keys (%u-bit).\n", bits);
6fdf58e8
MD
396 for (i = 0; i < nr_dup; i++) {
397 zerocount = 0;
398 for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
399 struct ja_test_node *node =
400 calloc(sizeof(*node), 1);
582a6ade 401
6fdf58e8
MD
402 ja_test_node_init(node, key);
403 rcu_read_lock();
404 ret = cds_ja_add(test_ja, key, &node->node);
405 rcu_read_unlock();
406 if (ret) {
407 fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
408 ret, key);
409 assert(0);
410 }
411 if (key == 0)
412 zerocount++;
582a6ade 413 }
582a6ade
MD
414 }
415 printf("OK\n");
416
417 printf("Test #2: successful key lookup (%u-bit).\n", bits);
418 zerocount = 0;
419 for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
af3cbd45 420 struct cds_hlist_head head;
6fdf58e8
MD
421 struct ja_test_node *node;
422 struct cds_hlist_node *pos;
423 int count = 0;
582a6ade
MD
424
425 rcu_read_lock();
426 head = cds_ja_lookup(test_ja, key);
af3cbd45 427 if (cds_hlist_empty(&head)) {
582a6ade
MD
428 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
429 assert(0);
430 }
6fdf58e8
MD
431 cds_hlist_for_each_entry_rcu(node, pos, &head, node.list) {
432 count++;
433 }
434 if (count != nr_dup) {
435 fprintf(stderr, "Unexpected number of match for key %" PRIu64 ", expected %d, got %d.\n", key, nr_dup, count);
436 }
582a6ade
MD
437 rcu_read_unlock();
438 if (key == 0)
439 zerocount++;
440 }
441 printf("OK\n");
442 if (bits > 8) {
443 printf("Test #3: unsuccessful key lookup (%u-bit).\n", bits);
444 zerocount = 0;
445 for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
af3cbd45 446 struct cds_hlist_head head;
582a6ade
MD
447
448 rcu_read_lock();
449 head = cds_ja_lookup(test_ja, key + 42);
af3cbd45 450 if (!cds_hlist_empty(&head)) {
582a6ade
MD
451 fprintf(stderr,
452 "Error unexpected lookup node %" PRIu64 "\n",
453 key + 42);
454 assert(0);
455 }
456 rcu_read_unlock();
457 if (key == 0)
458 zerocount++;
459 }
460 printf("OK\n");
461 }
4d6ef45e
MD
462 printf("Test #4: remove keys (16-bit).\n");
463 zerocount = 0;
464 for (key = 0; key <= max_key && (key != 0 || zerocount < 1); key += 1ULL << (bits - 8)) {
465 struct cds_hlist_head head;
466 struct ja_test_node *node;
6fdf58e8
MD
467 struct cds_hlist_node *pos;
468 int count = 0;
4d6ef45e
MD
469
470 rcu_read_lock();
471 head = cds_ja_lookup(test_ja, key);
6fdf58e8
MD
472
473
474 cds_hlist_for_each_entry_rcu(node, pos, &head, node.list) {
475 struct cds_hlist_head testhead;
476
477 count++;
478 if (!node) {
479 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
480 assert(0);
481 }
482 ret = cds_ja_del(test_ja, key, &node->node);
483 if (ret) {
484 fprintf(stderr, "Error (%d) removing node %" PRIu64 "\n", ret, key);
485 assert(0);
486 }
487 call_rcu(&node->node.head, free_node_cb);
488 testhead = cds_ja_lookup(test_ja, key);
489 if (count < nr_dup && cds_hlist_empty(&testhead)) {
490 fprintf(stderr, "Error: no node found after deletion of some nodes of a key\n");
491 assert(0);
492 }
4d6ef45e 493 }
4d6ef45e
MD
494 head = cds_ja_lookup(test_ja, key);
495 if (!cds_hlist_empty(&head)) {
496 fprintf(stderr, "Error lookup %" PRIu64 ": %p (after delete) failed. Node is not expected.\n", key, head.next);
497 assert(0);
498 }
499 rcu_read_unlock();
500 if (key == 0)
501 zerocount++;
502 }
503 printf("OK\n");
582a6ade 504
3d8fe307 505 ret = cds_ja_destroy(test_ja, free_node_cb);
582a6ade
MD
506 if (ret) {
507 fprintf(stderr, "Error destroying judy array\n");
508 return -1;
509 }
510 printf("Test ends\n");
511
512 return 0;
513}
514
1a0c0717
MD
515static
516int do_sanity_test(void)
517{
518 int i, j, ret;
582a6ade 519
1a0c0717
MD
520 printf("Sanity test start.\n");
521
522 for (i = 0; i < 3; i++) {
523 ret = test_8bit_key();
524 if (ret) {
525 return ret;
526 }
527 rcu_quiescent_state();
528 }
529 ret = test_16bit_key();
530 if (ret) {
531 return ret;
532 }
533 rcu_quiescent_state();
534
535 /* key bits */
536 for (i = 8; i <= 64; i *= 2) {
537 /* nr of nodes per key */
538 for (j = 1; j < 4; j++) {
539 ret = test_sparse_key(i, j);
540 if (ret) {
541 return ret;
542 }
543 rcu_quiescent_state();
544 }
545 }
546 printf("Sanity test end.\n");
547
548 return 0;
549}
550
551enum urcu_ja_addremove {
552 AR_RANDOM = 0,
553 AR_ADD = 1,
554 AR_REMOVE = -1,
555}; /* 1: add, -1 remove, 0: random */
556
557static enum urcu_ja_addremove addremove; /* 1: add, -1 remove, 0: random */
558
559static
560void test_ja_rw_sigusr1_handler(int signo)
561{
562 switch (addremove) {
563 case AR_ADD:
564 printf("Add/Remove: random.\n");
565 addremove = AR_RANDOM;
566 break;
567 case AR_RANDOM:
568 printf("Add/Remove: remove only.\n");
569 addremove = AR_REMOVE;
570 break;
571 case AR_REMOVE:
572 printf("Add/Remove: add only.\n");
573 addremove = AR_ADD;
574 break;
575 }
576}
577
578static
579void *test_ja_rw_thr_reader(void *_count)
580{
581 unsigned long long *count = _count;
582 struct cds_hlist_head head;
583 uint64_t key;
584
585 printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
586 "reader", pthread_self(), (unsigned long) gettid());
587
588 set_affinity();
589
590 rcu_register_thread();
591
592 while (!test_go)
593 {
594 }
595 cmm_smp_mb();
596
597 for (;;) {
598 rcu_read_lock();
599
600 /* note: only looking up ulong keys */
601 key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % lookup_pool_size) + lookup_pool_offset;
602 head = cds_ja_lookup(test_ja, key);
603 if (cds_hlist_empty(&head)) {
604 if (validate_lookup) {
605 printf("[ERROR] Lookup cannot find initial node.\n");
606 exit(-1);
607 }
608 URCU_TLS(lookup_fail)++;
609 } else {
610 URCU_TLS(lookup_ok)++;
611 }
756c692d 612 rcu_debug_yield_read();
1a0c0717
MD
613 if (caa_unlikely(rduration))
614 loop_sleep(rduration);
615 rcu_read_unlock();
616 URCU_TLS(nr_reads)++;
617 if (caa_unlikely(!test_duration_read()))
618 break;
619 if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
620 rcu_quiescent_state();
621 }
622
623 rcu_unregister_thread();
624
625 *count = URCU_TLS(nr_reads);
626 printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
627 "reader", pthread_self(), (unsigned long) gettid());
628 printf_verbose("readid : %lx, lookupfail %lu, lookupok %lu\n",
629 pthread_self(), URCU_TLS(lookup_fail),
630 URCU_TLS(lookup_ok));
631 return ((void*)1);
632}
633
634static
635void *test_ja_rw_thr_writer(void *_count)
636{
637 struct wr_count *count = _count;
638 struct cds_hlist_head head;
639 uint64_t key;
640 int ret;
641
642 printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n",
643 "writer", pthread_self(), (unsigned long) gettid());
644
645 set_affinity();
646
647 rcu_register_thread();
648
649 while (!test_go)
650 {
651 }
652 cmm_smp_mb();
653
654 for (;;) {
655 if ((addremove == AR_ADD || add_only)
656 || (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
657 struct ja_test_node *node = malloc(sizeof(*node));
658
659 /* note: only inserting ulong keys */
660 key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
661 ja_test_node_init(node, key);
662 rcu_read_lock();
663 ret = cds_ja_add(test_ja, key, &node->node);
664 URCU_TLS(nr_add)++;
665 rcu_read_unlock();
666 if (ret) {
667 fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
668 ret, key);
669 assert(0);
670 }
671 } else {
672 struct ja_test_node *node;
673
674 /* May delete */
675 /* note: only deleting ulong keys */
676 key = ((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset;
677
678 rcu_read_lock();
679
680 head = cds_ja_lookup(test_ja, key);
681 node = cds_hlist_first_entry_rcu(&head, struct ja_test_node, node.list);
682 if (node) {
683 ret = cds_ja_del(test_ja, key, &node->node);
d7069878 684 if (!ret) {
1a0c0717 685 call_rcu(&node->node.head, free_node_cb);
1a0c0717 686 URCU_TLS(nr_del)++;
d7069878
MD
687 } else {
688 URCU_TLS(nr_delnoent)++;
1a0c0717
MD
689 }
690 } else {
691 URCU_TLS(nr_delnoent)++;
692 }
6da38aec 693 rcu_read_unlock();
1a0c0717
MD
694 }
695
696 URCU_TLS(nr_writes)++;
697 if (caa_unlikely(!test_duration_write()))
698 break;
699 if (caa_unlikely(wdelay))
700 loop_sleep(wdelay);
701 if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
702 rcu_quiescent_state();
703 }
704
705 rcu_unregister_thread();
706
707 printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
708 "writer", pthread_self(), (unsigned long) gettid());
709 printf_verbose("info id %lx: nr_add %lu, nr_addexist %lu, nr_del %lu, "
710 "nr_delnoent %lu\n", pthread_self(), URCU_TLS(nr_add),
711 URCU_TLS(nr_addexist), URCU_TLS(nr_del),
712 URCU_TLS(nr_delnoent));
713 count->update_ops = URCU_TLS(nr_writes);
714 count->add = URCU_TLS(nr_add);
715 count->add_exist = URCU_TLS(nr_addexist);
716 count->remove = URCU_TLS(nr_del);
717 return ((void*)2);
718}
719
720static
721int do_mt_populate_ja(void)
722{
723 struct cds_hlist_head head;
724 uint64_t key;
725 int ret;
726
727 if (!init_populate)
728 return 0;
729
730 printf("Starting rw test\n");
731
732 for (key = init_pool_offset; key < init_pool_offset + init_pool_size; key++) {
733 struct ja_test_node *node = malloc(sizeof(*node));
734
735 /* note: only inserting ulong keys */
736 key = (unsigned long) key;
737 ja_test_node_init(node, key);
738 rcu_read_lock();
739 ret = cds_ja_add(test_ja, key, &node->node);
740 URCU_TLS(nr_add)++;
741 URCU_TLS(nr_writes)++;
742 rcu_read_unlock();
743 if (ret) {
744 fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
745 ret, key);
746 assert(0);
747 }
748 }
749 return 0;
750}
751
752static
753int do_mt_test(void)
44151f89 754{
44151f89
MD
755 pthread_t *tid_reader, *tid_writer;
756 void *tret;
1a0c0717 757 int ret, i, err;
44151f89
MD
758 unsigned long long *count_reader;
759 struct wr_count *count_writer;
760 unsigned long long tot_reads = 0, tot_writes = 0,
761 tot_add = 0, tot_add_exist = 0, tot_remove = 0;
44151f89 762 unsigned int remain;
1a0c0717
MD
763
764 tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
765 tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
766 count_reader = malloc(sizeof(*count_reader) * nr_readers);
767 count_writer = malloc(sizeof(*count_writer) * nr_writers);
768
769 printf("Allocating Judy Array for %u-bit keys\n", key_bits);
770 test_ja = cds_ja_new(key_bits);
771 if (!test_ja) {
772 printf("Error allocating judy array.\n");
773 ret = -1;
774 goto end;
775 }
776
777 do_mt_populate_ja();
778
779 next_aff = 0;
780
781 for (i = 0; i < nr_readers; i++) {
782 err = pthread_create(&tid_reader[i],
783 NULL, test_ja_rw_thr_reader,
784 &count_reader[i]);
785 if (err != 0)
786 exit(1);
787 }
788 for (i = 0; i < nr_writers; i++) {
789 err = pthread_create(&tid_writer[i],
790 NULL, test_ja_rw_thr_writer,
791 &count_writer[i]);
792 if (err != 0)
793 exit(1);
794 }
795
796 cmm_smp_mb();
797
798 test_go = 1;
799
800 rcu_thread_offline_qsbr();
801
802 remain = duration;
803 do {
804 remain = sleep(remain);
805 } while (remain > 0);
806
807 test_stop = 1;
808
809 for (i = 0; i < nr_readers; i++) {
810 err = pthread_join(tid_reader[i], &tret);
811 if (err != 0)
812 exit(1);
813 tot_reads += count_reader[i];
814 }
815 for (i = 0; i < nr_writers; i++) {
816 err = pthread_join(tid_writer[i], &tret);
817 if (err != 0)
818 exit(1);
819 tot_writes += count_writer[i].update_ops;
820 tot_add += count_writer[i].add;
821 tot_add_exist += count_writer[i].add_exist;
822 tot_remove += count_writer[i].remove;
823 }
824
825 ret = cds_ja_destroy(test_ja, free_node_cb);
826 if (ret) {
827 fprintf(stderr, "Error destroying judy array\n");
828 goto end;
829 }
830 rcu_thread_online_qsbr();
831
832 free(tid_reader);
833 free(tid_writer);
834 free(count_reader);
835 free(count_writer);
836 ret = 0;
837end:
838 return ret;
839}
840
841int main(int argc, char **argv)
842{
843 int i, j, a, ret, err;
a2a7ff59 844 uint64_t key;
1a0c0717 845 struct sigaction act;
44151f89
MD
846
847 if (argc < 4) {
848 show_usage(argc, argv);
849 return -1;
850 }
851
852 err = sscanf(argv[1], "%u", &nr_readers);
853 if (err != 1) {
854 show_usage(argc, argv);
855 return -1;
856 }
857
858 err = sscanf(argv[2], "%u", &nr_writers);
859 if (err != 1) {
860 show_usage(argc, argv);
861 return -1;
862 }
863
864 err = sscanf(argv[3], "%lu", &duration);
865 if (err != 1) {
866 show_usage(argc, argv);
867 return -1;
868 }
869
870 for (i = 4; i < argc; i++) {
871 if (argv[i][0] != '-')
872 continue;
873 switch (argv[i][1]) {
874#ifdef DEBUG_YIELD
875 case 'r':
876 yield_active |= YIELD_READ;
877 break;
878 case 'w':
879 yield_active |= YIELD_WRITE;
880 break;
881#endif
882 case 'a':
883 if (argc < i + 2) {
884 show_usage(argc, argv);
885 return -1;
886 }
887 a = atoi(argv[++i]);
888 cpu_affinities[next_aff++] = a;
889 use_affinity = 1;
890 printf_verbose("Adding CPU %d affinity\n", a);
891 break;
892 case 'c':
893 if (argc < i + 2) {
894 show_usage(argc, argv);
895 return -1;
896 }
897 rduration = atol(argv[++i]);
898 break;
899 case 'd':
900 if (argc < i + 2) {
901 show_usage(argc, argv);
902 return -1;
903 }
904 wdelay = atol(argv[++i]);
905 break;
906 case 'v':
907 verbose_mode = 1;
908 break;
909 case 'i':
910 add_only = 1;
911 break;
912 case 'k':
913 init_populate = atol(argv[++i]);
914 break;
915 case 'R':
916 lookup_pool_offset = atol(argv[++i]);
917 break;
918 case 'S':
919 write_pool_offset = atol(argv[++i]);
920 break;
921 case 'T':
922 init_pool_offset = atol(argv[++i]);
923 break;
924 case 'M':
925 lookup_pool_size = atol(argv[++i]);
926 break;
927 case 'N':
928 write_pool_size = atol(argv[++i]);
929 break;
930 case 'O':
931 init_pool_size = atol(argv[++i]);
932 break;
933 case 'V':
934 validate_lookup = 1;
935 break;
1a0c0717
MD
936 case 's':
937 sanity_test = 1;
938 break;
939 case 'B':
940 key_bits = atol(argv[++i]);
941 break;
44151f89
MD
942 }
943 }
944
945 printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
946 duration, nr_readers, nr_writers);
947 printf_verbose("Writer delay : %lu loops.\n", wdelay);
948 printf_verbose("Reader duration : %lu loops.\n", rduration);
949 printf_verbose("Mode:%s.\n",
950 add_only ? " add only" : " add/delete");
951 printf_verbose("Init pool size offset %lu size %lu.\n",
952 init_pool_offset, init_pool_size);
953 printf_verbose("Lookup pool size offset %lu size %lu.\n",
954 lookup_pool_offset, lookup_pool_size);
955 printf_verbose("Update pool size offset %lu size %lu.\n",
956 write_pool_offset, write_pool_size);
957 printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
958 "main", pthread_self(), (unsigned long)gettid());
959
1a0c0717
MD
960 memset(&act, 0, sizeof(act));
961 ret = sigemptyset(&act.sa_mask);
962 if (ret == -1) {
963 perror("sigemptyset");
964 return -1;
965 }
966 act.sa_handler = test_ja_rw_sigusr1_handler;
967 act.sa_flags = SA_RESTART;
968 ret = sigaction(SIGUSR1, &act, NULL);
969 if (ret == -1) {
970 perror("sigaction");
971 return -1;
972 }
44151f89
MD
973
974 err = create_all_cpu_call_rcu_data(0);
975 if (err) {
976 printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
977 }
978
582a6ade 979 rcu_register_thread();
44151f89 980
1a0c0717
MD
981 if (sanity_test) {
982 ret = do_sanity_test();
44151f89 983 if (ret) {
1a0c0717 984 fprintf(stderr, "Error in sanity test\n");
44151f89 985 }
1a0c0717
MD
986 } else {
987 do_mt_test();
44151f89 988 }
a2a7ff59 989
582a6ade 990 rcu_unregister_thread();
1a0c0717 991 free_all_cpu_call_rcu_data();
44151f89
MD
992 return 0;
993
994#if 0
995 /*
996 * Hash Population needs to be seen as a RCU reader
997 * thread from the point of view of resize.
998 */
999 rcu_register_thread();
1000 ret = (get_populate_hash_cb())();
1001 assert(!ret);
1002
1003 rcu_thread_offline();
1004
44151f89
MD
1005 /* teardown counter thread */
1006 act.sa_handler = SIG_IGN;
1007 act.sa_flags = SA_RESTART;
1008 ret = sigaction(SIGUSR2, &act, NULL);
1009 if (ret == -1) {
1010 perror("sigaction");
1011 return -1;
1012 }
1013 {
1014 char msg[1] = { 0x42 };
1015 ssize_t ret;
1016
1017 do {
1018 ret = write(count_pipe[1], msg, 1); /* wakeup thread */
1019 } while (ret == -1L && errno == EINTR);
1020 }
1021
1022 fflush(stdout);
1023 rcu_thread_online();
1024 rcu_read_lock();
1025 printf("Counting nodes... ");
1026 cds_lfht_count_nodes(test_ht, &approx_before, &count, &approx_after);
1027 printf("done.\n");
1028 test_delete_all_nodes(test_ht);
1029 rcu_read_unlock();
1030 rcu_thread_offline();
1031 if (count) {
1032 printf("Approximation before node accounting: %ld nodes.\n",
1033 approx_before);
1034 printf("Nodes deleted from hash table before destroy: "
1035 "%lu nodes.\n",
1036 count);
1037 printf("Approximation after node accounting: %ld nodes.\n",
1038 approx_after);
1039 }
1040 ret = cds_lfht_destroy(test_ht, NULL);
1041 if (ret)
1042 printf_verbose("final delete aborted\n");
1043 else
1044 printf_verbose("final delete success\n");
1045 printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
1046 tot_writes);
1047 printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
1048 "nr_writers %3u "
1049 "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
1050 "nr_add %12llu nr_add_fail %12llu nr_remove %12llu nr_leaked %12lld\n",
1051 argv[0], duration, nr_readers, rduration,
1052 nr_writers, wdelay, tot_reads, tot_writes,
1053 tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
1054 (long long) tot_add + init_populate - tot_remove - count);
1055 rcu_unregister_thread();
44151f89
MD
1056#endif
1057 return 0;
1058}
This page took 0.066992 seconds and 4 git commands to generate.