update test
[lttv.git] / trunk / tests / kernel / test-fair-rwlock.c
CommitLineData
f0a36bb1 1/* test-fair-rwlock.c
2 *
3 */
4
5#include <linux/module.h>
6#include <linux/proc_fs.h>
7#include <linux/sched.h>
8#include <linux/timex.h>
9#include <linux/fair-rwlock.h>
10#include <linux/kthread.h>
11#include <linux/delay.h>
12#include <linux/hardirq.h>
13#include <linux/module.h>
7f563886 14#include <linux/percpu.h>
f0a36bb1 15#include <asm/ptrace.h>
16
7f563886 17#if (NR_CPUS > 64 && (BITS_PER_LONG == 32 || NR_CPUS > 32768))
f0a36bb1 18#error "fair rwlock needs more bits per long to deal with that many CPUs"
19#endif
20
68f25f81 21/* Test with no contention duration, in seconds */
22#define SINGLE_WRITER_TEST_DURATION 10
23#define SINGLE_READER_TEST_DURATION 10
24#define MULTIPLE_READERS_TEST_DURATION 10
25
89889f86 26/* Test duration, in seconds */
f36c4112 27#define TEST_DURATION 60
89889f86 28
f0a36bb1 29#define THREAD_ROFFSET 1UL
30#define THREAD_RMASK ((NR_CPUS - 1) * THREAD_ROFFSET)
31#define SOFTIRQ_ROFFSET (THREAD_RMASK + 1)
32#define SOFTIRQ_RMASK ((NR_CPUS - 1) * SOFTIRQ_ROFFSET)
33#define HARDIRQ_ROFFSET ((SOFTIRQ_RMASK | THREAD_RMASK) + 1)
34#define HARDIRQ_RMASK ((NR_CPUS - 1) * HARDIRQ_ROFFSET)
35
7f563886 36#define SUBSCRIBERS_WOFFSET \
37 ((HARDIRQ_RMASK | SOFTIRQ_RMASK | THREAD_RMASK) + 1)
38#define SUBSCRIBERS_WMASK \
39 ((NR_CPUS - 1) * SUBSCRIBERS_WOFFSET)
40#define WRITER_MUTEX \
41 ((SUBSCRIBERS_WMASK | HARDIRQ_RMASK | SOFTIRQ_RMASK | THREAD_RMASK) + 1)
42#define SOFTIRQ_WMASK (WRITER_MUTEX << 1)
43#define SOFTIRQ_WOFFSET SOFTIRQ_WMASK
426d6b67 44#define HARDIRQ_WMASK (SOFTIRQ_WMASK << 1)
7f563886 45#define HARDIRQ_WOFFSET HARDIRQ_WMASK
f0a36bb1 46
47#define NR_VARS 100
1c21e42c 48#define NR_WRITERS 2
49#define NR_TRYLOCK_WRITERS 2
50#define NR_READERS 4
51#define NR_TRYLOCK_READERS 2
52#define NR_INTERRUPT_READERS 1
53#define NR_TRYLOCK_INTERRUPT_READERS 1
f0a36bb1 54
4d1751f9 55/*
56 * Writer iteration delay, in us. 0 for busy loop. Caution : writers can
57 * starve readers.
58 */
59#define WRITER_DELAY 10
89889f86 60
f0a36bb1 61static int var[NR_VARS];
62static struct task_struct *reader_threads[NR_READERS];
1c21e42c 63static struct task_struct *trylock_reader_threads[NR_TRYLOCK_READERS];
f0a36bb1 64static struct task_struct *writer_threads[NR_WRITERS];
1c21e42c 65static struct task_struct *trylock_writer_threads[NR_TRYLOCK_WRITERS];
f0a36bb1 66static struct task_struct *interrupt_reader;
1c21e42c 67static struct task_struct *trylock_interrupt_reader;
f0a36bb1 68
69static struct fair_rwlock frwlock = {
70 .value = ATOMIC_LONG_INIT(0),
f0a36bb1 71};
72
68f25f81 73static cycles_t cycles_calibration_min,
74 cycles_calibration_avg,
75 cycles_calibration_max;
76
77static inline cycles_t calibrate_cycles(cycles_t cycles)
78{
79 return cycles - cycles_calibration_avg;
80}
81
f0a36bb1 82struct proc_dir_entry *pentry = NULL;
83
84static int reader_thread(void *data)
85{
86 int i;
87 int prev, cur;
88 unsigned long iter = 0;
68f25f81 89 cycles_t time1, time2, delay, delaymax = 0, delaymin = ULLONG_MAX,
90 delayavg = 0;
f0a36bb1 91
92 printk("reader_thread/%lu runnning\n", (unsigned long)data);
93 do {
94 iter++;
7f563886 95 preempt_disable(); /* for get_cycles accuracy */
68f25f81 96 rdtsc_barrier();
7f563886 97 time1 = get_cycles();
68f25f81 98 rdtsc_barrier();
99
f0a36bb1 100 fair_read_lock(&frwlock);
68f25f81 101
102 rdtsc_barrier();
7f563886 103 time2 = get_cycles();
68f25f81 104 rdtsc_barrier();
105 delay = time2 - time1;
106 delaymax = max(delaymax, delay);
107 delaymin = min(delaymin, delay);
108 delayavg += delay;
f0a36bb1 109 prev = var[0];
110 for (i = 1; i < NR_VARS; i++) {
111 cur = var[i];
112 if (cur != prev)
113 printk(KERN_ALERT
114 "Unequal cur %d/prev %d at i %d, iter %lu "
115 "in thread\n", cur, prev, i, iter);
116 }
117 fair_read_unlock(&frwlock);
7f563886 118 preempt_enable(); /* for get_cycles accuracy */
f0a36bb1 119 //msleep(100);
120 } while (!kthread_should_stop());
68f25f81 121 delayavg /= iter;
7f563886 122 printk("reader_thread/%lu iterations : %lu, "
68f25f81 123 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
124 (unsigned long)data, iter,
125 calibrate_cycles(delaymin),
126 calibrate_cycles(delayavg),
127 calibrate_cycles(delaymax));
f0a36bb1 128 return 0;
129}
130
1c21e42c 131static int trylock_reader_thread(void *data)
132{
133 int i;
134 int prev, cur;
135 unsigned long iter = 0, success_iter = 0;
136
137 printk("trylock_reader_thread/%lu runnning\n", (unsigned long)data);
138 do {
139 while (!fair_read_trylock(&frwlock))
140 iter++;
141 success_iter++;
142 prev = var[0];
143 for (i = 1; i < NR_VARS; i++) {
144 cur = var[i];
145 if (cur != prev)
146 printk(KERN_ALERT
147 "Unequal cur %d/prev %d at i %d, iter %lu "
148 "in thread\n", cur, prev, i, iter);
149 }
150 fair_read_unlock(&frwlock);
151 //msleep(100);
152 } while (!kthread_should_stop());
153 printk("trylock_reader_thread/%lu iterations : %lu, "
154 "successful iterations : %lu\n",
155 (unsigned long)data, iter, success_iter);
156 return 0;
157}
158
68f25f81 159DEFINE_PER_CPU(cycles_t, int_delaymin);
160DEFINE_PER_CPU(cycles_t, int_delayavg);
7f563886 161DEFINE_PER_CPU(cycles_t, int_delaymax);
68f25f81 162DEFINE_PER_CPU(cycles_t, int_ipi_nr);
7f563886 163
f0a36bb1 164static void interrupt_reader_ipi(void *data)
165{
166 int i;
167 int prev, cur;
7f563886 168 cycles_t time1, time2;
68f25f81 169 cycles_t *delaymax, *delaymin, *delayavg, *ipi_nr, delay;
7f563886 170
171 /*
172 * Skip the ipi caller, not in irq context.
173 */
174 if (!in_irq())
175 return;
f0a36bb1 176
7f563886 177 delaymax = &per_cpu(int_delaymax, smp_processor_id());
68f25f81 178 delaymin = &per_cpu(int_delaymin, smp_processor_id());
179 delayavg = &per_cpu(int_delayavg, smp_processor_id());
180 ipi_nr = &per_cpu(int_ipi_nr, smp_processor_id());
181
182 rdtsc_barrier();
7f563886 183 time1 = get_cycles();
68f25f81 184 rdtsc_barrier();
185
f0a36bb1 186 fair_read_lock(&frwlock);
68f25f81 187
188 rdtsc_barrier();
7f563886 189 time2 = get_cycles();
68f25f81 190 rdtsc_barrier();
191 delay = time2 - time1;
192 *delaymax = max(*delaymax, delay);
193 *delaymin = min(*delaymin, delay);
194 *delayavg += delay;
195 (*ipi_nr)++;
f0a36bb1 196 prev = var[0];
197 for (i = 1; i < NR_VARS; i++) {
198 cur = var[i];
199 if (cur != prev)
200 printk(KERN_ALERT
201 "Unequal cur %d/prev %d at i %d in interrupt\n",
202 cur, prev, i);
203 }
204 fair_read_unlock(&frwlock);
205}
206
1c21e42c 207DEFINE_PER_CPU(unsigned long, trylock_int_iter);
208DEFINE_PER_CPU(unsigned long, trylock_int_success);
209
210static void trylock_interrupt_reader_ipi(void *data)
211{
212 int i;
213 int prev, cur;
214
215 /*
216 * Skip the ipi caller, not in irq context.
217 */
218 if (!in_irq())
219 return;
220
221 per_cpu(trylock_int_iter, smp_processor_id())++;
222 while (!fair_read_trylock(&frwlock))
223 per_cpu(trylock_int_iter, smp_processor_id())++;
224 per_cpu(trylock_int_success, smp_processor_id())++;
225 prev = var[0];
226 for (i = 1; i < NR_VARS; i++) {
227 cur = var[i];
228 if (cur != prev)
229 printk(KERN_ALERT
230 "Unequal cur %d/prev %d at i %d in interrupt\n",
231 cur, prev, i);
232 }
233 fair_read_unlock(&frwlock);
234}
235
236
f0a36bb1 237static int interrupt_reader_thread(void *data)
238{
239 unsigned long iter = 0;
7f563886 240 int i;
241
68f25f81 242 for_each_online_cpu(i) {
243 per_cpu(int_delaymax, i) = 0;
244 per_cpu(int_delaymin, i) = ULLONG_MAX;
245 per_cpu(int_delayavg, i) = 0;
246 per_cpu(int_ipi_nr, i) = 0;
247 }
f0a36bb1 248 do {
249 iter++;
250 on_each_cpu(interrupt_reader_ipi, NULL, 0);
251 msleep(100);
252 } while (!kthread_should_stop());
253 printk("interrupt_reader_thread/%lu iterations : %lu\n",
254 (unsigned long)data, iter);
7f563886 255 for_each_online_cpu(i) {
68f25f81 256 per_cpu(int_delayavg, i) /= per_cpu(int_ipi_nr, i);
7f563886 257 printk("interrupt readers on CPU %i, "
68f25f81 258 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
259 i,
260 calibrate_cycles(per_cpu(int_delaymin, i)),
261 calibrate_cycles(per_cpu(int_delayavg, i)),
262 calibrate_cycles(per_cpu(int_delaymax, i)));
7f563886 263 }
f0a36bb1 264 return 0;
265}
266
1c21e42c 267static int trylock_interrupt_reader_thread(void *data)
268{
269 unsigned long iter = 0;
270 int i;
271
272 do {
273 iter++;
274 on_each_cpu(trylock_interrupt_reader_ipi, NULL, 0);
275 msleep(100);
276 } while (!kthread_should_stop());
277 printk("trylock_interrupt_reader_thread/%lu iterations : %lu\n",
278 (unsigned long)data, iter);
279 for_each_online_cpu(i) {
280 printk("trylock interrupt readers on CPU %i, "
281 "iterations %lu, "
282 "successful iterations : %lu\n",
283 i, per_cpu(trylock_int_iter, i),
284 per_cpu(trylock_int_success, i));
68f25f81 285 per_cpu(trylock_int_iter, i) = 0;
286 per_cpu(trylock_int_success, i) = 0;
1c21e42c 287 }
288 return 0;
289}
290
f0a36bb1 291static int writer_thread(void *data)
292{
293 int i;
294 int new;
295 unsigned long iter = 0;
68f25f81 296 cycles_t time1, time2, delay, delaymax = 0, delaymin = ULLONG_MAX,
297 delayavg = 0;
f0a36bb1 298
299 printk("writer_thread/%lu runnning\n", (unsigned long)data);
300 do {
301 iter++;
7f563886 302 preempt_disable(); /* for get_cycles accuracy */
68f25f81 303 rdtsc_barrier();
7f563886 304 time1 = get_cycles();
68f25f81 305 rdtsc_barrier();
306
f0a36bb1 307 fair_write_lock_irq(&frwlock);
308 //fair_write_lock(&frwlock);
68f25f81 309
310 rdtsc_barrier();
7f563886 311 time2 = get_cycles();
68f25f81 312 rdtsc_barrier();
313 delay = time2 - time1;
314 delaymax = max(delaymax, delay);
315 delaymin = min(delaymin, delay);
316 delayavg += delay;
f0a36bb1 317 new = (int)get_cycles();
318 for (i = 0; i < NR_VARS; i++) {
319 var[i] = new;
320 }
321 //fair_write_unlock(&frwlock);
322 fair_write_unlock_irq(&frwlock);
7f563886 323 preempt_enable(); /* for get_cycles accuracy */
89889f86 324 if (WRITER_DELAY > 0)
4d1751f9 325 udelay(WRITER_DELAY);
f0a36bb1 326 } while (!kthread_should_stop());
68f25f81 327 delayavg /= iter;
7f563886 328 printk("writer_thread/%lu iterations : %lu, "
68f25f81 329 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
330 (unsigned long)data, iter,
331 calibrate_cycles(delaymin),
332 calibrate_cycles(delayavg),
333 calibrate_cycles(delaymax));
f0a36bb1 334 return 0;
335}
336
1c21e42c 337static int trylock_writer_thread(void *data)
338{
339 int i;
340 int new;
341 unsigned long iter = 0, success = 0;
342
343 printk("trylock_writer_thread/%lu runnning\n", (unsigned long)data);
344 do {
345 fair_write_subscribe(&frwlock);
346 while (!fair_write_trylock_subscribed_irq(&frwlock)) {
347 iter++;
348 continue;
349 }
350 success++;
351 //fair_write_lock(&frwlock);
352 new = (int)get_cycles();
353 for (i = 0; i < NR_VARS; i++) {
354 var[i] = new;
355 }
356 //fair_write_unlock(&frwlock);
357 fair_write_unlock_irq(&frwlock);
358 if (WRITER_DELAY > 0)
4d1751f9 359 udelay(WRITER_DELAY);
1c21e42c 360 } while (!kthread_should_stop());
361 printk("trylock_writer_thread/%lu iterations : %lu, "
362 "successful iterations : %lu\n",
363 (unsigned long)data, iter, success);
364 return 0;
365}
366
f0a36bb1 367static void fair_rwlock_create(void)
368{
369 unsigned long i;
370
371 for (i = 0; i < NR_READERS; i++) {
372 printk("starting reader thread %lu\n", i);
373 reader_threads[i] = kthread_run(reader_thread, (void *)i,
374 "frwlock_reader");
375 BUG_ON(!reader_threads[i]);
376 }
377
1c21e42c 378 for (i = 0; i < NR_TRYLOCK_READERS; i++) {
379 printk("starting trylock reader thread %lu\n", i);
380 trylock_reader_threads[i] = kthread_run(trylock_reader_thread,
381 (void *)i, "frwlock_trylock_reader");
382 BUG_ON(!trylock_reader_threads[i]);
383 }
384
385
f0a36bb1 386 printk("starting interrupt reader %lu\n", i);
387 interrupt_reader = kthread_run(interrupt_reader_thread, NULL,
388 "frwlock_interrupt_reader");
1c21e42c 389 printk("starting trylock interrupt reader %lu\n", i);
390 trylock_interrupt_reader = kthread_run(trylock_interrupt_reader_thread,
391 NULL, "frwlock_trylock_interrupt_reader");
f0a36bb1 392
393 for (i = 0; i < NR_WRITERS; i++) {
394 printk("starting writer thread %lu\n", i);
395 writer_threads[i] = kthread_run(writer_thread, (void *)i,
396 "frwlock_writer");
397 BUG_ON(!writer_threads[i]);
398 }
1c21e42c 399 for (i = 0; i < NR_TRYLOCK_WRITERS; i++) {
400 printk("starting trylock writer thread %lu\n", i);
401 trylock_writer_threads[i] = kthread_run(trylock_writer_thread,
402 (void *)i, "frwlock_trylock_writer");
403 BUG_ON(!trylock_writer_threads[i]);
404 }
f0a36bb1 405}
406
407static void fair_rwlock_stop(void)
408{
409 unsigned long i;
410
1c21e42c 411 for (i = 0; i < NR_WRITERS; i++)
7f563886 412 kthread_stop(writer_threads[i]);
1c21e42c 413 for (i = 0; i < NR_TRYLOCK_WRITERS; i++)
414 kthread_stop(trylock_writer_threads[i]);
415 for (i = 0; i < NR_READERS; i++)
f0a36bb1 416 kthread_stop(reader_threads[i]);
1c21e42c 417 for (i = 0; i < NR_TRYLOCK_READERS; i++)
418 kthread_stop(trylock_reader_threads[i]);
7f563886 419 kthread_stop(interrupt_reader);
1c21e42c 420 kthread_stop(trylock_interrupt_reader);
f0a36bb1 421}
422
423
424static void perform_test(const char *name, void (*callback)(void))
425{
426 printk("%s\n", name);
427 callback();
428}
429
430static int my_open(struct inode *inode, struct file *file)
431{
68f25f81 432 unsigned long i;
433 cycles_t time1, time2, delay;
434
435 printk("** get_cycles calibration **\n");
436 cycles_calibration_min = ULLONG_MAX;
437 cycles_calibration_avg = 0;
438 cycles_calibration_max = 0;
439
440 local_irq_disable();
441 for (i = 0; i < 10; i++) {
442 rdtsc_barrier();
443 time1 = get_cycles();
444 rdtsc_barrier();
445 rdtsc_barrier();
446 time2 = get_cycles();
447 rdtsc_barrier();
448 delay = time2 - time1;
449 cycles_calibration_min = min(cycles_calibration_min, delay);
450 cycles_calibration_avg += delay;
451 cycles_calibration_max = max(cycles_calibration_max, delay);
452 }
453 cycles_calibration_avg /= 10;
454 local_irq_enable();
455
456 printk("get_cycles takes [min,avg,max] %llu,%llu,%llu cycles, "
457 "results calibrated on avg\n",
458 cycles_calibration_min,
459 cycles_calibration_avg,
460 cycles_calibration_max);
461
462 printk("** Single writer test, no contention **\n");
463 writer_threads[0] = kthread_run(writer_thread, (void *)0,
464 "frwlock_writer");
465 BUG_ON(!writer_threads[0]);
466 ssleep(SINGLE_WRITER_TEST_DURATION);
467 kthread_stop(writer_threads[0]);
468
469 printk("** Single reader test, no contention **\n");
470 reader_threads[0] = kthread_run(reader_thread, (void *)0,
471 "frwlock_reader");
472 BUG_ON(!reader_threads[0]);
473 ssleep(SINGLE_READER_TEST_DURATION);
474 kthread_stop(reader_threads[0]);
475
476 printk("** Multiple readers test, no contention **\n");
477 for (i = 0; i < NR_READERS; i++) {
478 printk("starting reader thread %lu\n", i);
479 reader_threads[i] = kthread_run(reader_thread, (void *)i,
480 "frwlock_reader");
481 BUG_ON(!reader_threads[i]);
482 }
483 ssleep(SINGLE_READER_TEST_DURATION);
484 for (i = 0; i < NR_READERS; i++)
485 kthread_stop(reader_threads[i]);
486
487 printk("** High contention test **\n");
f0a36bb1 488 perform_test("fair-rwlock-create", fair_rwlock_create);
f36c4112 489 ssleep(TEST_DURATION);
f0a36bb1 490 perform_test("fair-rwlock-stop", fair_rwlock_stop);
491
492 return -EPERM;
493}
494
495
496static struct file_operations my_operations = {
497 .open = my_open,
498};
499
500int init_module(void)
501{
502 pentry = create_proc_entry("testfrwlock", 0444, NULL);
503 if (pentry)
504 pentry->proc_fops = &my_operations;
505
506 printk("NR_CPUS : %d\n", NR_CPUS);
507 printk("THREAD_ROFFSET : %lX\n", THREAD_ROFFSET);
508 printk("THREAD_RMASK : %lX\n", THREAD_RMASK);
f0a36bb1 509 printk("SOFTIRQ_ROFFSET : %lX\n", SOFTIRQ_ROFFSET);
510 printk("SOFTIRQ_RMASK : %lX\n", SOFTIRQ_RMASK);
f0a36bb1 511 printk("HARDIRQ_ROFFSET : %lX\n", HARDIRQ_ROFFSET);
512 printk("HARDIRQ_RMASK : %lX\n", HARDIRQ_RMASK);
7f563886 513 printk("SUBSCRIBERS_WOFFSET : %lX\n", SUBSCRIBERS_WOFFSET);
514 printk("SUBSCRIBERS_WMASK : %lX\n", SUBSCRIBERS_WMASK);
515 printk("WRITER_MUTEX : %lX\n", WRITER_MUTEX);
516 printk("SOFTIRQ_WMASK : %lX\n", SOFTIRQ_WMASK);
f0a36bb1 517 printk("HARDIRQ_WMASK : %lX\n", HARDIRQ_WMASK);
518
519 return 0;
520}
521
522void cleanup_module(void)
523{
524 remove_proc_entry("testfrwlock", NULL);
525}
526
527MODULE_LICENSE("GPL");
528MODULE_AUTHOR("Mathieu Desnoyers");
529MODULE_DESCRIPTION("Fair rwlock test");
This page took 0.045116 seconds and 4 git commands to generate.