tests: Use uatomic for accessing global states
[urcu.git] / tests / benchmark / test_urcu_hash.c
CommitLineData
ce29b371
MJ
1// SPDX-FileCopyrightText: 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2//
3// SPDX-License-Identifier: GPL-2.0-or-later
4
ab7d5fc6 5/*
ab7d5fc6 6 * Userspace RCU library - test program
ab7d5fc6
MD
7 */
8
18ca7a5b 9#include "test_urcu_hash.h"
ab7d5fc6 10
f52c1ef7
MD
11enum test_hash {
12 TEST_HASH_RW,
20adf780 13 TEST_HASH_UNIQUE,
f52c1ef7
MD
14};
15
16struct test_hash_cb {
17 void (*sigusr1)(int signo);
18 void (*sigusr2)(int signo);
19 void *(*thr_reader)(void *_count);
20 void *(*thr_writer)(void *_count);
21 int (*populate_hash)(void);
22};
23
24static
25struct test_hash_cb test_hash_cb[] = {
26 [TEST_HASH_RW] = {
27 test_hash_rw_sigusr1_handler,
28 test_hash_rw_sigusr2_handler,
29 test_hash_rw_thr_reader,
30 test_hash_rw_thr_writer,
31 test_hash_rw_populate_hash,
32 },
20adf780
MD
33 [TEST_HASH_UNIQUE] = {
34 test_hash_unique_sigusr1_handler,
35 test_hash_unique_sigusr2_handler,
36 test_hash_unique_thr_reader,
37 test_hash_unique_thr_writer,
38 test_hash_unique_populate_hash,
39 },
40
f52c1ef7
MD
41};
42
43static enum test_hash test_choice = TEST_HASH_RW;
44
61c3fb60 45static
f52c1ef7
MD
46void (*get_sigusr1_cb(void))(int)
47{
48 return test_hash_cb[test_choice].sigusr1;
49}
50
61c3fb60 51static
f52c1ef7
MD
52void (*get_sigusr2_cb(void))(int)
53{
54 return test_hash_cb[test_choice].sigusr2;
55}
56
61c3fb60 57static
f52c1ef7
MD
58void *(*get_thr_reader_cb(void))(void *)
59{
60 return test_hash_cb[test_choice].thr_reader;
61}
62
61c3fb60 63static
f52c1ef7
MD
64void *(*get_thr_writer_cb(void))(void *)
65{
66 return test_hash_cb[test_choice].thr_writer;
67}
68
61c3fb60 69static
f52c1ef7
MD
70int (*get_populate_hash_cb(void))(void)
71{
72 return test_hash_cb[test_choice].populate_hash;
73}
74
bd252a04
MD
75DEFINE_URCU_TLS(unsigned int, rand_lookup);
76DEFINE_URCU_TLS(unsigned long, nr_add);
77DEFINE_URCU_TLS(unsigned long, nr_addexist);
78DEFINE_URCU_TLS(unsigned long, nr_del);
79DEFINE_URCU_TLS(unsigned long, nr_delnoent);
80DEFINE_URCU_TLS(unsigned long, lookup_fail);
81DEFINE_URCU_TLS(unsigned long, lookup_ok);
b8e1907c 82
18ca7a5b 83struct cds_lfht *test_ht;
5e28c532 84
18ca7a5b 85volatile int test_go, test_stop;
ab7d5fc6 86
18ca7a5b 87unsigned long wdelay;
ab7d5fc6 88
18ca7a5b 89unsigned long duration;
ab7d5fc6
MD
90
91/* read-side C.S. duration, in loops */
18ca7a5b
MD
92unsigned long rduration;
93
94unsigned long init_hash_size = DEFAULT_HASH_SIZE;
95unsigned long min_hash_alloc_size = DEFAULT_MIN_ALLOC_SIZE;
96unsigned long max_hash_buckets_size = (1UL << 20);
97unsigned long init_populate;
98int opt_auto_resize;
99int add_only, add_unique, add_replace;
100const struct cds_lfht_mm_type *memory_backend;
101
102unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
103unsigned long init_pool_size = DEFAULT_RAND_POOL,
d837911d
MD
104 lookup_pool_size = DEFAULT_RAND_POOL,
105 write_pool_size = DEFAULT_RAND_POOL;
18ca7a5b 106int validate_lookup;
495913bf 107unsigned long nr_hash_chains; /* 0: normal table, other: number of hash chains */
8008a032 108
18ca7a5b 109int count_pipe[2];
7ed7682f 110
18ca7a5b 111int verbose_mode;
ab7d5fc6 112
18ca7a5b
MD
113unsigned int cpu_affinities[NR_CPUS];
114unsigned int next_aff = 0;
115int use_affinity = 0;
ab7d5fc6 116
18ca7a5b 117pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
ab7d5fc6 118
bd252a04
MD
119DEFINE_URCU_TLS(unsigned long long, nr_writes);
120DEFINE_URCU_TLS(unsigned long long, nr_reads);
ab7d5fc6 121
18ca7a5b
MD
122unsigned int nr_readers;
123unsigned int nr_writers;
ab7d5fc6 124
18ca7a5b 125static pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
fb6d173d 126
18ca7a5b 127void set_affinity(void)
ab7d5fc6 128{
2388c075 129#ifdef HAVE_SCHED_SETAFFINITY
ab7d5fc6 130 cpu_set_t mask;
95bc7fb9
MD
131 int cpu, ret;
132#endif /* HAVE_SCHED_SETAFFINITY */
ab7d5fc6
MD
133
134 if (!use_affinity)
135 return;
136
2388c075 137#ifdef HAVE_SCHED_SETAFFINITY
ab7d5fc6
MD
138 ret = pthread_mutex_lock(&affinity_mutex);
139 if (ret) {
140 perror("Error in pthread mutex lock");
141 exit(-1);
142 }
143 cpu = cpu_affinities[next_aff++];
144 ret = pthread_mutex_unlock(&affinity_mutex);
145 if (ret) {
146 perror("Error in pthread mutex unlock");
147 exit(-1);
148 }
149 CPU_ZERO(&mask);
150 CPU_SET(cpu, &mask);
e7e6ff7f 151 sched_setaffinity(0, sizeof(mask), &mask);
fb6d173d 152#endif /* HAVE_SCHED_SETAFFINITY */
ab7d5fc6
MD
153}
154
ab7d5fc6
MD
155void rcu_copy_mutex_lock(void)
156{
157 int ret;
158 ret = pthread_mutex_lock(&rcu_copy_mutex);
159 if (ret) {
160 perror("Error in pthread mutex lock");
161 exit(-1);
162 }
163}
164
165void rcu_copy_mutex_unlock(void)
166{
167 int ret;
168
169 ret = pthread_mutex_unlock(&rcu_copy_mutex);
170 if (ret) {
171 perror("Error in pthread mutex unlock");
172 exit(-1);
173 }
174}
175
996ff57c 176unsigned long test_compare(const void *key1, size_t key1_len,
e7e6ff7f 177 const void *key2, size_t key2_len)
732ad076 178{
8ed51e04 179 if (caa_unlikely(key1_len != key2_len))
732ad076 180 return -1;
01477510 181 urcu_posix_assert(key1_len == sizeof(unsigned long));
732ad076
MD
182 if (key1 == key2)
183 return 0;
184 else
185 return 1;
abc490a1 186}
ab7d5fc6 187
61c3fb60 188static
70469b43 189void *thr_count(void *arg __attribute__((unused)))
7ed7682f 190{
94df6318
MD
191 printf_verbose("thread_begin %s, tid %lu\n",
192 "counter", urcu_get_thread_id());
7ed7682f
MD
193
194 rcu_register_thread();
195
196 for (;;) {
caf3653d 197 unsigned long count;
d933dd0e 198 long approx_before, approx_after;
7ed7682f
MD
199 ssize_t len;
200 char buf[1];
201
202 rcu_thread_offline();
203 len = read(count_pipe[0], buf, 1);
204 rcu_thread_online();
8ed51e04 205 if (caa_unlikely(!test_duration_read()))
7ed7682f
MD
206 break;
207 if (len != 1)
208 continue;
209 /* Accounting */
210 printf("Counting nodes... ");
211 fflush(stdout);
212 rcu_read_lock();
caf3653d 213 cds_lfht_count_nodes(test_ht, &approx_before, &count,
7ed7682f
MD
214 &approx_after);
215 rcu_read_unlock();
216 printf("done.\n");
d933dd0e 217 printf("Approximation before node accounting: %ld nodes.\n",
7ed7682f
MD
218 approx_before);
219 printf("Accounting of nodes in the hash table: "
caf3653d
MD
220 "%lu nodes.\n",
221 count);
d933dd0e 222 printf("Approximation after node accounting: %ld nodes.\n",
7ed7682f
MD
223 approx_after);
224 }
225 rcu_unregister_thread();
226 return NULL;
227}
228
abc490a1
MD
229void free_node_cb(struct rcu_head *head)
230{
3c692076 231 struct lfht_test_node *node =
81d91005 232 caa_container_of(head, struct lfht_test_node, head);
abc490a1
MD
233 free(node);
234}
235
175ec0eb
MD
236static
237void test_delete_all_nodes(struct cds_lfht *ht)
238{
239 struct cds_lfht_iter iter;
3c692076 240 struct lfht_test_node *node;
175ec0eb
MD
241 unsigned long count = 0;
242
6d320126 243 cds_lfht_for_each_entry(ht, &iter, node, node) {
175ec0eb
MD
244 int ret;
245
bc8c3c74 246 ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
01477510 247 urcu_posix_assert(!ret);
81d91005 248 call_rcu(&node->head, free_node_cb);
175ec0eb
MD
249 count++;
250 }
251 printf("deleted %lu nodes.\n", count);
252}
253
61c3fb60 254static
70469b43 255void show_usage(char **argv)
ab7d5fc6 256{
06637138
MD
257 printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
258 argv[0]);
259 printf("OPTIONS:\n");
48ed1c18 260 printf(" [-r] [-w] (yield reader and/or writer)\n");
48ed1c18
MD
261 printf(" [-d delay] (writer period (us))\n");
262 printf(" [-c duration] (reader C.S. duration (in loops))\n");
263 printf(" [-v] (verbose output)\n");
264 printf(" [-a cpu#] [-a cpu#]... (affinity)\n");
b99436d7
LJ
265 printf(" [-h size] (initial number of buckets)\n");
266 printf(" [-m size] (minimum number of allocated buckets)\n");
267 printf(" [-n size] (maximum number of buckets)\n");
18ca7a5b 268printf(" [not -u nor -s] Add entries (supports redundant keys).\n");
48ed1c18
MD
269 printf(" [-u] Uniquify add (no redundant keys).\n");
270 printf(" [-s] Replace (swap) entries.\n");
271 printf(" [-i] Add only (no removal).\n");
272 printf(" [-k nr_nodes] Number of nodes to insert initially.\n");
273 printf(" [-A] Automatically resize hash table.\n");
c0b8a865 274 printf(" [-B order|chunk|mmap] Specify the memory backend.\n");
48ed1c18
MD
275 printf(" [-R offset] Lookup pool offset.\n");
276 printf(" [-S offset] Write pool offset.\n");
277 printf(" [-T offset] Init pool offset.\n");
278 printf(" [-M size] Lookup pool size.\n");
279 printf(" [-N size] Write pool size.\n");
280 printf(" [-O size] Init pool size.\n");
06637138
MD
281 printf(" [-V] Validate lookups of init values.\n");
282 printf(" (use with filled init pool, same lookup range,\n");
283 printf(" with different write range)\n");
20adf780 284 printf(" [-U] Uniqueness test.\n");
495913bf 285 printf(" [-C] Number of hash chains.\n");
06637138 286 printf("\n");
ab7d5fc6
MD
287}
288
289int main(int argc, char **argv)
290{
ab7d5fc6 291 pthread_t *tid_reader, *tid_writer;
7ed7682f 292 pthread_t tid_count;
ab7d5fc6 293 void *tret;
b8e1907c
MD
294 unsigned long long *count_reader;
295 struct wr_count *count_writer;
296 unsigned long long tot_reads = 0, tot_writes = 0,
3c16bf4b 297 tot_add = 0, tot_add_exist = 0, tot_remove = 0;
caf3653d 298 unsigned long count;
d933dd0e 299 long approx_before, approx_after;
e7e6ff7f 300 int i, a, ret, err, mainret = 0;
83e334d0 301 unsigned int i_thr;
3967a8a8
MD
302 struct sigaction act;
303 unsigned int remain;
e7e6ff7f
MD
304 unsigned int nr_readers_created = 0, nr_writers_created = 0;
305 long long nr_leaked;
ab7d5fc6
MD
306
307 if (argc < 4) {
70469b43 308 show_usage(argv);
e7e6ff7f
MD
309 mainret = 1;
310 goto end;
ab7d5fc6
MD
311 }
312
313 err = sscanf(argv[1], "%u", &nr_readers);
314 if (err != 1) {
70469b43 315 show_usage(argv);
e7e6ff7f
MD
316 mainret = 1;
317 goto end;
ab7d5fc6
MD
318 }
319
320 err = sscanf(argv[2], "%u", &nr_writers);
321 if (err != 1) {
70469b43 322 show_usage(argv);
e7e6ff7f
MD
323 mainret = 1;
324 goto end;
ab7d5fc6 325 }
83e334d0 326
ab7d5fc6
MD
327 err = sscanf(argv[3], "%lu", &duration);
328 if (err != 1) {
70469b43 329 show_usage(argv);
e7e6ff7f
MD
330 mainret = 1;
331 goto end;
ab7d5fc6
MD
332 }
333
334 for (i = 4; i < argc; i++) {
335 if (argv[i][0] != '-')
336 continue;
337 switch (argv[i][1]) {
ab7d5fc6 338 case 'r':
2650042a 339 rcu_debug_yield_enable(RCU_YIELD_READ);
ab7d5fc6
MD
340 break;
341 case 'w':
2650042a 342 rcu_debug_yield_enable(RCU_YIELD_WRITE);
ab7d5fc6 343 break;
ab7d5fc6
MD
344 case 'a':
345 if (argc < i + 2) {
70469b43 346 show_usage(argv);
e7e6ff7f
MD
347 mainret = 1;
348 goto end;
ab7d5fc6
MD
349 }
350 a = atoi(argv[++i]);
351 cpu_affinities[next_aff++] = a;
352 use_affinity = 1;
353 printf_verbose("Adding CPU %d affinity\n", a);
354 break;
355 case 'c':
356 if (argc < i + 2) {
70469b43 357 show_usage(argv);
e7e6ff7f
MD
358 mainret = 1;
359 goto end;
ab7d5fc6
MD
360 }
361 rduration = atol(argv[++i]);
362 break;
363 case 'd':
364 if (argc < i + 2) {
70469b43 365 show_usage(argv);
e7e6ff7f
MD
366 mainret = 1;
367 goto end;
ab7d5fc6
MD
368 }
369 wdelay = atol(argv[++i]);
370 break;
371 case 'v':
372 verbose_mode = 1;
373 break;
6d5c0ca9
MD
374 case 'h':
375 if (argc < i + 2) {
70469b43 376 show_usage(argv);
e7e6ff7f
MD
377 mainret = 1;
378 goto end;
6d5c0ca9
MD
379 }
380 init_hash_size = atol(argv[++i]);
381 break;
32becef6
LJ
382 case 'm':
383 if (argc < i + 2) {
70469b43 384 show_usage(argv);
e7e6ff7f
MD
385 mainret = 1;
386 goto end;
32becef6
LJ
387 }
388 min_hash_alloc_size = atol(argv[++i]);
389 break;
b99436d7
LJ
390 case 'n':
391 if (argc < i + 2) {
70469b43 392 show_usage(argv);
e7e6ff7f
MD
393 mainret = 1;
394 goto end;
b99436d7
LJ
395 }
396 max_hash_buckets_size = atol(argv[++i]);
397 break;
6d5c0ca9 398 case 'u':
48ed1c18
MD
399 if (add_replace) {
400 printf("Please specify at most one of -s or -u.\n");
401 exit(-1);
402 }
6d5c0ca9
MD
403 add_unique = 1;
404 break;
48ed1c18
MD
405 case 's':
406 if (add_unique) {
407 printf("Please specify at most one of -s or -u.\n");
408 exit(-1);
409 }
410 add_replace = 1;
411 break;
6d5c0ca9
MD
412 case 'i':
413 add_only = 1;
414 break;
cd1ae16a
MD
415 case 'k':
416 init_populate = atol(argv[++i]);
417 break;
151e7a93
MD
418 case 'A':
419 opt_auto_resize = 1;
420 break;
c0b8a865
LJ
421 case 'B':
422 if (argc < i + 2) {
70469b43 423 show_usage(argv);
e7e6ff7f
MD
424 mainret = 1;
425 goto end;
c0b8a865
LJ
426 }
427 i++;
428 if (!strcmp("order", argv[i]))
429 memory_backend = &cds_lfht_mm_order;
430 else if (!strcmp("chunk", argv[i]))
431 memory_backend = &cds_lfht_mm_chunk;
432 else if (!strcmp("mmap", argv[i]))
433 memory_backend = &cds_lfht_mm_mmap;
e7e6ff7f 434 else {
c0b8a865 435 printf("Please specify memory backend with order|chunk|mmap.\n");
e7e6ff7f
MD
436 mainret = 1;
437 goto end;
c0b8a865
LJ
438 }
439 break;
8008a032
MD
440 case 'R':
441 lookup_pool_offset = atol(argv[++i]);
442 break;
443 case 'S':
444 write_pool_offset = atol(argv[++i]);
445 break;
446 case 'T':
447 init_pool_offset = atol(argv[++i]);
448 break;
d837911d
MD
449 case 'M':
450 lookup_pool_size = atol(argv[++i]);
451 break;
452 case 'N':
453 write_pool_size = atol(argv[++i]);
454 break;
455 case 'O':
456 init_pool_size = atol(argv[++i]);
457 break;
59b10634
MD
458 case 'V':
459 validate_lookup = 1;
460 break;
20adf780
MD
461 case 'U':
462 test_choice = TEST_HASH_UNIQUE;
463 break;
495913bf
MD
464 case 'C':
465 nr_hash_chains = atol(argv[++i]);
466 break;
ab7d5fc6
MD
467 }
468 }
469
6d5c0ca9
MD
470 /* Check if hash size is power of 2 */
471 if (init_hash_size && init_hash_size & (init_hash_size - 1)) {
b99436d7 472 printf("Error: Initial number of buckets (%lu) is not a power of 2.\n",
6d5c0ca9 473 init_hash_size);
e7e6ff7f
MD
474 mainret = 1;
475 goto end;
6d5c0ca9
MD
476 }
477
d0d8f9aa 478 if (min_hash_alloc_size && min_hash_alloc_size & (min_hash_alloc_size - 1)) {
b99436d7 479 printf("Error: Minimum number of allocated buckets (%lu) is not a power of 2.\n",
32becef6 480 min_hash_alloc_size);
e7e6ff7f
MD
481 mainret = 1;
482 goto end;
32becef6
LJ
483 }
484
b99436d7
LJ
485 if (max_hash_buckets_size && max_hash_buckets_size & (max_hash_buckets_size - 1)) {
486 printf("Error: Maximum number of buckets (%lu) is not a power of 2.\n",
487 max_hash_buckets_size);
e7e6ff7f
MD
488 mainret = 1;
489 goto end;
b99436d7
LJ
490 }
491
3967a8a8
MD
492 memset(&act, 0, sizeof(act));
493 ret = sigemptyset(&act.sa_mask);
494 if (ret == -1) {
495 perror("sigemptyset");
e7e6ff7f
MD
496 mainret = 1;
497 goto end;
3967a8a8 498 }
f52c1ef7 499 act.sa_handler = get_sigusr1_cb();
3967a8a8
MD
500 act.sa_flags = SA_RESTART;
501 ret = sigaction(SIGUSR1, &act, NULL);
502 if (ret == -1) {
503 perror("sigaction");
e7e6ff7f
MD
504 mainret = 1;
505 goto end;
7ed7682f
MD
506 }
507
f52c1ef7 508 act.sa_handler = get_sigusr2_cb();
973e5e1b
MD
509 act.sa_flags = SA_RESTART;
510 ret = sigaction(SIGUSR2, &act, NULL);
511 if (ret == -1) {
512 perror("sigaction");
e7e6ff7f
MD
513 mainret = 1;
514 goto end;
973e5e1b 515 }
3967a8a8 516
ab7d5fc6
MD
517 printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
518 duration, nr_readers, nr_writers);
519 printf_verbose("Writer delay : %lu loops.\n", wdelay);
520 printf_verbose("Reader duration : %lu loops.\n", rduration);
6d5c0ca9
MD
521 printf_verbose("Mode:%s%s.\n",
522 add_only ? " add only" : " add/remove",
48ed1c18 523 add_unique ? " uniquify" : ( add_replace ? " replace" : " insert"));
b99436d7
LJ
524 printf_verbose("Initial number of buckets: %lu buckets.\n", init_hash_size);
525 printf_verbose("Minimum number of allocated buckets: %lu buckets.\n", min_hash_alloc_size);
526 printf_verbose("Maximum number of buckets: %lu buckets.\n", max_hash_buckets_size);
5dc00396
MD
527 printf_verbose("Init pool size offset %lu size %lu.\n",
528 init_pool_offset, init_pool_size);
529 printf_verbose("Lookup pool size offset %lu size %lu.\n",
530 lookup_pool_offset, lookup_pool_size);
531 printf_verbose("Update pool size offset %lu size %lu.\n",
532 write_pool_offset, write_pool_size);
495913bf
MD
533 printf_verbose("Number of hash chains: %lu.\n",
534 nr_hash_chains);
94df6318
MD
535 printf_verbose("thread %-6s, tid %lu\n",
536 "main", urcu_get_thread_id());
ab7d5fc6 537
9aa14175 538 tid_reader = calloc(nr_readers, sizeof(*tid_reader));
e7e6ff7f
MD
539 if (!tid_reader) {
540 mainret = 1;
541 goto end;
542 }
9aa14175 543 tid_writer = calloc(nr_writers, sizeof(*tid_writer));
e7e6ff7f
MD
544 if (!tid_writer) {
545 mainret = 1;
546 goto end_free_tid_reader;
547 }
9aa14175 548 count_reader = calloc(nr_readers, sizeof(*count_reader));
e7e6ff7f
MD
549 if (!count_reader) {
550 mainret = 1;
551 goto end_free_tid_writer;
552 }
9aa14175 553 count_writer = calloc(nr_writers, sizeof(*count_writer));
e7e6ff7f
MD
554 if (!count_writer) {
555 mainret = 1;
556 goto end_free_count_reader;
557 }
48ed1c18
MD
558
559 err = create_all_cpu_call_rcu_data(0);
8bcbd94a
MD
560 if (err) {
561 printf("Per-CPU call_rcu() worker threads unavailable. Using default global worker thread.\n");
562 }
48ed1c18 563
c0b8a865
LJ
564 if (memory_backend) {
565 test_ht = _cds_lfht_new(init_hash_size, min_hash_alloc_size,
566 max_hash_buckets_size,
567 (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
568 CDS_LFHT_ACCOUNTING, memory_backend,
569 &rcu_flavor, NULL);
570 } else {
571 test_ht = cds_lfht_new(init_hash_size, min_hash_alloc_size,
572 max_hash_buckets_size,
573 (opt_auto_resize ? CDS_LFHT_AUTO_RESIZE : 0) |
574 CDS_LFHT_ACCOUNTING, NULL);
575 }
0d02f4b5
MD
576 if (!test_ht) {
577 printf("Error allocating hash table.\n");
e7e6ff7f
MD
578 mainret = 1;
579 goto end_free_call_rcu_data;
0d02f4b5 580 }
c0b8a865 581
48ed1c18 582 /*
c0b8a865 583 * Hash Population needs to be seen as a RCU reader
48ed1c18
MD
584 * thread from the point of view of resize.
585 */
586 rcu_register_thread();
e7e6ff7f 587 ret = (get_populate_hash_cb())();
01477510 588 urcu_posix_assert(!ret);
59e371e3
MD
589
590 rcu_thread_offline();
14756542 591
ab7d5fc6
MD
592 next_aff = 0;
593
e7e6ff7f
MD
594 ret = pipe(count_pipe);
595 if (ret == -1) {
596 perror("pipe");
597 mainret = 1;
598 goto end_online;
599 }
600
601 /* spawn counter thread */
602 err = pthread_create(&tid_count, NULL, thr_count,
603 NULL);
604 if (err != 0) {
605 errno = err;
606 mainret = 1;
607 perror("pthread_create");
608 goto end_close_pipe;
609 }
610
83e334d0
MJ
611 for (i_thr = 0; i_thr < nr_readers; i_thr++) {
612 err = pthread_create(&tid_reader[i_thr],
f52c1ef7 613 NULL, get_thr_reader_cb(),
83e334d0 614 &count_reader[i_thr]);
e7e6ff7f
MD
615 if (err != 0) {
616 errno = err;
617 mainret = 1;
618 perror("pthread_create");
619 goto end_pthread_join;
620 }
621 nr_readers_created++;
ab7d5fc6 622 }
83e334d0
MJ
623 for (i_thr = 0; i_thr < nr_writers; i_thr++) {
624 err = pthread_create(&tid_writer[i_thr],
f52c1ef7 625 NULL, get_thr_writer_cb(),
83e334d0 626 &count_writer[i_thr]);
e7e6ff7f
MD
627 if (err != 0) {
628 errno = err;
629 mainret = 1;
630 perror("pthread_create");
631 goto end_pthread_join;
632 }
633 nr_writers_created++;
ab7d5fc6
MD
634 }
635
abc490a1 636 cmm_smp_mb();
ab7d5fc6
MD
637
638 test_go = 1;
639
3967a8a8
MD
640 remain = duration;
641 do {
642 remain = sleep(remain);
643 } while (remain > 0);
ab7d5fc6
MD
644
645 test_stop = 1;
646
e7e6ff7f 647end_pthread_join:
83e334d0
MJ
648 for (i_thr = 0; i_thr < nr_readers_created; i_thr++) {
649 err = pthread_join(tid_reader[i_thr], &tret);
e7e6ff7f
MD
650 if (err != 0) {
651 errno = err;
652 mainret = 1;
653 perror("pthread_join");
654 }
83e334d0 655 tot_reads += count_reader[i_thr];
ab7d5fc6 656 }
83e334d0
MJ
657 for (i_thr = 0; i_thr < nr_writers_created; i_thr++) {
658 err = pthread_join(tid_writer[i_thr], &tret);
e7e6ff7f
MD
659 if (err != 0) {
660 errno = err;
661 mainret = 1;
662 perror("pthread_join");
663 }
83e334d0
MJ
664 tot_writes += count_writer[i_thr].update_ops;
665 tot_add += count_writer[i_thr].add;
666 tot_add_exist += count_writer[i_thr].add_exist;
667 tot_remove += count_writer[i_thr].remove;
ab7d5fc6 668 }
7ed7682f
MD
669
670 /* teardown counter thread */
671 act.sa_handler = SIG_IGN;
672 act.sa_flags = SA_RESTART;
673 ret = sigaction(SIGUSR2, &act, NULL);
674 if (ret == -1) {
e7e6ff7f 675 mainret = 1;
7ed7682f 676 perror("sigaction");
7ed7682f
MD
677 }
678 {
679 char msg[1] = { 0x42 };
bd23a6c6 680 ssize_t sret;
3fb1173c
MD
681
682 do {
bd23a6c6
MJ
683 sret = write(count_pipe[1], msg, 1); /* wakeup thread */
684 } while (sret == -1L && errno == EINTR);
7ed7682f
MD
685 }
686 err = pthread_join(tid_count, &tret);
e7e6ff7f
MD
687 if (err != 0) {
688 errno = err;
689 mainret = 1;
690 perror("pthread_join");
691 }
7ed7682f 692
e7e6ff7f
MD
693end_close_pipe:
694 for (i = 0; i < 2; i++) {
695 err = close(count_pipe[i]);
696 if (err) {
697 mainret = 1;
698 perror("close pipe");
699 }
700 }
33c7c748 701 fflush(stdout);
e7e6ff7f 702end_online:
59e371e3
MD
703 rcu_thread_online();
704 rcu_read_lock();
175ec0eb 705 printf("Counting nodes... ");
caf3653d 706 cds_lfht_count_nodes(test_ht, &approx_before, &count, &approx_after);
175ec0eb
MD
707 printf("done.\n");
708 test_delete_all_nodes(test_ht);
59e371e3
MD
709 rcu_read_unlock();
710 rcu_thread_offline();
caf3653d 711 if (count) {
d933dd0e 712 printf("Approximation before node accounting: %ld nodes.\n",
973e5e1b 713 approx_before);
175ec0eb 714 printf("Nodes deleted from hash table before destroy: "
caf3653d
MD
715 "%lu nodes.\n",
716 count);
d933dd0e 717 printf("Approximation after node accounting: %ld nodes.\n",
973e5e1b
MD
718 approx_after);
719 }
e7e6ff7f 720
b7d619b0 721 ret = cds_lfht_destroy(test_ht, NULL);
e7e6ff7f 722 if (ret) {
33c7c748 723 printf_verbose("final delete aborted\n");
e7e6ff7f
MD
724 mainret = 1;
725 } else {
33c7c748 726 printf_verbose("final delete success\n");
e7e6ff7f 727 }
ab7d5fc6
MD
728 printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
729 tot_writes);
e7e6ff7f 730 nr_leaked = (long long) tot_add + init_populate - tot_remove - count;
ab7d5fc6
MD
731 printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu "
732 "nr_writers %3u "
d837911d 733 "wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu "
cd1ae16a 734 "nr_add %12llu nr_add_fail %12llu nr_remove %12llu nr_leaked %12lld\n",
ab7d5fc6 735 argv[0], duration, nr_readers, rduration,
d837911d 736 nr_writers, wdelay, tot_reads, tot_writes,
3c16bf4b 737 tot_reads + tot_writes, tot_add, tot_add_exist, tot_remove,
e7e6ff7f
MD
738 nr_leaked);
739 if (nr_leaked != 0) {
740 mainret = 1;
741 printf("WARNING: %lld nodes were leaked!\n", nr_leaked);
742 }
743
59e371e3 744 rcu_unregister_thread();
e7e6ff7f 745end_free_call_rcu_data:
3a22f1dd 746 free_all_cpu_call_rcu_data();
ab7d5fc6 747 free(count_writer);
e7e6ff7f
MD
748end_free_count_reader:
749 free(count_reader);
750end_free_tid_writer:
751 free(tid_writer);
752end_free_tid_reader:
753 free(tid_reader);
754end:
755 if (!mainret)
756 exit(EXIT_SUCCESS);
757 else
758 exit(EXIT_FAILURE);
ab7d5fc6 759}
This page took 0.084851 seconds and 4 git commands to generate.