ab23982033e87c646c3ddc0b986daaadf3f62a87
[urcu.git] / tests / test_urcu_ja.c
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"
25 #include <inttypes.h>
26 #include <stdint.h>
27
28 DEFINE_URCU_TLS(unsigned int, rand_lookup);
29 DEFINE_URCU_TLS(unsigned long, nr_add);
30 DEFINE_URCU_TLS(unsigned long, nr_addexist);
31 DEFINE_URCU_TLS(unsigned long, nr_del);
32 DEFINE_URCU_TLS(unsigned long, nr_delnoent);
33 DEFINE_URCU_TLS(unsigned long, lookup_fail);
34 DEFINE_URCU_TLS(unsigned long, lookup_ok);
35
36 struct cds_ja *test_ja;
37
38 volatile int test_go, test_stop;
39
40 unsigned long wdelay;
41
42 unsigned long duration;
43
44 /* read-side C.S. duration, in loops */
45 unsigned long rduration;
46
47 unsigned long init_populate;
48 int add_only;
49
50 unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
51 unsigned long init_pool_size = DEFAULT_RAND_POOL,
52 lookup_pool_size = DEFAULT_RAND_POOL,
53 write_pool_size = DEFAULT_RAND_POOL;
54 int validate_lookup;
55 int sanity_test;
56 unsigned int key_bits = 32;
57
58 int count_pipe[2];
59
60 int verbose_mode;
61
62 unsigned int cpu_affinities[NR_CPUS];
63 unsigned int next_aff = 0;
64 int use_affinity = 0;
65
66 pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
67
68 DEFINE_URCU_TLS(unsigned long long, nr_writes);
69 DEFINE_URCU_TLS(unsigned long long, nr_reads);
70
71 unsigned int nr_readers;
72 unsigned int nr_writers;
73
74 static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
75
76 void 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
107 void 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
117 void 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
128 void free_node_cb(struct rcu_head *head)
129 {
130 struct ja_test_node *node =
131 caa_container_of(head, struct ja_test_node, node.head);
132 free(node);
133 }
134
135 #if 0
136 static
137 void 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
155 void 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");
165 printf(" [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");
175 printf(" [-s] Do sanity test.\n");
176 printf(" [-B] Key bits for multithread test (default: 32).\n");
177 printf("\n\n");
178 }
179
180
181 static
182 int 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++) {
214 struct cds_hlist_head head;
215
216 rcu_read_lock();
217 head = cds_ja_lookup(test_ja, key);
218 if (cds_hlist_empty(&head)) {
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++) {
227 struct cds_hlist_head head;
228
229 rcu_read_lock();
230 head = cds_ja_lookup(test_ja, key);
231 if (!cds_hlist_empty(&head)) {
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");
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);
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 }
263 rcu_read_unlock();
264 }
265 printf("OK\n");
266
267 ret = cds_ja_destroy(test_ja, free_node_cb);
268 if (ret) {
269 fprintf(stderr, "Error destroying judy array\n");
270 return -1;
271 }
272 return 0;
273 }
274
275 static
276 int 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");
290 for (key = 0; key < 10000; key++) {
291 //for (key = 0; key < 65536; key+=256) {
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");
308 for (key = 0; key < 10000; key++) {
309 //for (key = 0; key < 65536; key+=256) {
310 struct cds_hlist_head head;
311
312 rcu_read_lock();
313 head = cds_ja_lookup(test_ja, key);
314 if (cds_hlist_empty(&head)) {
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++) {
323 struct cds_hlist_head head;
324
325 rcu_read_lock();
326 head = cds_ja_lookup(test_ja, key);
327 if (!cds_hlist_empty(&head)) {
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");
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");
363
364 ret = cds_ja_destroy(test_ja, free_node_cb);
365 if (ret) {
366 fprintf(stderr, "Error destroying judy array\n");
367 return -1;
368 }
369 return 0;
370 }
371
372 /*
373 * nr_dup is number of nodes per key.
374 */
375 static
376 int test_sparse_key(unsigned int bits, int nr_dup)
377 {
378 uint64_t key, max_key;
379 int zerocount, i, ret;
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);
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);
401
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++;
413 }
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)) {
420 struct cds_hlist_head head;
421 struct ja_test_node *node;
422 struct cds_hlist_node *pos;
423 int count = 0;
424
425 rcu_read_lock();
426 head = cds_ja_lookup(test_ja, key);
427 if (cds_hlist_empty(&head)) {
428 fprintf(stderr, "Error lookup node %" PRIu64 "\n", key);
429 assert(0);
430 }
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 }
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)) {
446 struct cds_hlist_head head;
447
448 rcu_read_lock();
449 head = cds_ja_lookup(test_ja, key + 42);
450 if (!cds_hlist_empty(&head)) {
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 }
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;
467 struct cds_hlist_node *pos;
468 int count = 0;
469
470 rcu_read_lock();
471 head = cds_ja_lookup(test_ja, key);
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 }
493 }
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");
504
505 ret = cds_ja_destroy(test_ja, free_node_cb);
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
515 static
516 int do_sanity_test(void)
517 {
518 int i, j, ret;
519
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
551 enum urcu_ja_addremove {
552 AR_RANDOM = 0,
553 AR_ADD = 1,
554 AR_REMOVE = -1,
555 }; /* 1: add, -1 remove, 0: random */
556
557 static enum urcu_ja_addremove addremove; /* 1: add, -1 remove, 0: random */
558
559 static
560 void 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
578 static
579 void *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 }
612 rcu_debug_yield_read();
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
634 static
635 void *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);
684 if (!ret) {
685 call_rcu(&node->node.head, free_node_cb);
686 URCU_TLS(nr_del)++;
687 } else {
688 URCU_TLS(nr_delnoent)++;
689 }
690 } else {
691 URCU_TLS(nr_delnoent)++;
692 }
693 }
694
695 URCU_TLS(nr_writes)++;
696 if (caa_unlikely(!test_duration_write()))
697 break;
698 if (caa_unlikely(wdelay))
699 loop_sleep(wdelay);
700 if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
701 rcu_quiescent_state();
702 }
703
704 rcu_unregister_thread();
705
706 printf_verbose("thread_end %s, thread id : %lx, tid %lu\n",
707 "writer", pthread_self(), (unsigned long) gettid());
708 printf_verbose("info id %lx: nr_add %lu, nr_addexist %lu, nr_del %lu, "
709 "nr_delnoent %lu\n", pthread_self(), URCU_TLS(nr_add),
710 URCU_TLS(nr_addexist), URCU_TLS(nr_del),
711 URCU_TLS(nr_delnoent));
712 count->update_ops = URCU_TLS(nr_writes);
713 count->add = URCU_TLS(nr_add);
714 count->add_exist = URCU_TLS(nr_addexist);
715 count->remove = URCU_TLS(nr_del);
716 return ((void*)2);
717 }
718
719 static
720 int do_mt_populate_ja(void)
721 {
722 struct cds_hlist_head head;
723 uint64_t key;
724 int ret;
725
726 if (!init_populate)
727 return 0;
728
729 printf("Starting rw test\n");
730
731 for (key = init_pool_offset; key < init_pool_offset + init_pool_size; key++) {
732 struct ja_test_node *node = malloc(sizeof(*node));
733
734 /* note: only inserting ulong keys */
735 key = (unsigned long) key;
736 ja_test_node_init(node, key);
737 rcu_read_lock();
738 ret = cds_ja_add(test_ja, key, &node->node);
739 URCU_TLS(nr_add)++;
740 URCU_TLS(nr_writes)++;
741 rcu_read_unlock();
742 if (ret) {
743 fprintf(stderr, "Error (%d) adding node %" PRIu64 "\n",
744 ret, key);
745 assert(0);
746 }
747 }
748 return 0;
749 }
750
751 static
752 int do_mt_test(void)
753 {
754 pthread_t *tid_reader, *tid_writer;
755 void *tret;
756 int ret, i, err;
757 unsigned long long *count_reader;
758 struct wr_count *count_writer;
759 unsigned long long tot_reads = 0, tot_writes = 0,
760 tot_add = 0, tot_add_exist = 0, tot_remove = 0;
761 unsigned int remain;
762
763 tid_reader = malloc(sizeof(*tid_reader) * nr_readers);
764 tid_writer = malloc(sizeof(*tid_writer) * nr_writers);
765 count_reader = malloc(sizeof(*count_reader) * nr_readers);
766 count_writer = malloc(sizeof(*count_writer) * nr_writers);
767
768 printf("Allocating Judy Array for %u-bit keys\n", key_bits);
769 test_ja = cds_ja_new(key_bits);
770 if (!test_ja) {
771 printf("Error allocating judy array.\n");
772 ret = -1;
773 goto end;
774 }
775
776 do_mt_populate_ja();
777
778 next_aff = 0;
779
780 for (i = 0; i < nr_readers; i++) {
781 err = pthread_create(&tid_reader[i],
782 NULL, test_ja_rw_thr_reader,
783 &count_reader[i]);
784 if (err != 0)
785 exit(1);
786 }
787 for (i = 0; i < nr_writers; i++) {
788 err = pthread_create(&tid_writer[i],
789 NULL, test_ja_rw_thr_writer,
790 &count_writer[i]);
791 if (err != 0)
792 exit(1);
793 }
794
795 cmm_smp_mb();
796
797 test_go = 1;
798
799 rcu_thread_offline_qsbr();
800
801 remain = duration;
802 do {
803 remain = sleep(remain);
804 } while (remain > 0);
805
806 test_stop = 1;
807
808 for (i = 0; i < nr_readers; i++) {
809 err = pthread_join(tid_reader[i], &tret);
810 if (err != 0)
811 exit(1);
812 tot_reads += count_reader[i];
813 }
814 for (i = 0; i < nr_writers; i++) {
815 err = pthread_join(tid_writer[i], &tret);
816 if (err != 0)
817 exit(1);
818 tot_writes += count_writer[i].update_ops;
819 tot_add += count_writer[i].add;
820 tot_add_exist += count_writer[i].add_exist;
821 tot_remove += count_writer[i].remove;
822 }
823
824 ret = cds_ja_destroy(test_ja, free_node_cb);
825 if (ret) {
826 fprintf(stderr, "Error destroying judy array\n");
827 goto end;
828 }
829 rcu_thread_online_qsbr();
830
831 free(tid_reader);
832 free(tid_writer);
833 free(count_reader);
834 free(count_writer);
835 ret = 0;
836 end:
837 return ret;
838 }
839
840 int main(int argc, char **argv)
841 {
842 int i, j, a, ret, err;
843 uint64_t key;
844 struct sigaction act;
845
846 if (argc < 4) {
847 show_usage(argc, argv);
848 return -1;
849 }
850
851 err = sscanf(argv[1], "%u", &nr_readers);
852 if (err != 1) {
853 show_usage(argc, argv);
854 return -1;
855 }
856
857 err = sscanf(argv[2], "%u", &nr_writers);
858 if (err != 1) {
859 show_usage(argc, argv);
860 return -1;
861 }
862
863 err = sscanf(argv[3], "%lu", &duration);
864 if (err != 1) {
865 show_usage(argc, argv);
866 return -1;
867 }
868
869 for (i = 4; i < argc; i++) {
870 if (argv[i][0] != '-')
871 continue;
872 switch (argv[i][1]) {
873 #ifdef DEBUG_YIELD
874 case 'r':
875 yield_active |= YIELD_READ;
876 break;
877 case 'w':
878 yield_active |= YIELD_WRITE;
879 break;
880 #endif
881 case 'a':
882 if (argc < i + 2) {
883 show_usage(argc, argv);
884 return -1;
885 }
886 a = atoi(argv[++i]);
887 cpu_affinities[next_aff++] = a;
888 use_affinity = 1;
889 printf_verbose("Adding CPU %d affinity\n", a);
890 break;
891 case 'c':
892 if (argc < i + 2) {
893 show_usage(argc, argv);
894 return -1;
895 }
896 rduration = atol(argv[++i]);
897 break;
898 case 'd':
899 if (argc < i + 2) {
900 show_usage(argc, argv);
901 return -1;
902 }
903 wdelay = atol(argv[++i]);
904 break;
905 case 'v':
906 verbose_mode = 1;
907 break;
908 case 'i':
909 add_only = 1;
910 break;
911 case 'k':
912 init_populate = atol(argv[++i]);
913 break;
914 case 'R':
915 lookup_pool_offset = atol(argv[++i]);
916 break;
917 case 'S':
918 write_pool_offset = atol(argv[++i]);
919 break;
920 case 'T':
921 init_pool_offset = atol(argv[++i]);
922 break;
923 case 'M':
924 lookup_pool_size = atol(argv[++i]);
925 break;
926 case 'N':
927 write_pool_size = atol(argv[++i]);
928 break;
929 case 'O':
930 init_pool_size = atol(argv[++i]);
931 break;
932 case 'V':
933 validate_lookup = 1;
934 break;
935 case 's':
936 sanity_test = 1;
937 break;
938 case 'B':
939 key_bits = atol(argv[++i]);
940 break;
941 }
942 }
943
944 printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
945 duration, nr_readers, nr_writers);
946 printf_verbose("Writer delay : %lu loops.\n", wdelay);
947 printf_verbose("Reader duration : %lu loops.\n", rduration);
948 printf_verbose("Mode:%s.\n",
949 add_only ? " add only" : " add/delete");
950 printf_verbose("Init pool size offset %lu size %lu.\n",
951 init_pool_offset, init_pool_size);
952 printf_verbose("Lookup pool size offset %lu size %lu.\n",
953 lookup_pool_offset, lookup_pool_size);
954 printf_verbose("Update pool size offset %lu size %lu.\n",
955 write_pool_offset, write_pool_size);
956 printf_verbose("thread %-6s, thread id : %lx, tid %lu\n",
957 "main", pthread_self(), (unsigned long)gettid());
958
959 memset(&act, 0, sizeof(act));
960 ret = sigemptyset(&act.sa_mask);
961 if (ret == -1) {
962 perror("sigemptyset");
963 return -1;
964 }
965 act.sa_handler = test_ja_rw_sigusr1_handler;
966 act.sa_flags = SA_RESTART;
967 ret = sigaction(SIGUSR1, &act, NULL);
968 if (ret == -1) {
969 perror("sigaction");
970 return -1;
971 }
972
973 err = create_all_cpu_call_rcu_data(0);
974 if (err) {
975 printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
976 }
977
978 rcu_register_thread();
979
980 if (sanity_test) {
981 ret = do_sanity_test();
982 if (ret) {
983 fprintf(stderr, "Error in sanity test\n");
984 }
985 } else {
986 do_mt_test();
987 }
988
989 rcu_unregister_thread();
990 free_all_cpu_call_rcu_data();
991 return 0;
992
993 #if 0
994 /*
995 * Hash Population needs to be seen as a RCU reader
996 * thread from the point of view of resize.
997 */
998 rcu_register_thread();
999 ret = (get_populate_hash_cb())();
1000 assert(!ret);
1001
1002 rcu_thread_offline();
1003
1004 /* teardown counter thread */
1005 act.sa_handler = SIG_IGN;
1006 act.sa_flags = SA_RESTART;
1007 ret = sigaction(SIGUSR2, &act, NULL);
1008 if (ret == -1) {
1009 perror("sigaction");
1010 return -1;
1011 }
1012 {
1013 char msg[1] = { 0x42 };
1014 ssize_t ret;
1015
1016 do {
1017 ret = write(count_pipe[1], msg, 1); /* wakeup thread */
1018 } while (ret == -1L && errno == EINTR);
1019 }
1020
1021 fflush(stdout);
1022 rcu_thread_online();
1023 rcu_read_lock();
1024 printf("Counting nodes... ");
1025 cds_lfht_count_nodes(test_ht, &approx_before, &count, &approx_after);
1026 printf("done.\n");
1027 test_delete_all_nodes(test_ht);
1028 rcu_read_unlock();
1029 rcu_thread_offline();
1030 if (count) {
1031 printf("Approximation before node accounting: %ld nodes.\n",
1032 approx_before);
1033 printf("Nodes deleted from hash table before destroy: "
1034 "%lu nodes.\n",
1035 count);
1036 printf("Approximation after node accounting: %ld nodes.\n",
1037 approx_after);
1038 }
1039 ret = cds_lfht_destroy(test_ht, NULL);
1040 if (ret)
1041 printf_verbose("final delete aborted\n");
1042 else
1043 printf_verbose("final delete success\n");
1044 printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
1045 tot_writes);
1046 printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
1047 "nr_writers %3u "
1048 "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
1049 "nr_add %12llu nr_add_fail %12llu nr_remove %12llu nr_leaked %12lld\n",
1050 argv[0], duration, nr_readers, rduration,
1051 nr_writers, wdelay, tot_reads, tot_writes,
1052 tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
1053 (long long) tot_add + init_populate - tot_remove - count);
1054 rcu_unregister_thread();
1055 #endif
1056 return 0;
1057 }
This page took 0.049256 seconds and 3 git commands to generate.