1da668aa1SThomas Huth /*
2da668aa1SThomas Huth * rcutorture.c: simple user-level performance/stress test of RCU.
3da668aa1SThomas Huth *
4da668aa1SThomas Huth * Usage:
5da668aa1SThomas Huth * ./rcu <nreaders> rperf [ <seconds> ]
6da668aa1SThomas Huth * Run a read-side performance test with the specified
7da668aa1SThomas Huth * number of readers for <seconds> seconds.
8da668aa1SThomas Huth * ./rcu <nupdaters> uperf [ <seconds> ]
9da668aa1SThomas Huth * Run an update-side performance test with the specified
10da668aa1SThomas Huth * number of updaters and specified duration.
11da668aa1SThomas Huth * ./rcu <nreaders> perf [ <seconds> ]
12da668aa1SThomas Huth * Run a combined read/update performance test with the specified
13da668aa1SThomas Huth * number of readers and one updater and specified duration.
14da668aa1SThomas Huth *
15da668aa1SThomas Huth * The above tests produce output as follows:
16da668aa1SThomas Huth *
17da668aa1SThomas Huth * n_reads: 46008000 n_updates: 146026 nreaders: 2 nupdaters: 1 duration: 1
18da668aa1SThomas Huth * ns/read: 43.4707 ns/update: 6848.1
19da668aa1SThomas Huth *
20da668aa1SThomas Huth * The first line lists the total number of RCU reads and updates executed
21da668aa1SThomas Huth * during the test, the number of reader threads, the number of updater
22da668aa1SThomas Huth * threads, and the duration of the test in seconds. The second line
23da668aa1SThomas Huth * lists the average duration of each type of operation in nanoseconds,
24da668aa1SThomas Huth * or "nan" if the corresponding type of operation was not performed.
25da668aa1SThomas Huth *
26da668aa1SThomas Huth * ./rcu <nreaders> stress [ <seconds> ]
27da668aa1SThomas Huth * Run a stress test with the specified number of readers and
28da668aa1SThomas Huth * one updater.
29da668aa1SThomas Huth *
30da668aa1SThomas Huth * This test produces output as follows:
31da668aa1SThomas Huth *
32da668aa1SThomas Huth * n_reads: 114633217 n_updates: 3903415 n_mberror: 0
33da668aa1SThomas Huth * rcu_stress_count: 114618391 14826 0 0 0 0 0 0 0 0 0
34da668aa1SThomas Huth *
35da668aa1SThomas Huth * The first line lists the number of RCU read and update operations
36da668aa1SThomas Huth * executed, followed by the number of memory-ordering violations
37da668aa1SThomas Huth * (which will be zero in a correct RCU implementation). The second
38da668aa1SThomas Huth * line lists the number of readers observing progressively more stale
39da668aa1SThomas Huth * data. A correct RCU implementation will have all but the first two
40da668aa1SThomas Huth * numbers non-zero.
41da668aa1SThomas Huth *
42da668aa1SThomas Huth * This program is free software; you can redistribute it and/or modify
43da668aa1SThomas Huth * it under the terms of the GNU General Public License as published by
44da668aa1SThomas Huth * the Free Software Foundation; either version 2 of the License, or
45da668aa1SThomas Huth * (at your option) any later version.
46da668aa1SThomas Huth *
47da668aa1SThomas Huth * This program is distributed in the hope that it will be useful,
48da668aa1SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
49da668aa1SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50da668aa1SThomas Huth * GNU General Public License for more details.
51da668aa1SThomas Huth *
52da668aa1SThomas Huth * You should have received a copy of the GNU General Public License
53*0c201cc1SKhadija Kamran * along with this program. If not, see <https://www.gnu.org/licenses/>.
54da668aa1SThomas Huth *
55da668aa1SThomas Huth * Copyright (c) 2008 Paul E. McKenney, IBM Corporation.
56da668aa1SThomas Huth */
57da668aa1SThomas Huth
58da668aa1SThomas Huth /*
59da668aa1SThomas Huth * Test variables.
60da668aa1SThomas Huth */
61da668aa1SThomas Huth
62da668aa1SThomas Huth #include "qemu/osdep.h"
63da668aa1SThomas Huth #include "qemu/atomic.h"
64da668aa1SThomas Huth #include "qemu/rcu.h"
65da668aa1SThomas Huth #include "qemu/thread.h"
66da668aa1SThomas Huth
67da668aa1SThomas Huth int nthreadsrunning;
68da668aa1SThomas Huth
69da668aa1SThomas Huth #define GOFLAG_INIT 0
70da668aa1SThomas Huth #define GOFLAG_RUN 1
71da668aa1SThomas Huth #define GOFLAG_STOP 2
72da668aa1SThomas Huth
73da668aa1SThomas Huth static volatile int goflag = GOFLAG_INIT;
74da668aa1SThomas Huth
75da668aa1SThomas Huth #define RCU_READ_RUN 1000
76da668aa1SThomas Huth
77da668aa1SThomas Huth #define NR_THREADS 100
78da668aa1SThomas Huth static QemuThread threads[NR_THREADS];
79da668aa1SThomas Huth static struct rcu_reader_data *data[NR_THREADS];
80da668aa1SThomas Huth static int n_threads;
81da668aa1SThomas Huth
82da668aa1SThomas Huth /*
83da668aa1SThomas Huth * Statistical counts
84da668aa1SThomas Huth *
85da668aa1SThomas Huth * These are the sum of local counters at the end of a run.
86da668aa1SThomas Huth * Updates are protected by a mutex.
87da668aa1SThomas Huth */
88da668aa1SThomas Huth static QemuMutex counts_mutex;
89da668aa1SThomas Huth long long n_reads = 0LL;
90da668aa1SThomas Huth long n_updates = 0L;
91da668aa1SThomas Huth
create_thread(void * (* func)(void *))92da668aa1SThomas Huth static void create_thread(void *(*func)(void *))
93da668aa1SThomas Huth {
94da668aa1SThomas Huth if (n_threads >= NR_THREADS) {
95da668aa1SThomas Huth fprintf(stderr, "Thread limit of %d exceeded!\n", NR_THREADS);
96da668aa1SThomas Huth exit(-1);
97da668aa1SThomas Huth }
98da668aa1SThomas Huth qemu_thread_create(&threads[n_threads], "test", func, &data[n_threads],
99da668aa1SThomas Huth QEMU_THREAD_JOINABLE);
100da668aa1SThomas Huth n_threads++;
101da668aa1SThomas Huth }
102da668aa1SThomas Huth
wait_all_threads(void)103da668aa1SThomas Huth static void wait_all_threads(void)
104da668aa1SThomas Huth {
105da668aa1SThomas Huth int i;
106da668aa1SThomas Huth
107da668aa1SThomas Huth for (i = 0; i < n_threads; i++) {
108da668aa1SThomas Huth qemu_thread_join(&threads[i]);
109da668aa1SThomas Huth }
110da668aa1SThomas Huth n_threads = 0;
111da668aa1SThomas Huth }
112da668aa1SThomas Huth
113da668aa1SThomas Huth /*
114da668aa1SThomas Huth * Performance test.
115da668aa1SThomas Huth */
116da668aa1SThomas Huth
rcu_read_perf_test(void * arg)117da668aa1SThomas Huth static void *rcu_read_perf_test(void *arg)
118da668aa1SThomas Huth {
119da668aa1SThomas Huth int i;
120da668aa1SThomas Huth long long n_reads_local = 0;
121da668aa1SThomas Huth
122da668aa1SThomas Huth rcu_register_thread();
123da668aa1SThomas Huth
12417c78154SStefan Hajnoczi *(struct rcu_reader_data **)arg = get_ptr_rcu_reader();
125da668aa1SThomas Huth qatomic_inc(&nthreadsrunning);
126da668aa1SThomas Huth while (goflag == GOFLAG_INIT) {
127da668aa1SThomas Huth g_usleep(1000);
128da668aa1SThomas Huth }
129da668aa1SThomas Huth while (goflag == GOFLAG_RUN) {
130da668aa1SThomas Huth for (i = 0; i < RCU_READ_RUN; i++) {
131da668aa1SThomas Huth rcu_read_lock();
132da668aa1SThomas Huth rcu_read_unlock();
133da668aa1SThomas Huth }
134da668aa1SThomas Huth n_reads_local += RCU_READ_RUN;
135da668aa1SThomas Huth }
136da668aa1SThomas Huth qemu_mutex_lock(&counts_mutex);
137da668aa1SThomas Huth n_reads += n_reads_local;
138da668aa1SThomas Huth qemu_mutex_unlock(&counts_mutex);
139da668aa1SThomas Huth
140da668aa1SThomas Huth rcu_unregister_thread();
141da668aa1SThomas Huth return NULL;
142da668aa1SThomas Huth }
143da668aa1SThomas Huth
rcu_update_perf_test(void * arg)144da668aa1SThomas Huth static void *rcu_update_perf_test(void *arg)
145da668aa1SThomas Huth {
146da668aa1SThomas Huth long long n_updates_local = 0;
147da668aa1SThomas Huth
148da668aa1SThomas Huth rcu_register_thread();
149da668aa1SThomas Huth
15017c78154SStefan Hajnoczi *(struct rcu_reader_data **)arg = get_ptr_rcu_reader();
151da668aa1SThomas Huth qatomic_inc(&nthreadsrunning);
152da668aa1SThomas Huth while (goflag == GOFLAG_INIT) {
153da668aa1SThomas Huth g_usleep(1000);
154da668aa1SThomas Huth }
155da668aa1SThomas Huth while (goflag == GOFLAG_RUN) {
156da668aa1SThomas Huth synchronize_rcu();
157da668aa1SThomas Huth n_updates_local++;
158da668aa1SThomas Huth }
159da668aa1SThomas Huth qemu_mutex_lock(&counts_mutex);
160da668aa1SThomas Huth n_updates += n_updates_local;
161da668aa1SThomas Huth qemu_mutex_unlock(&counts_mutex);
162da668aa1SThomas Huth
163da668aa1SThomas Huth rcu_unregister_thread();
164da668aa1SThomas Huth return NULL;
165da668aa1SThomas Huth }
166da668aa1SThomas Huth
perftestinit(void)167da668aa1SThomas Huth static void perftestinit(void)
168da668aa1SThomas Huth {
169da668aa1SThomas Huth nthreadsrunning = 0;
170da668aa1SThomas Huth }
171da668aa1SThomas Huth
perftestrun(int nthreads,int duration,int nreaders,int nupdaters)172da668aa1SThomas Huth static void perftestrun(int nthreads, int duration, int nreaders, int nupdaters)
173da668aa1SThomas Huth {
174da668aa1SThomas Huth while (qatomic_read(&nthreadsrunning) < nthreads) {
175da668aa1SThomas Huth g_usleep(1000);
176da668aa1SThomas Huth }
177da668aa1SThomas Huth goflag = GOFLAG_RUN;
178da668aa1SThomas Huth g_usleep(duration * G_USEC_PER_SEC);
179da668aa1SThomas Huth goflag = GOFLAG_STOP;
180da668aa1SThomas Huth wait_all_threads();
181da668aa1SThomas Huth printf("n_reads: %lld n_updates: %ld nreaders: %d nupdaters: %d duration: %d\n",
182da668aa1SThomas Huth n_reads, n_updates, nreaders, nupdaters, duration);
183da668aa1SThomas Huth printf("ns/read: %g ns/update: %g\n",
184da668aa1SThomas Huth ((duration * 1000*1000*1000.*(double)nreaders) /
185da668aa1SThomas Huth (double)n_reads),
186da668aa1SThomas Huth ((duration * 1000*1000*1000.*(double)nupdaters) /
187da668aa1SThomas Huth (double)n_updates));
188da668aa1SThomas Huth exit(0);
189da668aa1SThomas Huth }
190da668aa1SThomas Huth
perftest(int nreaders,int duration)191da668aa1SThomas Huth static void perftest(int nreaders, int duration)
192da668aa1SThomas Huth {
193da668aa1SThomas Huth int i;
194da668aa1SThomas Huth
195da668aa1SThomas Huth perftestinit();
196da668aa1SThomas Huth for (i = 0; i < nreaders; i++) {
197da668aa1SThomas Huth create_thread(rcu_read_perf_test);
198da668aa1SThomas Huth }
199da668aa1SThomas Huth create_thread(rcu_update_perf_test);
200da668aa1SThomas Huth perftestrun(i + 1, duration, nreaders, 1);
201da668aa1SThomas Huth }
202da668aa1SThomas Huth
rperftest(int nreaders,int duration)203da668aa1SThomas Huth static void rperftest(int nreaders, int duration)
204da668aa1SThomas Huth {
205da668aa1SThomas Huth int i;
206da668aa1SThomas Huth
207da668aa1SThomas Huth perftestinit();
208da668aa1SThomas Huth for (i = 0; i < nreaders; i++) {
209da668aa1SThomas Huth create_thread(rcu_read_perf_test);
210da668aa1SThomas Huth }
211da668aa1SThomas Huth perftestrun(i, duration, nreaders, 0);
212da668aa1SThomas Huth }
213da668aa1SThomas Huth
uperftest(int nupdaters,int duration)214da668aa1SThomas Huth static void uperftest(int nupdaters, int duration)
215da668aa1SThomas Huth {
216da668aa1SThomas Huth int i;
217da668aa1SThomas Huth
218da668aa1SThomas Huth perftestinit();
219da668aa1SThomas Huth for (i = 0; i < nupdaters; i++) {
220da668aa1SThomas Huth create_thread(rcu_update_perf_test);
221da668aa1SThomas Huth }
222da668aa1SThomas Huth perftestrun(i, duration, 0, nupdaters);
223da668aa1SThomas Huth }
224da668aa1SThomas Huth
225da668aa1SThomas Huth /*
226da668aa1SThomas Huth * Stress test.
227da668aa1SThomas Huth */
228da668aa1SThomas Huth
229da668aa1SThomas Huth #define RCU_STRESS_PIPE_LEN 10
230da668aa1SThomas Huth
231da668aa1SThomas Huth struct rcu_stress {
232da668aa1SThomas Huth int age; /* how many update cycles while not rcu_stress_current */
233da668aa1SThomas Huth int mbtest;
234da668aa1SThomas Huth };
235da668aa1SThomas Huth
236da668aa1SThomas Huth struct rcu_stress rcu_stress_array[RCU_STRESS_PIPE_LEN] = { { 0 } };
237da668aa1SThomas Huth struct rcu_stress *rcu_stress_current;
238da668aa1SThomas Huth int n_mberror;
239da668aa1SThomas Huth
240da668aa1SThomas Huth /* Updates protected by counts_mutex */
241da668aa1SThomas Huth long long rcu_stress_count[RCU_STRESS_PIPE_LEN + 1];
242da668aa1SThomas Huth
243da668aa1SThomas Huth
rcu_read_stress_test(void * arg)244da668aa1SThomas Huth static void *rcu_read_stress_test(void *arg)
245da668aa1SThomas Huth {
246da668aa1SThomas Huth int i;
247da668aa1SThomas Huth struct rcu_stress *p;
248da668aa1SThomas Huth int pc;
249da668aa1SThomas Huth long long n_reads_local = 0;
250da668aa1SThomas Huth long long rcu_stress_local[RCU_STRESS_PIPE_LEN + 1] = { 0 };
251da668aa1SThomas Huth volatile int garbage = 0;
252da668aa1SThomas Huth
253da668aa1SThomas Huth rcu_register_thread();
254da668aa1SThomas Huth
25517c78154SStefan Hajnoczi *(struct rcu_reader_data **)arg = get_ptr_rcu_reader();
256da668aa1SThomas Huth while (goflag == GOFLAG_INIT) {
257da668aa1SThomas Huth g_usleep(1000);
258da668aa1SThomas Huth }
259da668aa1SThomas Huth while (goflag == GOFLAG_RUN) {
260da668aa1SThomas Huth rcu_read_lock();
261da668aa1SThomas Huth p = qatomic_rcu_read(&rcu_stress_current);
262da668aa1SThomas Huth if (qatomic_read(&p->mbtest) == 0) {
263da668aa1SThomas Huth n_mberror++;
264da668aa1SThomas Huth }
265da668aa1SThomas Huth rcu_read_lock();
266da668aa1SThomas Huth for (i = 0; i < 100; i++) {
267da668aa1SThomas Huth garbage++;
268da668aa1SThomas Huth }
269da668aa1SThomas Huth rcu_read_unlock();
270da668aa1SThomas Huth pc = qatomic_read(&p->age);
271da668aa1SThomas Huth rcu_read_unlock();
272da668aa1SThomas Huth if ((pc > RCU_STRESS_PIPE_LEN) || (pc < 0)) {
273da668aa1SThomas Huth pc = RCU_STRESS_PIPE_LEN;
274da668aa1SThomas Huth }
275da668aa1SThomas Huth rcu_stress_local[pc]++;
276da668aa1SThomas Huth n_reads_local++;
277da668aa1SThomas Huth }
278da668aa1SThomas Huth qemu_mutex_lock(&counts_mutex);
279da668aa1SThomas Huth n_reads += n_reads_local;
280da668aa1SThomas Huth for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) {
281da668aa1SThomas Huth rcu_stress_count[i] += rcu_stress_local[i];
282da668aa1SThomas Huth }
283da668aa1SThomas Huth qemu_mutex_unlock(&counts_mutex);
284da668aa1SThomas Huth
285da668aa1SThomas Huth rcu_unregister_thread();
286da668aa1SThomas Huth return NULL;
287da668aa1SThomas Huth }
288da668aa1SThomas Huth
289da668aa1SThomas Huth /*
290da668aa1SThomas Huth * Stress Test Updater
291da668aa1SThomas Huth *
292da668aa1SThomas Huth * The updater cycles around updating rcu_stress_current to point at
293da668aa1SThomas Huth * one of the rcu_stress_array_entries and resets it's age. It
294da668aa1SThomas Huth * then increments the age of all the other entries. The age
295da668aa1SThomas Huth * will be read under an rcu_read_lock() and distribution of values
296da668aa1SThomas Huth * calculated. The final result gives an indication of how many
297da668aa1SThomas Huth * previously current rcu_stress entries are in flight until the RCU
298da668aa1SThomas Huth * cycle complete.
299da668aa1SThomas Huth */
rcu_update_stress_test(void * arg)300da668aa1SThomas Huth static void *rcu_update_stress_test(void *arg)
301da668aa1SThomas Huth {
302da668aa1SThomas Huth int i, rcu_stress_idx = 0;
303da668aa1SThomas Huth struct rcu_stress *cp = qatomic_read(&rcu_stress_current);
304da668aa1SThomas Huth
305da668aa1SThomas Huth rcu_register_thread();
30617c78154SStefan Hajnoczi *(struct rcu_reader_data **)arg = get_ptr_rcu_reader();
307da668aa1SThomas Huth
308da668aa1SThomas Huth while (goflag == GOFLAG_INIT) {
309da668aa1SThomas Huth g_usleep(1000);
310da668aa1SThomas Huth }
311da668aa1SThomas Huth
312da668aa1SThomas Huth while (goflag == GOFLAG_RUN) {
313da668aa1SThomas Huth struct rcu_stress *p;
314da668aa1SThomas Huth rcu_stress_idx++;
315da668aa1SThomas Huth if (rcu_stress_idx >= RCU_STRESS_PIPE_LEN) {
316da668aa1SThomas Huth rcu_stress_idx = 0;
317da668aa1SThomas Huth }
318da668aa1SThomas Huth p = &rcu_stress_array[rcu_stress_idx];
319da668aa1SThomas Huth /* catching up with ourselves would be a bug */
320da668aa1SThomas Huth assert(p != cp);
321da668aa1SThomas Huth qatomic_set(&p->mbtest, 0);
322da668aa1SThomas Huth smp_mb();
323da668aa1SThomas Huth qatomic_set(&p->age, 0);
324da668aa1SThomas Huth qatomic_set(&p->mbtest, 1);
325da668aa1SThomas Huth qatomic_rcu_set(&rcu_stress_current, p);
326da668aa1SThomas Huth cp = p;
327da668aa1SThomas Huth /*
328da668aa1SThomas Huth * New RCU structure is now live, update pipe counts on old
329da668aa1SThomas Huth * ones.
330da668aa1SThomas Huth */
331da668aa1SThomas Huth for (i = 0; i < RCU_STRESS_PIPE_LEN; i++) {
332da668aa1SThomas Huth if (i != rcu_stress_idx) {
333da668aa1SThomas Huth qatomic_set(&rcu_stress_array[i].age,
334da668aa1SThomas Huth rcu_stress_array[i].age + 1);
335da668aa1SThomas Huth }
336da668aa1SThomas Huth }
337da668aa1SThomas Huth synchronize_rcu();
338da668aa1SThomas Huth n_updates++;
339da668aa1SThomas Huth }
340da668aa1SThomas Huth
341da668aa1SThomas Huth rcu_unregister_thread();
342da668aa1SThomas Huth return NULL;
343da668aa1SThomas Huth }
344da668aa1SThomas Huth
rcu_fake_update_stress_test(void * arg)345da668aa1SThomas Huth static void *rcu_fake_update_stress_test(void *arg)
346da668aa1SThomas Huth {
347da668aa1SThomas Huth rcu_register_thread();
348da668aa1SThomas Huth
34917c78154SStefan Hajnoczi *(struct rcu_reader_data **)arg = get_ptr_rcu_reader();
350da668aa1SThomas Huth while (goflag == GOFLAG_INIT) {
351da668aa1SThomas Huth g_usleep(1000);
352da668aa1SThomas Huth }
353da668aa1SThomas Huth while (goflag == GOFLAG_RUN) {
354da668aa1SThomas Huth synchronize_rcu();
355da668aa1SThomas Huth g_usleep(1000);
356da668aa1SThomas Huth }
357da668aa1SThomas Huth
358da668aa1SThomas Huth rcu_unregister_thread();
359da668aa1SThomas Huth return NULL;
360da668aa1SThomas Huth }
361da668aa1SThomas Huth
stresstest(int nreaders,int duration)362da668aa1SThomas Huth static void stresstest(int nreaders, int duration)
363da668aa1SThomas Huth {
364da668aa1SThomas Huth int i;
365da668aa1SThomas Huth
366da668aa1SThomas Huth rcu_stress_current = &rcu_stress_array[0];
367da668aa1SThomas Huth rcu_stress_current->age = 0;
368da668aa1SThomas Huth rcu_stress_current->mbtest = 1;
369da668aa1SThomas Huth for (i = 0; i < nreaders; i++) {
370da668aa1SThomas Huth create_thread(rcu_read_stress_test);
371da668aa1SThomas Huth }
372da668aa1SThomas Huth create_thread(rcu_update_stress_test);
373da668aa1SThomas Huth for (i = 0; i < 5; i++) {
374da668aa1SThomas Huth create_thread(rcu_fake_update_stress_test);
375da668aa1SThomas Huth }
376da668aa1SThomas Huth goflag = GOFLAG_RUN;
377da668aa1SThomas Huth g_usleep(duration * G_USEC_PER_SEC);
378da668aa1SThomas Huth goflag = GOFLAG_STOP;
379da668aa1SThomas Huth wait_all_threads();
380da668aa1SThomas Huth printf("n_reads: %lld n_updates: %ld n_mberror: %d\n",
381da668aa1SThomas Huth n_reads, n_updates, n_mberror);
382da668aa1SThomas Huth printf("rcu_stress_count:");
383da668aa1SThomas Huth for (i = 0; i <= RCU_STRESS_PIPE_LEN; i++) {
384da668aa1SThomas Huth printf(" %lld", rcu_stress_count[i]);
385da668aa1SThomas Huth }
386da668aa1SThomas Huth printf("\n");
387da668aa1SThomas Huth exit(0);
388da668aa1SThomas Huth }
389da668aa1SThomas Huth
390da668aa1SThomas Huth /* GTest interface */
391da668aa1SThomas Huth
gtest_stress(int nreaders,int duration)392da668aa1SThomas Huth static void gtest_stress(int nreaders, int duration)
393da668aa1SThomas Huth {
394da668aa1SThomas Huth int i;
395da668aa1SThomas Huth
396da668aa1SThomas Huth rcu_stress_current = &rcu_stress_array[0];
397da668aa1SThomas Huth rcu_stress_current->age = 0;
398da668aa1SThomas Huth rcu_stress_current->mbtest = 1;
399da668aa1SThomas Huth for (i = 0; i < nreaders; i++) {
400da668aa1SThomas Huth create_thread(rcu_read_stress_test);
401da668aa1SThomas Huth }
402da668aa1SThomas Huth create_thread(rcu_update_stress_test);
403da668aa1SThomas Huth for (i = 0; i < 5; i++) {
404da668aa1SThomas Huth create_thread(rcu_fake_update_stress_test);
405da668aa1SThomas Huth }
406da668aa1SThomas Huth goflag = GOFLAG_RUN;
407da668aa1SThomas Huth g_usleep(duration * G_USEC_PER_SEC);
408da668aa1SThomas Huth goflag = GOFLAG_STOP;
409da668aa1SThomas Huth wait_all_threads();
410da668aa1SThomas Huth g_assert_cmpint(n_mberror, ==, 0);
411da668aa1SThomas Huth for (i = 2; i <= RCU_STRESS_PIPE_LEN; i++) {
412da668aa1SThomas Huth g_assert_cmpint(rcu_stress_count[i], ==, 0);
413da668aa1SThomas Huth }
414da668aa1SThomas Huth }
415da668aa1SThomas Huth
gtest_stress_1_1(void)416da668aa1SThomas Huth static void gtest_stress_1_1(void)
417da668aa1SThomas Huth {
418da668aa1SThomas Huth gtest_stress(1, 1);
419da668aa1SThomas Huth }
420da668aa1SThomas Huth
gtest_stress_10_1(void)421da668aa1SThomas Huth static void gtest_stress_10_1(void)
422da668aa1SThomas Huth {
423da668aa1SThomas Huth gtest_stress(10, 1);
424da668aa1SThomas Huth }
425da668aa1SThomas Huth
gtest_stress_1_5(void)426da668aa1SThomas Huth static void gtest_stress_1_5(void)
427da668aa1SThomas Huth {
428da668aa1SThomas Huth gtest_stress(1, 5);
429da668aa1SThomas Huth }
430da668aa1SThomas Huth
gtest_stress_10_5(void)431da668aa1SThomas Huth static void gtest_stress_10_5(void)
432da668aa1SThomas Huth {
433da668aa1SThomas Huth gtest_stress(10, 5);
434da668aa1SThomas Huth }
435da668aa1SThomas Huth
436da668aa1SThomas Huth /*
437da668aa1SThomas Huth * Mainprogram.
438da668aa1SThomas Huth */
439da668aa1SThomas Huth
usage(int argc,char * argv[])440da668aa1SThomas Huth static void usage(int argc, char *argv[])
441da668aa1SThomas Huth {
442da668aa1SThomas Huth fprintf(stderr, "Usage: %s [nreaders [ [r|u]perf | stress [duration]]\n",
443da668aa1SThomas Huth argv[0]);
444da668aa1SThomas Huth exit(-1);
445da668aa1SThomas Huth }
446da668aa1SThomas Huth
main(int argc,char * argv[])447da668aa1SThomas Huth int main(int argc, char *argv[])
448da668aa1SThomas Huth {
449da668aa1SThomas Huth int nreaders = 1;
450da668aa1SThomas Huth int duration = 1;
451da668aa1SThomas Huth
452da668aa1SThomas Huth qemu_mutex_init(&counts_mutex);
453da668aa1SThomas Huth if (argc >= 2 && argv[1][0] == '-') {
454da668aa1SThomas Huth g_test_init(&argc, &argv, NULL);
455da668aa1SThomas Huth if (g_test_quick()) {
456da668aa1SThomas Huth g_test_add_func("/rcu/torture/1reader", gtest_stress_1_1);
457da668aa1SThomas Huth g_test_add_func("/rcu/torture/10readers", gtest_stress_10_1);
458da668aa1SThomas Huth } else {
459da668aa1SThomas Huth g_test_add_func("/rcu/torture/1reader", gtest_stress_1_5);
460da668aa1SThomas Huth g_test_add_func("/rcu/torture/10readers", gtest_stress_10_5);
461da668aa1SThomas Huth }
462da668aa1SThomas Huth return g_test_run();
463da668aa1SThomas Huth }
464da668aa1SThomas Huth
465da668aa1SThomas Huth if (argc >= 2) {
466da668aa1SThomas Huth nreaders = strtoul(argv[1], NULL, 0);
467da668aa1SThomas Huth }
468da668aa1SThomas Huth if (argc > 3) {
469da668aa1SThomas Huth duration = strtoul(argv[3], NULL, 0);
470da668aa1SThomas Huth }
471da668aa1SThomas Huth if (argc < 3 || strcmp(argv[2], "stress") == 0) {
472da668aa1SThomas Huth stresstest(nreaders, duration);
473da668aa1SThomas Huth } else if (strcmp(argv[2], "rperf") == 0) {
474da668aa1SThomas Huth rperftest(nreaders, duration);
475da668aa1SThomas Huth } else if (strcmp(argv[2], "uperf") == 0) {
476da668aa1SThomas Huth uperftest(nreaders, duration);
477da668aa1SThomas Huth } else if (strcmp(argv[2], "perf") == 0) {
478da668aa1SThomas Huth perftest(nreaders, duration);
479da668aa1SThomas Huth }
480da668aa1SThomas Huth usage(argc, argv);
481da668aa1SThomas Huth return 0;
482da668aa1SThomas Huth }
483