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