rcu: move alignment to per-cpu structure
[libside.git] / tests / regression / side-rcu-test.c
CommitLineData
a536d5a4
MD
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
6#include <pthread.h>
7#include <stdint.h>
8#include <inttypes.h>
9
748f8271
MD
10static int nr_reader_threads = 2;
11static int nr_writer_threads = 2;
a536d5a4
MD
12static int duration_s = 10;
13
14static volatile int start_test, stop_test;
15
16struct thread_ctx {
17 pthread_t thread_id;
18 uint64_t count;
19};
20
80a8b8dd
MD
21#include "../../src/rcu.h"
22
a536d5a4
MD
23static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
24
25static struct side_rcu_gp_state test_rcu_gp;
26
8b17fb21 27#define POISON_VALUE 55
a536d5a4
MD
28
29struct test_data {
30 int v;
31};
32
8b17fb21 33static struct test_data *rcu_p;
a536d5a4
MD
34
35static
36void *test_reader_thread(void *arg)
37{
38 struct thread_ctx *thread_ctx = (struct thread_ctx *) arg;
39 uint64_t count = 0;
40
41 while (!start_test) { }
42
43 while (!stop_test) {
8b17fb21
MD
44 struct test_data *p;
45 int v, period;
a536d5a4
MD
46
47 period = side_rcu_read_begin(&test_rcu_gp);
8b17fb21
MD
48 p = side_rcu_dereference(rcu_p);
49 if (p) {
50 v = p->v;
51 if (v != 0 && v != 1) {
52 fprintf(stderr, "Unexpected value: %d\n", v);
53 abort();
54 }
55 }
a536d5a4
MD
56 side_rcu_read_end(&test_rcu_gp, period);
57 count++;
58 }
59 thread_ctx->count = count;
60 return NULL;
61}
62
63static
64void *test_writer_thread(void *arg)
65{
66 struct thread_ctx *thread_ctx = (struct thread_ctx *) arg;
67 uint64_t count = 0;
68
69 while (!start_test) { }
70
71 while (!stop_test) {
72 struct test_data *new_data, *old_data;
73
74 new_data = calloc(1, sizeof(struct test_data));
75 if (!new_data)
76 abort();
77
78 pthread_mutex_lock(&lock);
8b17fb21 79 old_data = rcu_p;
a536d5a4
MD
80 if (old_data)
81 new_data->v = old_data->v ^ 1; /* 0 or 1 */
8b17fb21 82 side_rcu_assign_pointer(rcu_p, new_data);
a536d5a4
MD
83 pthread_mutex_unlock(&lock);
84
85 side_rcu_wait_grace_period(&test_rcu_gp);
86
87 if (old_data) {
88 old_data->v = POISON_VALUE;
89 free(old_data);
90 }
91 count++;
92 }
93 thread_ctx->count = count;
94 return NULL;
95}
96
f50a47e0
MD
97static
98void print_help(void)
99{
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");
104}
105
106static
107int parse_cmd_line(int argc, const char **argv)
108{
109 const char *arg = NULL;
110 int i, ret = 0;
111
112 for (i = 1; i < argc; i++) {
113 arg = argv[i];
114
115 switch (arg[0]) {
116 case '-':
117 switch (arg[1]) {
118 case '\0':
119 goto error;
120 case 'd':
121 if (i == argc - 1)
122 goto error_extra_arg;
123 duration_s = atoi(argv[i + 1]);
124 i++;
125 break;
126 case 'r':
127 if (i == argc - 1)
128 goto error_extra_arg;
129 nr_reader_threads = atoi(argv[i + 1]);
130 i++;
131 break;
132 case 'w':
133 if (i == argc - 1)
134 goto error_extra_arg;
135 nr_writer_threads = atoi(argv[i + 1]);
136 i++;
137 break;
138 case 'h':
139 print_help();
140 ret = 1;
141 break;
142 }
143 break;
144 default:
145 goto error;
146 }
147
148 }
149 return ret;
150
151error:
152 fprintf(stderr, "Unknown command line option '%s'\n", arg);
153 return -1;
154error_extra_arg:
155 fprintf(stderr, "Command line option '%s' requires an extra argument\n", arg);
156 return -1;
157}
158
159int main(int argc, const char **argv)
80a8b8dd 160{
a536d5a4
MD
161 struct thread_ctx *reader_ctx;
162 struct thread_ctx *writer_ctx;
163 int i, ret;
f50a47e0 164 int sleep_s;
a536d5a4
MD
165 uint64_t read_tot = 0, write_tot = 0;
166
f50a47e0
MD
167 ret = parse_cmd_line(argc, argv);
168 if (ret < 0)
169 return -1;
170 if (ret > 0)
171 return 0;
a536d5a4 172
f50a47e0
MD
173 sleep_s = duration_s;
174 side_rcu_gp_init(&test_rcu_gp);
a536d5a4
MD
175 reader_ctx = calloc(nr_reader_threads, sizeof(struct thread_ctx));
176 if (!reader_ctx)
177 abort();
178 writer_ctx = calloc(nr_writer_threads, sizeof(struct thread_ctx));
179 if (!writer_ctx)
180 abort();
181
182
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]);
185 if (ret) {
186 errno = ret;
187 perror("pthread_create");
188 abort();
189 }
190 }
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]);
193 if (ret) {
194 errno = ret;
195 perror("pthread_create");
196 abort();
197 }
198 }
199
200 start_test = 1;
201
202 while (sleep_s > 0) {
203 sleep_s = sleep(sleep_s);
204 }
205
206 stop_test = 1;
207
208 for (i = 0; i < nr_reader_threads; i++) {
209 void *res;
210
211 ret = pthread_join(reader_ctx[i].thread_id, &res);
212 if (ret) {
213 errno = ret;
214 perror("pthread_join");
215 abort();
216 }
217 read_tot += reader_ctx[i].count;
218 }
219 for (i = 0; i < nr_writer_threads; i++) {
220 void *res;
221
222 ret = pthread_join(writer_ctx[i].thread_id, &res);
223 if (ret) {
224 errno = ret;
225 perror("pthread_join");
226 abort();
227 }
228 write_tot += writer_ctx[i].count;
229 }
f50a47e0 230 printf("Summary: duration: %d s, nr_reader_threads: %d, nr_writer_threads: %d, reads: %" PRIu64 ", writes: %" PRIu64 "\n",
a536d5a4
MD
231 duration_s, nr_reader_threads, nr_writer_threads, read_tot, write_tot);
232 free(reader_ctx);
233 free(writer_ctx);
234 side_rcu_gp_exit(&test_rcu_gp);
80a8b8dd
MD
235 return 0;
236}
This page took 0.032775 seconds and 4 git commands to generate.