mm-only debug patch...
[mmotm.git] / kernel / synchro-test.c
blob6ea17fb7088097efcd3e6e38308c3fd6409330e8
1 /* synchro-test.c: run some threads to test the synchronisation primitives
3 * Copyright (C) 2005, 2006 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 * The module should be run as something like:
13 * insmod synchro-test.ko rd=2 wr=2
14 * insmod synchro-test.ko mx=1
15 * insmod synchro-test.ko sm=2 ism=1
16 * insmod synchro-test.ko sm=2 ism=2
18 * See Documentation/synchro-test.txt for more information.
21 #include <linux/module.h>
22 #include <linux/poll.h>
23 #include <linux/moduleparam.h>
24 #include <linux/sched.h>
25 #include <linux/stat.h>
26 #include <linux/init.h>
27 #include <asm/atomic.h>
28 #include <linux/personality.h>
29 #include <linux/smp_lock.h>
30 #include <linux/delay.h>
31 #include <linux/timer.h>
32 #include <linux/completion.h>
33 #include <linux/mutex.h>
35 #define MAX_THREADS 64
38 * Turn on self-validation if we do a one-shot boot-time test:
40 #ifndef MODULE
41 # define VALIDATE_OPERATORS
42 #endif
44 static int nummx;
45 static int numsm, seminit = 4;
46 static int numrd, numwr, numdg;
47 static int elapse = 5, load = 2, do_sched, interval = 2;
48 static int verbose = 0;
50 MODULE_AUTHOR("David Howells");
51 MODULE_DESCRIPTION("Synchronisation primitive test demo");
52 MODULE_LICENSE("GPL");
54 module_param_named(v, verbose, int, 0);
55 MODULE_PARM_DESC(verbose, "Verbosity");
57 module_param_named(mx, nummx, int, 0);
58 MODULE_PARM_DESC(nummx, "Number of mutex threads");
60 module_param_named(sm, numsm, int, 0);
61 MODULE_PARM_DESC(numsm, "Number of semaphore threads");
63 module_param_named(ism, seminit, int, 0);
64 MODULE_PARM_DESC(seminit, "Initial semaphore value");
66 module_param_named(rd, numrd, int, 0);
67 MODULE_PARM_DESC(numrd, "Number of reader threads");
69 module_param_named(wr, numwr, int, 0);
70 MODULE_PARM_DESC(numwr, "Number of writer threads");
72 module_param_named(dg, numdg, int, 0);
73 MODULE_PARM_DESC(numdg, "Number of downgrader threads");
75 module_param(elapse, int, 0);
76 MODULE_PARM_DESC(elapse, "Number of seconds to run for");
78 module_param(load, int, 0);
79 MODULE_PARM_DESC(load, "Length of load in uS");
81 module_param(interval, int, 0);
82 MODULE_PARM_DESC(interval, "Length of interval in uS before re-getting lock");
84 module_param(do_sched, int, 0);
85 MODULE_PARM_DESC(do_sched, "True if each thread should schedule regularly");
87 /* the semaphores under test */
88 static struct mutex ____cacheline_aligned mutex;
89 static struct semaphore ____cacheline_aligned sem;
90 static struct rw_semaphore ____cacheline_aligned rwsem;
92 static atomic_t ____cacheline_aligned do_stuff = ATOMIC_INIT(0);
94 #ifdef VALIDATE_OPERATORS
95 static atomic_t ____cacheline_aligned mutexes = ATOMIC_INIT(0);
96 static atomic_t ____cacheline_aligned semaphores = ATOMIC_INIT(0);
97 static atomic_t ____cacheline_aligned readers = ATOMIC_INIT(0);
98 static atomic_t ____cacheline_aligned writers = ATOMIC_INIT(0);
99 #endif
101 static unsigned int ____cacheline_aligned mutexes_taken [MAX_THREADS];
102 static unsigned int ____cacheline_aligned semaphores_taken [MAX_THREADS];
103 static unsigned int ____cacheline_aligned reads_taken [MAX_THREADS];
104 static unsigned int ____cacheline_aligned writes_taken [MAX_THREADS];
105 static unsigned int ____cacheline_aligned downgrades_taken [MAX_THREADS];
107 static struct completion ____cacheline_aligned mx_comp[MAX_THREADS];
108 static struct completion ____cacheline_aligned sm_comp[MAX_THREADS];
109 static struct completion ____cacheline_aligned rd_comp[MAX_THREADS];
110 static struct completion ____cacheline_aligned wr_comp[MAX_THREADS];
111 static struct completion ____cacheline_aligned dg_comp[MAX_THREADS];
113 static struct timer_list ____cacheline_aligned timer;
115 #define ACCOUNT(var, N) var##_taken[N]++;
117 #ifdef VALIDATE_OPERATORS
118 #define TRACK(var, dir) atomic_##dir(&(var))
120 #define CHECK(var, cond, val) \
121 do { \
122 int x = atomic_read(&(var)); \
123 if (unlikely(!(x cond (val)))) \
124 printk("check [%s %s %d, == %d] failed in %s\n", \
125 #var, #cond, (val), x, __func__); \
126 } while (0)
128 #else
129 #define TRACK(var, dir) do {} while(0)
130 #define CHECK(var, cond, val) do {} while(0)
131 #endif
133 static inline void do_mutex_lock(unsigned int N)
135 mutex_lock(&mutex);
137 ACCOUNT(mutexes, N);
138 TRACK(mutexes, inc);
139 CHECK(mutexes, ==, 1);
142 static inline void do_mutex_unlock(unsigned int N)
144 CHECK(mutexes, ==, 1);
145 TRACK(mutexes, dec);
147 mutex_unlock(&mutex);
150 static inline void do_down(unsigned int N)
152 CHECK(mutexes, <, seminit);
154 down(&sem);
156 ACCOUNT(semaphores, N);
157 TRACK(semaphores, inc);
160 static inline void do_up(unsigned int N)
162 CHECK(semaphores, >, 0);
163 TRACK(semaphores, dec);
165 up(&sem);
168 static inline void do_down_read(unsigned int N)
170 down_read(&rwsem);
172 ACCOUNT(reads, N);
173 TRACK(readers, inc);
174 CHECK(readers, >, 0);
175 CHECK(writers, ==, 0);
178 static inline void do_up_read(unsigned int N)
180 CHECK(readers, >, 0);
181 CHECK(writers, ==, 0);
182 TRACK(readers, dec);
184 up_read(&rwsem);
187 static inline void do_down_write(unsigned int N)
189 down_write(&rwsem);
191 ACCOUNT(writes, N);
192 TRACK(writers, inc);
193 CHECK(writers, ==, 1);
194 CHECK(readers, ==, 0);
197 static inline void do_up_write(unsigned int N)
199 CHECK(writers, ==, 1);
200 CHECK(readers, ==, 0);
201 TRACK(writers, dec);
203 up_write(&rwsem);
206 static inline void do_downgrade_write(unsigned int N)
208 CHECK(writers, ==, 1);
209 CHECK(readers, ==, 0);
210 TRACK(writers, dec);
211 TRACK(readers, inc);
213 downgrade_write(&rwsem);
215 ACCOUNT(downgrades, N);
218 static inline void sched(void)
220 if (do_sched)
221 schedule();
224 static int mutexer(void *arg)
226 unsigned int N = (unsigned long) arg;
228 daemonize("Mutex%u", N);
229 set_user_nice(current, 19);
231 while (atomic_read(&do_stuff)) {
232 do_mutex_lock(N);
233 if (load)
234 udelay(load);
235 do_mutex_unlock(N);
236 sched();
237 if (interval)
238 udelay(interval);
241 if (verbose >= 2)
242 printk("%s: done\n", current->comm);
243 complete_and_exit(&mx_comp[N], 0);
246 static int semaphorer(void *arg)
248 unsigned int N = (unsigned long) arg;
250 daemonize("Sem%u", N);
251 set_user_nice(current, 19);
253 while (atomic_read(&do_stuff)) {
254 do_down(N);
255 if (load)
256 udelay(load);
257 do_up(N);
258 sched();
259 if (interval)
260 udelay(interval);
263 if (verbose >= 2)
264 printk("%s: done\n", current->comm);
265 complete_and_exit(&sm_comp[N], 0);
268 static int reader(void *arg)
270 unsigned int N = (unsigned long) arg;
272 daemonize("Read%u", N);
273 set_user_nice(current, 19);
275 while (atomic_read(&do_stuff)) {
276 do_down_read(N);
277 #ifdef LOAD_TEST
278 if (load)
279 udelay(load);
280 #endif
281 do_up_read(N);
282 sched();
283 if (interval)
284 udelay(interval);
287 if (verbose >= 2)
288 printk("%s: done\n", current->comm);
289 complete_and_exit(&rd_comp[N], 0);
292 static int writer(void *arg)
294 unsigned int N = (unsigned long) arg;
296 daemonize("Write%u", N);
297 set_user_nice(current, 19);
299 while (atomic_read(&do_stuff)) {
300 do_down_write(N);
301 #ifdef LOAD_TEST
302 if (load)
303 udelay(load);
304 #endif
305 do_up_write(N);
306 sched();
307 if (interval)
308 udelay(interval);
311 if (verbose >= 2)
312 printk("%s: done\n", current->comm);
313 complete_and_exit(&wr_comp[N], 0);
316 static int downgrader(void *arg)
318 unsigned int N = (unsigned long) arg;
320 daemonize("Down%u", N);
321 set_user_nice(current, 19);
323 while (atomic_read(&do_stuff)) {
324 do_down_write(N);
325 #ifdef LOAD_TEST
326 if (load)
327 udelay(load);
328 #endif
329 do_downgrade_write(N);
330 #ifdef LOAD_TEST
331 if (load)
332 udelay(load);
333 #endif
334 do_up_read(N);
335 sched();
336 if (interval)
337 udelay(interval);
340 if (verbose >= 2)
341 printk("%s: done\n", current->comm);
342 complete_and_exit(&dg_comp[N], 0);
345 static void stop_test(unsigned long dummy)
347 atomic_set(&do_stuff, 0);
350 static unsigned int total(const char *what, unsigned int counts[], int num)
352 unsigned int tot = 0, max = 0, min = UINT_MAX, zeros = 0, cnt;
353 int loop;
355 for (loop = 0; loop < num; loop++) {
356 cnt = counts[loop];
358 if (cnt == 0) {
359 zeros++;
360 min = 0;
361 continue;
364 tot += cnt;
365 if (tot > max)
366 max = tot;
367 if (tot < min)
368 min = tot;
371 if (verbose && tot > 0) {
372 printk("%s:", what);
374 for (loop = 0; loop < num; loop++) {
375 cnt = counts[loop];
377 if (cnt == 0)
378 printk(" zzz");
379 else
380 printk(" %d%%", cnt * 100 / tot);
383 printk("\n");
386 return tot;
389 /*****************************************************************************/
393 static int __init do_tests(void)
395 unsigned long loop;
396 unsigned int mutex_total, sem_total, rd_total, wr_total, dg_total;
398 if (nummx < 0 || nummx > MAX_THREADS ||
399 numsm < 0 || numsm > MAX_THREADS ||
400 numrd < 0 || numrd > MAX_THREADS ||
401 numwr < 0 || numwr > MAX_THREADS ||
402 numdg < 0 || numdg > MAX_THREADS ||
403 seminit < 1 ||
404 elapse < 1 ||
405 load < 0 || load > 999 ||
406 interval < 0 || interval > 999
408 printk("Parameter out of range\n");
409 return -ERANGE;
412 if ((nummx | numsm | numrd | numwr | numdg) == 0) {
413 int num = num_online_cpus();
415 if (num > MAX_THREADS)
416 num = MAX_THREADS;
417 nummx = numsm = numrd = numwr = numdg = num;
419 load = 1;
420 interval = 1;
421 do_sched = 1;
422 printk("No parameters - using defaults.\n");
425 if (verbose)
426 printk("\nStarting synchronisation primitive tests...\n");
428 mutex_init(&mutex);
429 sema_init(&sem, seminit);
430 init_rwsem(&rwsem);
431 atomic_set(&do_stuff, 1);
433 /* kick off all the children */
434 for (loop = 0; loop < MAX_THREADS; loop++) {
435 if (loop < nummx) {
436 init_completion(&mx_comp[loop]);
437 kernel_thread(mutexer, (void *) loop, 0);
440 if (loop < numsm) {
441 init_completion(&sm_comp[loop]);
442 kernel_thread(semaphorer, (void *) loop, 0);
445 if (loop < numrd) {
446 init_completion(&rd_comp[loop]);
447 kernel_thread(reader, (void *) loop, 0);
450 if (loop < numwr) {
451 init_completion(&wr_comp[loop]);
452 kernel_thread(writer, (void *) loop, 0);
455 if (loop < numdg) {
456 init_completion(&dg_comp[loop]);
457 kernel_thread(downgrader, (void *) loop, 0);
461 /* set a stop timer */
462 init_timer(&timer);
463 timer.function = stop_test;
464 timer.expires = jiffies + elapse * HZ;
465 add_timer(&timer);
467 /* now wait until it's all done */
468 for (loop = 0; loop < nummx; loop++)
469 wait_for_completion(&mx_comp[loop]);
471 for (loop = 0; loop < numsm; loop++)
472 wait_for_completion(&sm_comp[loop]);
474 for (loop = 0; loop < numrd; loop++)
475 wait_for_completion(&rd_comp[loop]);
477 for (loop = 0; loop < numwr; loop++)
478 wait_for_completion(&wr_comp[loop]);
480 for (loop = 0; loop < numdg; loop++)
481 wait_for_completion(&dg_comp[loop]);
483 atomic_set(&do_stuff, 0);
484 del_timer(&timer);
486 if (mutex_is_locked(&mutex))
487 printk(KERN_ERR "Mutex is still locked!\n");
489 /* count up */
490 mutex_total = total("MTX", mutexes_taken, nummx);
491 sem_total = total("SEM", semaphores_taken, numsm);
492 rd_total = total("RD ", reads_taken, numrd);
493 wr_total = total("WR ", writes_taken, numwr);
494 dg_total = total("DG ", downgrades_taken, numdg);
496 /* print the results */
497 if (verbose) {
498 printk("mutexes taken: %u\n", mutex_total);
499 printk("semaphores taken: %u\n", sem_total);
500 printk("reads taken: %u\n", rd_total);
501 printk("writes taken: %u\n", wr_total);
502 printk("downgrades taken: %u\n", dg_total);
504 else {
505 char buf[30];
507 sprintf(buf, "%d/%d", interval, load);
509 printk("%3d %3d %3d %3d %3d %c %5s %9u %9u %9u %9u %9u\n",
510 nummx, numsm, numrd, numwr, numdg,
511 do_sched ? 's' : '-',
512 buf,
513 mutex_total,
514 sem_total,
515 rd_total,
516 wr_total,
517 dg_total);
520 /* tell insmod to discard the module */
521 if (verbose)
522 printk("Tests complete\n");
523 return -ENOANO;
525 } /* end do_tests() */
527 module_init(do_tests);