1 // SPDX-License-Identifier: MIT
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
10 static int nr_reader_threads
= 2;
11 static int nr_writer_threads
= 2;
12 static int duration_s
= 10;
14 static volatile int start_test
, stop_test
;
21 #include "../../src/rcu.h"
23 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
25 static struct side_rcu_gp_state test_rcu_gp
;
27 #define POISON_VALUE 55
33 static struct test_data
*rcu_p
;
36 void *test_reader_thread(void *arg
)
38 struct thread_ctx
*thread_ctx
= (struct thread_ctx
*) arg
;
41 while (!start_test
) { }
47 period
= side_rcu_read_begin(&test_rcu_gp
);
48 p
= side_rcu_dereference(rcu_p
);
51 if (v
!= 0 && v
!= 1) {
52 fprintf(stderr
, "Unexpected value: %d\n", v
);
56 side_rcu_read_end(&test_rcu_gp
, period
);
59 thread_ctx
->count
= count
;
64 void *test_writer_thread(void *arg
)
66 struct thread_ctx
*thread_ctx
= (struct thread_ctx
*) arg
;
69 while (!start_test
) { }
72 struct test_data
*new_data
, *old_data
;
74 new_data
= calloc(1, sizeof(struct test_data
));
78 pthread_mutex_lock(&lock
);
81 new_data
->v
= old_data
->v
^ 1; /* 0 or 1 */
82 side_rcu_assign_pointer(rcu_p
, new_data
);
83 pthread_mutex_unlock(&lock
);
85 side_rcu_wait_grace_period(&test_rcu_gp
);
88 old_data
->v
= POISON_VALUE
;
93 thread_ctx
->count
= count
;
100 printf("Invoke with command line arguments:\n");
101 printf(" -d <seconds> (test duration in seconds)\n");
102 printf(" -r <nr_readers> (number of reader threads)\n");
103 printf(" -w <nr_writers> (number of writers threads)\n");
107 int parse_cmd_line(int argc
, const char **argv
)
109 const char *arg
= NULL
;
112 for (i
= 1; i
< argc
; i
++) {
122 goto error_extra_arg
;
123 duration_s
= atoi(argv
[i
+ 1]);
128 goto error_extra_arg
;
129 nr_reader_threads
= atoi(argv
[i
+ 1]);
134 goto error_extra_arg
;
135 nr_writer_threads
= atoi(argv
[i
+ 1]);
152 fprintf(stderr
, "Unknown command line option '%s'\n", arg
);
155 fprintf(stderr
, "Command line option '%s' requires an extra argument\n", arg
);
159 int main(int argc
, const char **argv
)
161 struct thread_ctx
*reader_ctx
;
162 struct thread_ctx
*writer_ctx
;
165 uint64_t read_tot
= 0, write_tot
= 0;
167 ret
= parse_cmd_line(argc
, argv
);
173 sleep_s
= duration_s
;
174 side_rcu_gp_init(&test_rcu_gp
);
175 reader_ctx
= calloc(nr_reader_threads
, sizeof(struct thread_ctx
));
178 writer_ctx
= calloc(nr_writer_threads
, sizeof(struct thread_ctx
));
183 for (i
= 0; i
< nr_reader_threads
; i
++) {
184 ret
= pthread_create(&reader_ctx
[i
].thread_id
, NULL
, test_reader_thread
, &reader_ctx
[i
]);
187 perror("pthread_create");
191 for (i
= 0; i
< nr_writer_threads
; i
++) {
192 ret
= pthread_create(&writer_ctx
[i
].thread_id
, NULL
, test_writer_thread
, &writer_ctx
[i
]);
195 perror("pthread_create");
202 while (sleep_s
> 0) {
203 sleep_s
= sleep(sleep_s
);
208 for (i
= 0; i
< nr_reader_threads
; i
++) {
211 ret
= pthread_join(reader_ctx
[i
].thread_id
, &res
);
214 perror("pthread_join");
217 read_tot
+= reader_ctx
[i
].count
;
219 for (i
= 0; i
< nr_writer_threads
; i
++) {
222 ret
= pthread_join(writer_ctx
[i
].thread_id
, &res
);
225 perror("pthread_join");
228 write_tot
+= writer_ctx
[i
].count
;
230 printf("Summary: duration: %d s, nr_reader_threads: %d, nr_writer_threads: %d, reads: %" PRIu64
", writes: %" PRIu64
"\n",
231 duration_s
, nr_reader_threads
, nr_writer_threads
, read_tot
, write_tot
);
234 side_rcu_gp_exit(&test_rcu_gp
);