Commit | Line | Data |
---|---|---|
dff86257 MD |
1 | /* |
2 | * test_urcu_rbtree.c | |
3 | * | |
4 | * Userspace RCU library - test program for RB tree | |
5 | * | |
6 | * Copyright February 2010 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
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 | #ifndef DYNAMIC_LINK_TEST | |
25 | #define _LGPL_SOURCE | |
26 | #else | |
27 | #define debug_yield_read() | |
28 | #endif | |
29 | #include "../config.h" | |
30 | #include <stdio.h> | |
31 | #include <pthread.h> | |
32 | #include <stdlib.h> | |
33 | #include <string.h> | |
34 | #include <sys/types.h> | |
35 | #include <sys/wait.h> | |
36 | #include <unistd.h> | |
37 | #include <stdio.h> | |
38 | #include <assert.h> | |
39 | #include <sys/syscall.h> | |
40 | #include <sched.h> | |
41 | #include <errno.h> | |
42 | #include <time.h> | |
43 | ||
44 | #include <urcu/arch.h> | |
45 | ||
a84e8c8e MD |
46 | extern int __thread disable_debug; |
47 | ||
dff86257 MD |
48 | /* hardcoded number of CPUs */ |
49 | #define NR_CPUS 16384 | |
50 | ||
51 | /* number of insert/delete */ | |
dbe4ae98 MD |
52 | #define NR_RAND 6 |
53 | //#define NR_RAND 7 | |
dff86257 MD |
54 | |
55 | #if defined(_syscall0) | |
56 | _syscall0(pid_t, gettid) | |
57 | #elif defined(__NR_gettid) | |
58 | static inline pid_t gettid(void) | |
59 | { | |
60 | return syscall(__NR_gettid); | |
61 | } | |
62 | #else | |
63 | #warning "use pid as tid" | |
64 | static inline pid_t gettid(void) | |
65 | { | |
66 | return getpid(); | |
67 | } | |
68 | #endif | |
69 | ||
70 | #include <urcu.h> | |
71 | #include <urcu/rcurbtree.h> | |
72 | #include <urcu-defer.h> | |
73 | ||
74 | /* TODO: error handling testing for -ENOMEM */ | |
75 | struct rcu_rbtree_node *rbtree_alloc(void) | |
76 | { | |
77 | return calloc(1, sizeof(struct rcu_rbtree_node)); | |
78 | } | |
79 | ||
c479601c | 80 | void rbtree_free(struct rcu_head *head) |
dff86257 | 81 | { |
c479601c MD |
82 | struct rcu_rbtree_node *node = |
83 | caa_container_of(head, struct rcu_rbtree_node, head); | |
dff86257 MD |
84 | free(node); |
85 | } | |
86 | ||
87 | int tree_comp(void *a, void *b) | |
88 | { | |
89 | if ((unsigned long)a < (unsigned long)b) | |
90 | return -1; | |
91 | else if ((unsigned long)a > (unsigned long)b) | |
92 | return 1; | |
93 | else | |
94 | return 0; | |
95 | } | |
96 | ||
97 | static DEFINE_RCU_RBTREE(rbtree, tree_comp, rbtree_alloc, rbtree_free); | |
98 | ||
99 | static volatile int test_go, test_stop; | |
100 | ||
101 | static unsigned long wdelay; | |
102 | ||
103 | static unsigned long duration; | |
104 | ||
105 | /* read-side C.S. duration, in loops */ | |
106 | static unsigned long rduration; | |
107 | ||
108 | /* write-side C.S. duration, in loops */ | |
109 | static unsigned long wduration; | |
110 | ||
111 | static inline void loop_sleep(unsigned long l) | |
112 | { | |
113 | while(l-- != 0) | |
114 | caa_cpu_relax(); | |
115 | } | |
116 | ||
117 | static int verbose_mode; | |
118 | ||
119 | #define printf_verbose(fmt, args...) \ | |
120 | do { \ | |
121 | if (verbose_mode) \ | |
122 | printf(fmt, args); \ | |
123 | } while (0) | |
124 | ||
125 | static unsigned int cpu_affinities[NR_CPUS]; | |
126 | static unsigned int next_aff = 0; | |
127 | static int use_affinity = 0; | |
128 | ||
129 | pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER; | |
130 | ||
131 | #ifndef HAVE_CPU_SET_T | |
132 | typedef unsigned long cpu_set_t; | |
133 | # define CPU_ZERO(cpuset) do { *(cpuset) = 0; } while(0) | |
134 | # define CPU_SET(cpu, cpuset) do { *(cpuset) |= (1UL << (cpu)); } while(0) | |
135 | #endif | |
136 | ||
137 | static void set_affinity(void) | |
138 | { | |
139 | cpu_set_t mask; | |
140 | int cpu; | |
141 | int ret; | |
142 | ||
143 | if (!use_affinity) | |
144 | return; | |
145 | ||
146 | #if HAVE_SCHED_SETAFFINITY | |
147 | ret = pthread_mutex_lock(&affinity_mutex); | |
148 | if (ret) { | |
149 | perror("Error in pthread mutex lock"); | |
150 | exit(-1); | |
151 | } | |
152 | cpu = cpu_affinities[next_aff++]; | |
153 | ret = pthread_mutex_unlock(&affinity_mutex); | |
154 | if (ret) { | |
155 | perror("Error in pthread mutex unlock"); | |
156 | exit(-1); | |
157 | } | |
158 | ||
159 | CPU_ZERO(&mask); | |
160 | CPU_SET(cpu, &mask); | |
161 | #if SCHED_SETAFFINITY_ARGS == 2 | |
162 | sched_setaffinity(0, &mask); | |
163 | #else | |
164 | sched_setaffinity(0, sizeof(mask), &mask); | |
165 | #endif | |
166 | #endif /* HAVE_SCHED_SETAFFINITY */ | |
167 | } | |
168 | ||
169 | /* | |
170 | * returns 0 if test should end. | |
171 | */ | |
172 | static int test_duration_write(void) | |
173 | { | |
174 | return !test_stop; | |
175 | } | |
176 | ||
177 | static int test_duration_read(void) | |
178 | { | |
179 | return !test_stop; | |
180 | } | |
181 | ||
182 | static unsigned long long __thread nr_writes; | |
183 | static unsigned long long __thread nr_reads; | |
184 | ||
185 | static unsigned int nr_readers; | |
186 | static unsigned int nr_writers; | |
187 | ||
3f73f150 MD |
188 | static unsigned long global_items; |
189 | static void **global_key = NULL; | |
190 | ||
dff86257 MD |
191 | pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; |
192 | ||
193 | void rcu_copy_mutex_lock(void) | |
194 | { | |
195 | int ret; | |
196 | ret = pthread_mutex_lock(&rcu_copy_mutex); | |
197 | if (ret) { | |
198 | perror("Error in pthread mutex lock"); | |
199 | exit(-1); | |
200 | } | |
201 | } | |
202 | ||
203 | void rcu_copy_mutex_unlock(void) | |
204 | { | |
205 | int ret; | |
206 | ||
207 | ret = pthread_mutex_unlock(&rcu_copy_mutex); | |
208 | if (ret) { | |
209 | perror("Error in pthread mutex unlock"); | |
210 | exit(-1); | |
211 | } | |
212 | } | |
213 | ||
65715d0c | 214 | static |
f6f32757 MD |
215 | void set_lookup_index(struct rcu_rbtree_node *node, |
216 | char *lookup_hit) | |
65715d0c MD |
217 | { |
218 | int i; | |
219 | ||
220 | for (i = 0; i < global_items; i++) { | |
3366b9c0 | 221 | if (node->begin == global_key[i] |
f6f32757 MD |
222 | && !lookup_hit[i]) { |
223 | lookup_hit[i] = 1; | |
224 | break; | |
225 | } | |
65715d0c | 226 | } |
65715d0c MD |
227 | } |
228 | ||
dff86257 MD |
229 | void *thr_reader(void *_count) |
230 | { | |
231 | unsigned long long *count = _count; | |
3f73f150 | 232 | struct rcu_rbtree_node *node; |
65715d0c MD |
233 | int i, index; |
234 | char *lookup_hit; | |
dff86257 MD |
235 | |
236 | printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", | |
237 | "reader", pthread_self(), (unsigned long)gettid()); | |
238 | ||
239 | set_affinity(); | |
240 | ||
241 | rcu_register_thread(); | |
242 | ||
65715d0c MD |
243 | lookup_hit = malloc(sizeof(*lookup_hit) * global_items); |
244 | ||
dff86257 MD |
245 | while (!test_go) |
246 | { | |
247 | } | |
248 | cmm_smp_mb(); | |
249 | ||
250 | for (;;) { | |
20a104c3 | 251 | /* search bottom of range */ |
3f73f150 | 252 | for (i = 0; i < global_items; i++) { |
230dd288 MD |
253 | rcu_read_lock(); |
254 | node = rcu_rbtree_search(&rbtree, | |
255 | rcu_dereference(rbtree.root), | |
3f73f150 | 256 | global_key[i]); |
8ded5fe9 | 257 | assert(!rcu_rbtree_is_nil(&rbtree, node)); |
230dd288 | 258 | rcu_read_unlock(); |
3f73f150 | 259 | } |
1c16a0d6 | 260 | |
20a104c3 MD |
261 | /* search end of range */ |
262 | for (i = 0; i < global_items; i++) { | |
263 | rcu_read_lock(); | |
264 | node = rcu_rbtree_search(&rbtree, | |
265 | rcu_dereference(rbtree.root), | |
7aa852c8 | 266 | (void*) ((unsigned long) global_key[i] + 2)); |
20a104c3 MD |
267 | assert(!rcu_rbtree_is_nil(&rbtree, node)); |
268 | rcu_read_unlock(); | |
269 | } | |
270 | ||
271 | /* search range (middle) */ | |
00539351 MD |
272 | for (i = 0; i < global_items; i++) { |
273 | rcu_read_lock(); | |
a84e8c8e | 274 | node = rcu_rbtree_search_range(&rbtree, |
00539351 | 275 | rcu_dereference(rbtree.root), |
20a104c3 MD |
276 | (void*) ((unsigned long) global_key[i] + 1), |
277 | (void*) ((unsigned long) global_key[i] + 2)); | |
8ded5fe9 | 278 | assert(!rcu_rbtree_is_nil(&rbtree, node)); |
00539351 MD |
279 | rcu_read_unlock(); |
280 | } | |
1c16a0d6 MD |
281 | |
282 | /* search begin key */ | |
283 | for (i = 0; i < global_items; i++) { | |
284 | rcu_read_lock(); | |
285 | node = rcu_rbtree_search_begin_key(&rbtree, | |
286 | rcu_dereference(rbtree.root), | |
287 | global_key[i]); | |
288 | assert(!rcu_rbtree_is_nil(&rbtree, node)); | |
289 | rcu_read_unlock(); | |
290 | } | |
291 | ||
65715d0c MD |
292 | /* min + next */ |
293 | memset(lookup_hit, 0, sizeof(*lookup_hit) * global_items); | |
294 | ||
295 | rcu_read_lock(); | |
296 | node = rcu_rbtree_min(&rbtree, | |
297 | rcu_dereference(rbtree.root)); | |
8ded5fe9 | 298 | while (!rcu_rbtree_is_nil(&rbtree, node)) { |
f6f32757 | 299 | set_lookup_index(node, lookup_hit); |
65715d0c MD |
300 | node = rcu_rbtree_next(&rbtree, node); |
301 | } | |
302 | rcu_read_unlock(); | |
303 | ||
304 | for (i = 0; i < global_items; i++) | |
305 | assert(lookup_hit[i]); | |
306 | ||
307 | /* max + prev */ | |
308 | memset(lookup_hit, 0, sizeof(*lookup_hit) * global_items); | |
309 | ||
310 | rcu_read_lock(); | |
311 | node = rcu_rbtree_max(&rbtree, | |
312 | rcu_dereference(rbtree.root)); | |
8ded5fe9 | 313 | while (!rcu_rbtree_is_nil(&rbtree, node)) { |
f6f32757 | 314 | set_lookup_index(node, lookup_hit); |
65715d0c MD |
315 | node = rcu_rbtree_prev(&rbtree, node); |
316 | } | |
317 | rcu_read_unlock(); | |
318 | ||
319 | for (i = 0; i < global_items; i++) | |
320 | assert(lookup_hit[i]); | |
321 | ||
dff86257 MD |
322 | debug_yield_read(); |
323 | if (unlikely(rduration)) | |
324 | loop_sleep(rduration); | |
dff86257 MD |
325 | nr_reads++; |
326 | if (unlikely(!test_duration_read())) | |
327 | break; | |
328 | } | |
329 | ||
330 | rcu_unregister_thread(); | |
331 | ||
332 | /* test extra thread registration */ | |
333 | rcu_register_thread(); | |
334 | rcu_unregister_thread(); | |
335 | ||
65715d0c MD |
336 | free(lookup_hit); |
337 | ||
dff86257 MD |
338 | *count = nr_reads; |
339 | printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", | |
340 | "reader", pthread_self(), (unsigned long)gettid()); | |
341 | return ((void*)1); | |
342 | ||
343 | } | |
344 | ||
345 | void *thr_writer(void *_count) | |
346 | { | |
347 | unsigned long long *count = _count; | |
348 | struct rcu_rbtree_node *node; | |
349 | void *key[NR_RAND]; | |
350 | int i; | |
351 | ||
352 | printf_verbose("thread_begin %s, thread id : %lx, tid %lu\n", | |
353 | "writer", pthread_self(), (unsigned long)gettid()); | |
354 | ||
355 | set_affinity(); | |
356 | ||
a84e8c8e MD |
357 | //disable_debug = 1; |
358 | ||
c479601c | 359 | rcu_register_thread(); |
dff86257 MD |
360 | |
361 | while (!test_go) | |
362 | { | |
363 | } | |
364 | cmm_smp_mb(); | |
365 | ||
366 | for (;;) { | |
367 | rcu_copy_mutex_lock(); | |
368 | ||
369 | for (i = 0; i < NR_RAND; i++) { | |
370 | node = rbtree_alloc(); | |
20a104c3 MD |
371 | //key[i] = (void *)(unsigned long)(rand() % 2048); |
372 | key[i] = (void *)(unsigned long)((rand() * 4) % 2048); | |
4310d6da MD |
373 | //For more collisions |
374 | //key[i] = (void *)(unsigned long)(rand() % 6); | |
3366b9c0 | 375 | node->begin = key[i]; |
20a104c3 MD |
376 | //node->end = (void *)((unsigned long) key[i] + 4); |
377 | node->end = (void *)((unsigned long) key[i] + 4); | |
230dd288 | 378 | rcu_read_lock(); |
dff86257 | 379 | rcu_rbtree_insert(&rbtree, node); |
230dd288 | 380 | rcu_read_unlock(); |
dff86257 | 381 | } |
230dd288 | 382 | rcu_copy_mutex_unlock(); |
dff86257 MD |
383 | |
384 | if (unlikely(wduration)) | |
385 | loop_sleep(wduration); | |
386 | ||
230dd288 | 387 | rcu_copy_mutex_lock(); |
dff86257 MD |
388 | for (i = 0; i < NR_RAND; i++) { |
389 | #if 0 | |
390 | node = rcu_rbtree_min(rbtree, rbtree->root); | |
8ded5fe9 | 391 | while (!rcu_rbtree_is_nil(&rbtree, node)) { |
dff86257 MD |
392 | printf("{ 0x%lX p:%lX r:%lX l:%lX %s %s %s} ", |
393 | (unsigned long)node->key, | |
394 | node->p->key, | |
395 | node->right->key, | |
396 | node->left->key, | |
397 | node->color ? "red" : "black", | |
398 | node->pos ? "right" : "left", | |
399 | node->nil ? "nil" : ""); | |
400 | node = rcu_rbtree_next(rbtree, node); | |
401 | } | |
402 | printf("\n"); | |
403 | #endif | |
230dd288 | 404 | rcu_read_lock(); |
dff86257 | 405 | node = rcu_rbtree_search(&rbtree, rbtree.root, key[i]); |
8ded5fe9 | 406 | assert(!rcu_rbtree_is_nil(&rbtree, node)); |
dff86257 | 407 | rcu_rbtree_remove(&rbtree, node); |
230dd288 | 408 | rcu_read_unlock(); |
c479601c | 409 | call_rcu(&node->head, rbtree_free); |
dff86257 MD |
410 | } |
411 | ||
412 | rcu_copy_mutex_unlock(); | |
413 | nr_writes++; | |
414 | if (unlikely(!test_duration_write())) | |
415 | break; | |
416 | if (unlikely(wdelay)) | |
417 | loop_sleep(wdelay); | |
418 | } | |
419 | ||
c479601c | 420 | rcu_unregister_thread(); |
dff86257 MD |
421 | |
422 | printf_verbose("thread_end %s, thread id : %lx, tid %lu\n", | |
423 | "writer", pthread_self(), (unsigned long)gettid()); | |
424 | *count = nr_writes; | |
425 | return ((void*)2); | |
426 | } | |
427 | ||
428 | void show_usage(int argc, char **argv) | |
429 | { | |
430 | printf("Usage : %s nr_readers nr_writers duration (s)", argv[0]); | |
431 | #ifdef DEBUG_YIELD | |
432 | printf(" [-r] [-w] (yield reader and/or writer)"); | |
433 | #endif | |
434 | printf(" [-d delay] (writer period (us))"); | |
435 | printf(" [-c duration] (reader C.S. duration (in loops))"); | |
436 | printf(" [-e duration] (writer C.S. duration (in loops))"); | |
437 | printf(" [-v] (verbose output)"); | |
438 | printf(" [-a cpu#] [-a cpu#]... (affinity)"); | |
439 | printf("\n"); | |
440 | } | |
441 | ||
442 | int main(int argc, char **argv) | |
443 | { | |
444 | int err; | |
445 | pthread_t *tid_reader, *tid_writer; | |
446 | void *tret; | |
447 | unsigned long long *count_reader, *count_writer; | |
448 | unsigned long long tot_reads = 0, tot_writes = 0; | |
449 | int i, a; | |
3f73f150 | 450 | struct rcu_rbtree_node *node; |
dff86257 MD |
451 | |
452 | if (argc < 4) { | |
453 | show_usage(argc, argv); | |
454 | return -1; | |
455 | } | |
456 | ||
457 | err = sscanf(argv[1], "%u", &nr_readers); | |
458 | if (err != 1) { | |
459 | show_usage(argc, argv); | |
460 | return -1; | |
461 | } | |
462 | ||
463 | err = sscanf(argv[2], "%u", &nr_writers); | |
464 | if (err != 1) { | |
465 | show_usage(argc, argv); | |
466 | return -1; | |
467 | } | |
468 | ||
469 | err = sscanf(argv[3], "%lu", &duration); | |
470 | if (err != 1) { | |
471 | show_usage(argc, argv); | |
472 | return -1; | |
473 | } | |
474 | ||
475 | for (i = 4; i < argc; i++) { | |
476 | if (argv[i][0] != '-') | |
477 | continue; | |
478 | switch (argv[i][1]) { | |
479 | #ifdef DEBUG_YIELD | |
480 | case 'r': | |
481 | yield_active |= YIELD_READ; | |
482 | break; | |
483 | case 'w': | |
484 | yield_active |= YIELD_WRITE; | |
485 | break; | |
486 | #endif | |
487 | case 'a': | |
488 | if (argc < i + 2) { | |
489 | show_usage(argc, argv); | |
490 | return -1; | |
491 | } | |
492 | a = atoi(argv[++i]); | |
493 | cpu_affinities[next_aff++] = a; | |
494 | use_affinity = 1; | |
495 | printf_verbose("Adding CPU %d affinity\n", a); | |
496 | break; | |
497 | case 'c': | |
498 | if (argc < i + 2) { | |
499 | show_usage(argc, argv); | |
500 | return -1; | |
501 | } | |
502 | rduration = atol(argv[++i]); | |
503 | break; | |
504 | case 'd': | |
505 | if (argc < i + 2) { | |
506 | show_usage(argc, argv); | |
507 | return -1; | |
508 | } | |
509 | wdelay = atol(argv[++i]); | |
510 | break; | |
511 | case 'e': | |
512 | if (argc < i + 2) { | |
513 | show_usage(argc, argv); | |
514 | return -1; | |
515 | } | |
516 | wduration = atol(argv[++i]); | |
517 | break; | |
518 | case 'v': | |
519 | verbose_mode = 1; | |
520 | break; | |
3f73f150 MD |
521 | case 'g': |
522 | if (argc < i + 2) { | |
523 | show_usage(argc, argv); | |
524 | return -1; | |
525 | } | |
526 | global_items = atol(argv[++i]); | |
527 | break; | |
dff86257 MD |
528 | } |
529 | } | |
530 | ||
531 | printf_verbose("running test for %lu seconds, %u readers, %u writers.\n", | |
532 | duration, nr_readers, nr_writers); | |
533 | printf_verbose("Writer delay : %lu loops.\n", wdelay); | |
534 | printf_verbose("Reader duration : %lu loops.\n", rduration); | |
535 | printf_verbose("thread %-6s, thread id : %lx, tid %lu\n", | |
536 | "main", pthread_self(), (unsigned long)gettid()); | |
537 | ||
538 | tid_reader = malloc(sizeof(*tid_reader) * nr_readers); | |
539 | tid_writer = malloc(sizeof(*tid_writer) * nr_writers); | |
540 | count_reader = malloc(sizeof(*count_reader) * nr_readers); | |
541 | count_writer = malloc(sizeof(*count_writer) * nr_writers); | |
3f73f150 | 542 | global_key = malloc(sizeof(*global_key) * global_items); |
dff86257 MD |
543 | |
544 | srand(time(NULL)); | |
545 | ||
546 | next_aff = 0; | |
547 | ||
548 | for (i = 0; i < nr_readers; i++) { | |
549 | err = pthread_create(&tid_reader[i], NULL, thr_reader, | |
550 | &count_reader[i]); | |
551 | if (err != 0) | |
552 | exit(1); | |
553 | } | |
554 | for (i = 0; i < nr_writers; i++) { | |
555 | err = pthread_create(&tid_writer[i], NULL, thr_writer, | |
556 | &count_writer[i]); | |
557 | if (err != 0) | |
558 | exit(1); | |
559 | } | |
560 | ||
806967f3 MD |
561 | rcu_register_thread(); |
562 | rcu_read_lock(); | |
3f73f150 MD |
563 | /* Insert items looked up by readers */ |
564 | for (i = 0; i < global_items; i++) { | |
565 | node = rbtree_alloc(); | |
20a104c3 MD |
566 | global_key[i] = (void *)(unsigned long)((rand() * 4) % 2048); |
567 | //global_key[i] = (void *)(unsigned long)(rand() % 2048); | |
4310d6da | 568 | //For more collisions |
a84e8c8e | 569 | global_key[i] = (void *)(unsigned long)(rand() % 6); |
3366b9c0 | 570 | node->begin = global_key[i]; |
20a104c3 MD |
571 | //node->end = (void *)((unsigned long) global_key[i] + 1); |
572 | node->end = (void *)((unsigned long) global_key[i] + 4); | |
3f73f150 MD |
573 | rcu_rbtree_insert(&rbtree, node); |
574 | } | |
806967f3 | 575 | rcu_read_unlock(); |
3f73f150 | 576 | |
dff86257 MD |
577 | cmm_smp_mb(); |
578 | ||
579 | test_go = 1; | |
580 | ||
581 | sleep(duration); | |
582 | ||
583 | test_stop = 1; | |
584 | ||
585 | for (i = 0; i < nr_readers; i++) { | |
586 | err = pthread_join(tid_reader[i], &tret); | |
587 | if (err != 0) | |
588 | exit(1); | |
589 | tot_reads += count_reader[i]; | |
590 | } | |
591 | for (i = 0; i < nr_writers; i++) { | |
592 | err = pthread_join(tid_writer[i], &tret); | |
593 | if (err != 0) | |
594 | exit(1); | |
595 | tot_writes += count_writer[i]; | |
596 | } | |
597 | ||
806967f3 | 598 | rcu_read_lock(); |
3f73f150 MD |
599 | for (i = 0; i < global_items; i++) { |
600 | node = rcu_rbtree_search(&rbtree, rbtree.root, global_key[i]); | |
8ded5fe9 | 601 | assert(!rcu_rbtree_is_nil(&rbtree, node)); |
3f73f150 MD |
602 | rcu_rbtree_remove(&rbtree, node); |
603 | call_rcu(&node->head, rbtree_free); | |
604 | } | |
806967f3 MD |
605 | rcu_read_unlock(); |
606 | rcu_unregister_thread(); | |
3f73f150 | 607 | |
dff86257 MD |
608 | printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads, |
609 | tot_writes); | |
610 | printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu " | |
611 | "nr_writers %3u " | |
3f73f150 MD |
612 | "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu " |
613 | "global_items %6lu\n", | |
dff86257 MD |
614 | argv[0], duration, nr_readers, rduration, wduration, |
615 | nr_writers, wdelay, tot_reads, tot_writes, | |
3f73f150 | 616 | tot_reads + tot_writes, global_items); |
dff86257 MD |
617 | free(tid_reader); |
618 | free(tid_writer); | |
619 | free(count_reader); | |
620 | free(count_writer); | |
3f73f150 | 621 | free(global_key); |
dff86257 MD |
622 | return 0; |
623 | } |