xref: /openbmc/qemu/tests/unit/rcutorture.c (revision 3db629f03e8caf39526cd0415dac16a6a6484107)
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