convert from svn repository: remove tags directory
[lttv.git] / trunk / tests / kernel / test-wbias-rwlock.c
CommitLineData
0e0fdeb6 1/* test-wbias-rwlock.c
f0a36bb1 2 *
3 */
4
5#include <linux/module.h>
6#include <linux/proc_fs.h>
7#include <linux/sched.h>
8#include <linux/timex.h>
f0a36bb1 9#include <linux/kthread.h>
10#include <linux/delay.h>
11#include <linux/hardirq.h>
12#include <linux/module.h>
7f563886 13#include <linux/percpu.h>
cd7cf33d 14#include <linux/spinlock.h>
f0a36bb1 15#include <asm/ptrace.h>
992fbe0f 16#include <linux/wbias-rwlock.h>
f0a36bb1 17
68f25f81 18/* Test with no contention duration, in seconds */
19#define SINGLE_WRITER_TEST_DURATION 10
20#define SINGLE_READER_TEST_DURATION 10
21#define MULTIPLE_READERS_TEST_DURATION 10
22
89889f86 23/* Test duration, in seconds */
f36c4112 24#define TEST_DURATION 60
89889f86 25
f0a36bb1 26#define NR_VARS 100
1c21e42c 27#define NR_WRITERS 2
d4ddd2db 28#define NR_TRYLOCK_WRITERS 1
29#define NR_NPREADERS 2
30#define NR_TRYLOCK_READERS 1
cd7cf33d 31
32/*
33 * 1 : test standard rwlock
0e0fdeb6 34 * 0 : test wbiasrwlock
cd7cf33d 35 */
36#define TEST_STD_RWLOCK 0
4fd25765 37
38/*
39 * 1 : test with thread and interrupt readers.
40 * 0 : test only with thread readers.
41 */
42#define TEST_INTERRUPTS 1
43
44#if (TEST_INTERRUPTS)
1c21e42c 45#define NR_INTERRUPT_READERS 1
46#define NR_TRYLOCK_INTERRUPT_READERS 1
4fd25765 47#else
48#define NR_INTERRUPT_READERS 0
49#define NR_TRYLOCK_INTERRUPT_READERS 0
50#endif
f0a36bb1 51
992fbe0f 52/*
53 * 1 : test with thread preemption readers.
54 * 0 : test only with non-preemptable thread readers.
55 */
292f0110 56#define TEST_PREEMPT 1
992fbe0f 57
58#if (TEST_PREEMPT)
59#define NR_PREADERS 2
60#else
61#define NR_PREADERS 0
62#endif
63
64
4d1751f9 65/*
66 * Writer iteration delay, in us. 0 for busy loop. Caution : writers can
67 * starve readers.
68 */
cd7cf33d 69#define WRITER_DELAY 100
4fd25765 70#define TRYLOCK_WRITER_DELAY 1000
71
72/*
73 * Number of iterations after which a trylock writer fails.
74 * -1 for infinite loop.
75 */
76#define TRYLOCK_WRITERS_FAIL_ITER 100
77
78/* Thread and interrupt reader delay, in ms */
79#define THREAD_READER_DELAY 0 /* busy loop */
80#define INTERRUPT_READER_DELAY 100
89889f86 81
6ef60a84 82#ifdef CONFIG_PREEMPT
83#define yield_in_non_preempt()
84#else
85#define yield_in_non_preempt() yield()
86#endif
87
f0a36bb1 88static int var[NR_VARS];
1f5845d5 89static struct task_struct *preader_threads[NR_PREADERS];
90static struct task_struct *npreader_threads[NR_NPREADERS];
1c21e42c 91static struct task_struct *trylock_reader_threads[NR_TRYLOCK_READERS];
f0a36bb1 92static struct task_struct *writer_threads[NR_WRITERS];
1c21e42c 93static struct task_struct *trylock_writer_threads[NR_TRYLOCK_WRITERS];
4fd25765 94static struct task_struct *interrupt_reader[NR_INTERRUPT_READERS];
95static struct task_struct *trylock_interrupt_reader[NR_TRYLOCK_INTERRUPT_READERS];
f0a36bb1 96
cd7cf33d 97#if (TEST_STD_RWLOCK)
98
99static DEFINE_RWLOCK(std_rw_lock);
100
101#define wrap_read_lock() read_lock(&std_rw_lock)
102#define wrap_read_trylock() read_trylock(&std_rw_lock)
103#define wrap_read_unlock() read_unlock(&std_rw_lock)
104
1f5845d5 105#define wrap_read_lock_inatomic() read_lock(&std_rw_lock)
106#define wrap_read_trylock_inatomic() read_trylock(&std_rw_lock)
1f5845d5 107
cd7cf33d 108#define wrap_read_lock_irq() read_lock(&std_rw_lock)
109#define wrap_read_trylock_irq() read_trylock(&std_rw_lock)
cd7cf33d 110
111#if (TEST_INTERRUPTS)
112#define wrap_write_lock() write_lock_irq(&std_rw_lock)
113#define wrap_write_unlock() write_unlock_irq(&std_rw_lock)
114#else
115#define wrap_write_lock() write_lock(&std_rw_lock)
116#define wrap_write_unlock() write_unlock(&std_rw_lock)
117#endif
118
6ef60a84 119#define wrap_write_trylock() write_trylock(&std_rw_lock)
120
cd7cf33d 121#else
122
7e9c6d5a 123#if (TEST_INTERRUPTS)
0cb746e2 124#if (TEST_PREEMPT)
d4ddd2db 125#define WBIASRWLOCKWCTX WB_PRIO_P
126#define WBIASRWLOCKRCTX (WB_RIRQ | WB_RNPTHREAD | WB_RPTHREAD)
7e9c6d5a 127#else
d4ddd2db 128#define WBIASRWLOCKWCTX WB_PRIO_NP
129#define WBIASRWLOCKRCTX (WB_RIRQ | WB_RNPTHREAD)
0cb746e2 130#endif
131#else
7e9c6d5a 132#if (TEST_PREEMPT)
d4ddd2db 133#define WBIASRWLOCKWCTX WB_PRIO_P
134#define WBIASRWLOCKRCTX (WB_RNPTHREAD | WB_RPTHREAD)
7e9c6d5a 135#else
d4ddd2db 136#define WBIASRWLOCKWCTX WB_PRIO_NP
137#define WBIASRWLOCKRCTX (WB_RNPTHREAD)
7e9c6d5a 138#endif
139#endif
d4ddd2db 140
141static DEFINE_WBIAS_RWLOCK(wbiasrwlock, WBIASRWLOCKWCTX, WBIASRWLOCKRCTX);
142CHECK_WBIAS_RWLOCK_MAP(wbiasrwlock, WBIASRWLOCKWCTX, WBIASRWLOCKRCTX);
7e9c6d5a 143
f0a36bb1 144
0cb746e2 145#if (TEST_PREEMPT)
0e0fdeb6 146#define wrap_read_lock() wbias_read_lock(&wbiasrwlock)
147#define wrap_read_trylock() wbias_read_trylock(&wbiasrwlock)
0cb746e2 148#else
149#define wrap_read_lock() wbias_read_lock_inatomic(&wbiasrwlock)
150#define wrap_read_trylock() wbias_read_trylock_inatomic(&wbiasrwlock)
0cb746e2 151#endif
6ef60a84 152#define wrap_read_unlock() wbias_read_unlock(&wbiasrwlock)
cd7cf33d 153
1f5845d5 154#define wrap_read_lock_inatomic() wbias_read_lock_inatomic(&wbiasrwlock)
6ef60a84 155#define wrap_read_trylock_inatomic() \
1f5845d5 156 wbias_read_trylock_inatomic(&wbiasrwlock)
1f5845d5 157
0e0fdeb6 158#define wrap_read_lock_irq() wbias_read_lock_irq(&wbiasrwlock)
159#define wrap_read_trylock_irq() wbias_read_trylock_irq(&wbiasrwlock)
cd7cf33d 160
7e9c6d5a 161#define wrap_write_lock() \
d4ddd2db 162 wbias_write_lock(&wbiasrwlock, WBIASRWLOCKWCTX, WBIASRWLOCKRCTX)
7e9c6d5a 163#define wrap_write_unlock() \
d4ddd2db 164 wbias_write_unlock(&wbiasrwlock, WBIASRWLOCKWCTX, WBIASRWLOCKRCTX)
6ef60a84 165#define wrap_write_trylock() \
d4ddd2db 166 wbias_write_trylock(&wbiasrwlock, WBIASRWLOCKWCTX, WBIASRWLOCKRCTX)
cd7cf33d 167
168#endif
169
68f25f81 170static cycles_t cycles_calibration_min,
171 cycles_calibration_avg,
172 cycles_calibration_max;
173
174static inline cycles_t calibrate_cycles(cycles_t cycles)
175{
176 return cycles - cycles_calibration_avg;
177}
178
f0a36bb1 179struct proc_dir_entry *pentry = NULL;
180
b37c9208 181static int p_or_np_reader_thread(const char *typename,
182 void *data, int preemptable)
f0a36bb1 183{
184 int i;
185 int prev, cur;
186 unsigned long iter = 0;
5b23bc48 187 cycles_t time1, time2, delay;
188 cycles_t ldelaymax = 0, ldelaymin = ULLONG_MAX, ldelayavg = 0;
189 cycles_t udelaymax = 0, udelaymin = ULLONG_MAX, udelayavg = 0;
f0a36bb1 190
b37c9208 191 printk("%s/%lu runnning\n", typename, (unsigned long)data);
f0a36bb1 192 do {
193 iter++;
1f5845d5 194 if (!preemptable)
195 preempt_disable();
68f25f81 196 rdtsc_barrier();
7f563886 197 time1 = get_cycles();
68f25f81 198 rdtsc_barrier();
199
1f5845d5 200 if (!preemptable)
201 wrap_read_lock_inatomic();
202 else
203 wrap_read_lock();
68f25f81 204
205 rdtsc_barrier();
7f563886 206 time2 = get_cycles();
68f25f81 207 rdtsc_barrier();
208 delay = time2 - time1;
5b23bc48 209 ldelaymax = max(ldelaymax, delay);
210 ldelaymin = min(ldelaymin, delay);
211 ldelayavg += delay;
f0a36bb1 212 prev = var[0];
213 for (i = 1; i < NR_VARS; i++) {
214 cur = var[i];
6ef60a84 215 if (cur != prev) {
f0a36bb1 216 printk(KERN_ALERT
217 "Unequal cur %d/prev %d at i %d, iter %lu "
6ef60a84 218 "in reader thread\n",
219 cur, prev, i, iter);
220 }
f0a36bb1 221 }
cd7cf33d 222
5b23bc48 223 rdtsc_barrier();
224 time1 = get_cycles();
225 rdtsc_barrier();
226
6ef60a84 227 wrap_read_unlock();
228
5b23bc48 229 rdtsc_barrier();
230 time2 = get_cycles();
231 rdtsc_barrier();
232 delay = time2 - time1;
233 udelaymax = max(udelaymax, delay);
234 udelaymin = min(udelaymin, delay);
235 udelayavg += delay;
236
1f5845d5 237 if (!preemptable)
238 preempt_enable();
5b23bc48 239
4fd25765 240 if (THREAD_READER_DELAY)
241 msleep(THREAD_READER_DELAY);
6ef60a84 242 yield_in_non_preempt();
f0a36bb1 243 } while (!kthread_should_stop());
4fd25765 244 if (!iter) {
b37c9208 245 printk("%s/%lu iterations : %lu", typename,
4fd25765 246 (unsigned long)data, iter);
247 } else {
5b23bc48 248 ldelayavg /= iter;
249 udelayavg /= iter;
b37c9208 250 printk("%s/%lu iterations : %lu, "
4fd25765 251 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
b37c9208 252 typename,
4fd25765 253 (unsigned long)data, iter,
5b23bc48 254 calibrate_cycles(ldelaymin),
255 calibrate_cycles(ldelayavg),
256 calibrate_cycles(ldelaymax));
257 printk("%s/%lu iterations : %lu, "
258 "unlock delay [min,avg,max] %llu,%llu,%llu cycles\n",
259 typename,
260 (unsigned long)data, iter,
261 calibrate_cycles(udelaymin),
262 calibrate_cycles(udelayavg),
263 calibrate_cycles(udelaymax));
4fd25765 264 }
f0a36bb1 265 return 0;
266}
267
1f5845d5 268static int preader_thread(void *data)
269{
b37c9208 270 return p_or_np_reader_thread("preader_thread", data, 1);
1f5845d5 271}
272
273static int npreader_thread(void *data)
274{
b37c9208 275 return p_or_np_reader_thread("npreader_thread", data, 0);
1f5845d5 276}
277
1c21e42c 278static int trylock_reader_thread(void *data)
279{
280 int i;
281 int prev, cur;
282 unsigned long iter = 0, success_iter = 0;
283
284 printk("trylock_reader_thread/%lu runnning\n", (unsigned long)data);
285 do {
0cb746e2 286#if (!TEST_PREEMPT)
287 preempt_disable();
288#endif
6ef60a84 289 while (!wrap_read_trylock()) {
290 cpu_relax();
1c21e42c 291 iter++;
6ef60a84 292 }
1c21e42c 293 success_iter++;
294 prev = var[0];
295 for (i = 1; i < NR_VARS; i++) {
296 cur = var[i];
6ef60a84 297 if (cur != prev) {
1c21e42c 298 printk(KERN_ALERT
299 "Unequal cur %d/prev %d at i %d, iter %lu "
6ef60a84 300 "in trylock reader thread\n",
301 cur, prev, i, iter);
302 }
1c21e42c 303 }
cd7cf33d 304 wrap_read_unlock();
0cb746e2 305#if (!TEST_PREEMPT)
306 preempt_enable();
307#endif
4fd25765 308 if (THREAD_READER_DELAY)
309 msleep(THREAD_READER_DELAY);
6ef60a84 310 yield_in_non_preempt();
1c21e42c 311 } while (!kthread_should_stop());
312 printk("trylock_reader_thread/%lu iterations : %lu, "
313 "successful iterations : %lu\n",
d4ddd2db 314 (unsigned long)data, iter + success_iter, success_iter);
1c21e42c 315 return 0;
316}
317
5b23bc48 318DEFINE_PER_CPU(cycles_t, int_ldelaymin);
319DEFINE_PER_CPU(cycles_t, int_ldelayavg);
320DEFINE_PER_CPU(cycles_t, int_ldelaymax);
321DEFINE_PER_CPU(cycles_t, int_udelaymin);
322DEFINE_PER_CPU(cycles_t, int_udelayavg);
323DEFINE_PER_CPU(cycles_t, int_udelaymax);
68f25f81 324DEFINE_PER_CPU(cycles_t, int_ipi_nr);
7f563886 325
f0a36bb1 326static void interrupt_reader_ipi(void *data)
327{
328 int i;
329 int prev, cur;
7f563886 330 cycles_t time1, time2;
5b23bc48 331 cycles_t *ldelaymax, *ldelaymin, *ldelayavg, *ipi_nr, delay;
332 cycles_t *udelaymax, *udelaymin, *udelayavg;
7f563886 333
334 /*
335 * Skip the ipi caller, not in irq context.
336 */
337 if (!in_irq())
338 return;
f0a36bb1 339
5b23bc48 340 ldelaymax = &per_cpu(int_ldelaymax, smp_processor_id());
341 ldelaymin = &per_cpu(int_ldelaymin, smp_processor_id());
342 ldelayavg = &per_cpu(int_ldelayavg, smp_processor_id());
343 udelaymax = &per_cpu(int_udelaymax, smp_processor_id());
344 udelaymin = &per_cpu(int_udelaymin, smp_processor_id());
345 udelayavg = &per_cpu(int_udelayavg, smp_processor_id());
68f25f81 346 ipi_nr = &per_cpu(int_ipi_nr, smp_processor_id());
347
348 rdtsc_barrier();
7f563886 349 time1 = get_cycles();
68f25f81 350 rdtsc_barrier();
351
cd7cf33d 352 wrap_read_lock_irq();
68f25f81 353
354 rdtsc_barrier();
7f563886 355 time2 = get_cycles();
68f25f81 356 rdtsc_barrier();
357 delay = time2 - time1;
5b23bc48 358 *ldelaymax = max(*ldelaymax, delay);
359 *ldelaymin = min(*ldelaymin, delay);
360 *ldelayavg += delay;
68f25f81 361 (*ipi_nr)++;
f0a36bb1 362 prev = var[0];
363 for (i = 1; i < NR_VARS; i++) {
364 cur = var[i];
365 if (cur != prev)
366 printk(KERN_ALERT
367 "Unequal cur %d/prev %d at i %d in interrupt\n",
368 cur, prev, i);
369 }
5b23bc48 370 rdtsc_barrier();
371 time1 = get_cycles();
372 rdtsc_barrier();
6ef60a84 373 wrap_read_unlock();
5b23bc48 374 time2 = get_cycles();
375 rdtsc_barrier();
376 delay = time2 - time1;
377 *udelaymax = max(*udelaymax, delay);
378 *udelaymin = min(*udelaymin, delay);
379 *udelayavg += delay;
f0a36bb1 380}
381
1c21e42c 382DEFINE_PER_CPU(unsigned long, trylock_int_iter);
383DEFINE_PER_CPU(unsigned long, trylock_int_success);
384
385static void trylock_interrupt_reader_ipi(void *data)
386{
387 int i;
388 int prev, cur;
389
390 /*
391 * Skip the ipi caller, not in irq context.
392 */
393 if (!in_irq())
394 return;
395
396 per_cpu(trylock_int_iter, smp_processor_id())++;
cd7cf33d 397 while (!wrap_read_trylock_irq())
1c21e42c 398 per_cpu(trylock_int_iter, smp_processor_id())++;
399 per_cpu(trylock_int_success, smp_processor_id())++;
400 prev = var[0];
401 for (i = 1; i < NR_VARS; i++) {
402 cur = var[i];
403 if (cur != prev)
404 printk(KERN_ALERT
405 "Unequal cur %d/prev %d at i %d in interrupt\n",
406 cur, prev, i);
407 }
6ef60a84 408 wrap_read_unlock();
1c21e42c 409}
410
411
f0a36bb1 412static int interrupt_reader_thread(void *data)
413{
414 unsigned long iter = 0;
7f563886 415 int i;
416
68f25f81 417 for_each_online_cpu(i) {
5b23bc48 418 per_cpu(int_ldelaymax, i) = 0;
419 per_cpu(int_ldelaymin, i) = ULLONG_MAX;
420 per_cpu(int_ldelayavg, i) = 0;
421 per_cpu(int_udelaymax, i) = 0;
422 per_cpu(int_udelaymin, i) = ULLONG_MAX;
423 per_cpu(int_udelayavg, i) = 0;
68f25f81 424 per_cpu(int_ipi_nr, i) = 0;
425 }
f0a36bb1 426 do {
427 iter++;
428 on_each_cpu(interrupt_reader_ipi, NULL, 0);
4fd25765 429 if (INTERRUPT_READER_DELAY)
430 msleep(INTERRUPT_READER_DELAY);
6ef60a84 431 yield_in_non_preempt();
f0a36bb1 432 } while (!kthread_should_stop());
433 printk("interrupt_reader_thread/%lu iterations : %lu\n",
434 (unsigned long)data, iter);
7f563886 435 for_each_online_cpu(i) {
4fd25765 436 if (!per_cpu(int_ipi_nr, i))
437 continue;
8314e111 438 per_cpu(int_ldelayavg, i) /= per_cpu(int_ipi_nr, i);
439 per_cpu(int_udelayavg, i) /= per_cpu(int_ipi_nr, i);
7f563886 440 printk("interrupt readers on CPU %i, "
68f25f81 441 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
442 i,
5b23bc48 443 calibrate_cycles(per_cpu(int_ldelaymin, i)),
444 calibrate_cycles(per_cpu(int_ldelayavg, i)),
445 calibrate_cycles(per_cpu(int_ldelaymax, i)));
446 printk("interrupt readers on CPU %i, "
447 "unlock delay [min,avg,max] %llu,%llu,%llu cycles\n",
448 i,
449 calibrate_cycles(per_cpu(int_udelaymin, i)),
450 calibrate_cycles(per_cpu(int_udelayavg, i)),
451 calibrate_cycles(per_cpu(int_udelaymax, i)));
7f563886 452 }
f0a36bb1 453 return 0;
454}
455
1c21e42c 456static int trylock_interrupt_reader_thread(void *data)
457{
458 unsigned long iter = 0;
459 int i;
460
461 do {
462 iter++;
463 on_each_cpu(trylock_interrupt_reader_ipi, NULL, 0);
4fd25765 464 if (INTERRUPT_READER_DELAY)
465 msleep(INTERRUPT_READER_DELAY);
6ef60a84 466 yield_in_non_preempt();
1c21e42c 467 } while (!kthread_should_stop());
468 printk("trylock_interrupt_reader_thread/%lu iterations : %lu\n",
469 (unsigned long)data, iter);
470 for_each_online_cpu(i) {
471 printk("trylock interrupt readers on CPU %i, "
472 "iterations %lu, "
473 "successful iterations : %lu\n",
474 i, per_cpu(trylock_int_iter, i),
475 per_cpu(trylock_int_success, i));
68f25f81 476 per_cpu(trylock_int_iter, i) = 0;
477 per_cpu(trylock_int_success, i) = 0;
1c21e42c 478 }
479 return 0;
480}
481
f0a36bb1 482static int writer_thread(void *data)
483{
484 int i;
6ef60a84 485 int new, prev, cur;
f0a36bb1 486 unsigned long iter = 0;
5b23bc48 487 cycles_t time1, time2, delay;
488 cycles_t ldelaymax = 0, ldelaymin = ULLONG_MAX, ldelayavg = 0;
489 cycles_t udelaymax = 0, udelaymin = ULLONG_MAX, udelayavg = 0;
f0a36bb1 490
491 printk("writer_thread/%lu runnning\n", (unsigned long)data);
492 do {
493 iter++;
0cb746e2 494#if (!TEST_PREEMPT)
495 preempt_disable();
496#endif
68f25f81 497 rdtsc_barrier();
7f563886 498 time1 = get_cycles();
68f25f81 499 rdtsc_barrier();
500
cd7cf33d 501 wrap_write_lock();
68f25f81 502
503 rdtsc_barrier();
7f563886 504 time2 = get_cycles();
68f25f81 505 rdtsc_barrier();
506 delay = time2 - time1;
5b23bc48 507 ldelaymax = max(ldelaymax, delay);
508 ldelaymin = min(ldelaymin, delay);
509 ldelayavg += delay;
6ef60a84 510 /*
511 * Read the previous values, check that they are coherent.
512 */
513 prev = var[0];
514 for (i = 1; i < NR_VARS; i++) {
515 cur = var[i];
516 if (cur != prev)
517 printk(KERN_ALERT
518 "Unequal cur %d/prev %d at i %d, iter %lu "
519 "in writer thread\n",
520 cur, prev, i, iter);
521 }
f0a36bb1 522 new = (int)get_cycles();
523 for (i = 0; i < NR_VARS; i++) {
524 var[i] = new;
525 }
cd7cf33d 526
5b23bc48 527 rdtsc_barrier();
528 time1 = get_cycles();
529 rdtsc_barrier();
530
cd7cf33d 531 wrap_write_unlock();
532
5b23bc48 533 rdtsc_barrier();
534 time2 = get_cycles();
535 rdtsc_barrier();
536 delay = time2 - time1;
537 udelaymax = max(udelaymax, delay);
538 udelaymin = min(udelaymin, delay);
539 udelayavg += delay;
540
0cb746e2 541#if (!TEST_PREEMPT)
542 preempt_enable();
543#endif
89889f86 544 if (WRITER_DELAY > 0)
4d1751f9 545 udelay(WRITER_DELAY);
0cb746e2 546 cpu_relax(); /*
547 * make sure we don't busy-loop faster than
548 * the lock busy-loop, it would cause reader and
549 * writer starvation.
550 */
6ef60a84 551 yield_in_non_preempt();
f0a36bb1 552 } while (!kthread_should_stop());
5b23bc48 553 ldelayavg /= iter;
554 udelayavg /= iter;
7f563886 555 printk("writer_thread/%lu iterations : %lu, "
68f25f81 556 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
557 (unsigned long)data, iter,
8314e111 558 calibrate_cycles(ldelaymin),
559 calibrate_cycles(ldelayavg),
560 calibrate_cycles(ldelaymax));
5b23bc48 561 printk("writer_thread/%lu iterations : %lu, "
562 "unlock delay [min,avg,max] %llu,%llu,%llu cycles\n",
563 (unsigned long)data, iter,
564 calibrate_cycles(udelaymin),
565 calibrate_cycles(udelayavg),
566 calibrate_cycles(udelaymax));
f0a36bb1 567 return 0;
568}
569
cd7cf33d 570static int trylock_writer_thread(void *data)
571{
572 int i;
573 int new;
574 unsigned long iter = 0, success = 0, fail = 0;
575
576 printk("trylock_writer_thread/%lu runnning\n", (unsigned long)data);
577 do {
6ef60a84 578#if ((!TEST_PREEMPT) && (!TEST_STD_RWLOCK))
579 preempt_disable();
580#endif
581
582#if (TEST_STD_RWLOCK && TEST_INTERRUPTS)
cd7cf33d 583 /* std write trylock cannot disable interrupts. */
584 local_irq_disable();
585#endif
586
587#if (TRYLOCK_WRITERS_FAIL_ITER == -1)
588 for (;;) {
589 iter++;
6ef60a84 590 if (wrap_write_trylock())
cd7cf33d 591 goto locked;
6ef60a84 592 cpu_relax();
cd7cf33d 593 }
594#else
595 for (i = 0; i < TRYLOCK_WRITERS_FAIL_ITER; i++) {
596 iter++;
6ef60a84 597 if (wrap_write_trylock())
cd7cf33d 598 goto locked;
6ef60a84 599 cpu_relax();
cd7cf33d 600 }
601#endif
602 fail++;
cd7cf33d 603
6ef60a84 604#if (TEST_STD_RWLOCK && TEST_INTERRUPTS)
605 local_irq_enable();
0cb746e2 606#endif
cd7cf33d 607
6ef60a84 608#if ((!TEST_PREEMPT) && (!TEST_STD_RWLOCK))
609 preempt_enable();
4fd25765 610#endif
4fd25765 611 goto loop;
612locked:
1c21e42c 613 success++;
1c21e42c 614 new = (int)get_cycles();
615 for (i = 0; i < NR_VARS; i++) {
616 var[i] = new;
617 }
992fbe0f 618 wrap_write_unlock();
6ef60a84 619#if ((!TEST_PREEMPT) && (!TEST_STD_RWLOCK))
0cb746e2 620 preempt_enable();
621#endif
6ef60a84 622loop:
4fd25765 623 if (TRYLOCK_WRITER_DELAY > 0)
624 udelay(TRYLOCK_WRITER_DELAY);
0cb746e2 625 cpu_relax(); /*
626 * make sure we don't busy-loop faster than
627 * the lock busy-loop, it would cause reader and
628 * writer starvation.
629 */
6ef60a84 630 yield_in_non_preempt();
1c21e42c 631 } while (!kthread_should_stop());
4fd25765 632 printk("trylock_writer_thread/%lu iterations : "
633 "[try,success,fail after %d try], "
634 "%lu,%lu,%lu\n",
635 (unsigned long)data, TRYLOCK_WRITERS_FAIL_ITER,
636 iter, success, fail);
1c21e42c 637 return 0;
638}
639
0e0fdeb6 640static void wbias_rwlock_create(void)
f0a36bb1 641{
642 unsigned long i;
643
1f5845d5 644 for (i = 0; i < NR_PREADERS; i++) {
645 printk("starting preemptable reader thread %lu\n", i);
646 preader_threads[i] = kthread_run(preader_thread, (void *)i,
647 "wbiasrwlock_preader");
648 BUG_ON(!preader_threads[i]);
649 }
650
651 for (i = 0; i < NR_NPREADERS; i++) {
652 printk("starting non-preemptable reader thread %lu\n", i);
653 npreader_threads[i] = kthread_run(npreader_thread, (void *)i,
654 "wbiasrwlock_npreader");
655 BUG_ON(!npreader_threads[i]);
f0a36bb1 656 }
657
1c21e42c 658 for (i = 0; i < NR_TRYLOCK_READERS; i++) {
659 printk("starting trylock reader thread %lu\n", i);
660 trylock_reader_threads[i] = kthread_run(trylock_reader_thread,
0e0fdeb6 661 (void *)i, "wbiasrwlock_trylock_reader");
1c21e42c 662 BUG_ON(!trylock_reader_threads[i]);
663 }
4fd25765 664 for (i = 0; i < NR_INTERRUPT_READERS; i++) {
665 printk("starting interrupt reader %lu\n", i);
666 interrupt_reader[i] = kthread_run(interrupt_reader_thread,
667 (void *)i,
0e0fdeb6 668 "wbiasrwlock_interrupt_reader");
4fd25765 669 }
670 for (i = 0; i < NR_TRYLOCK_INTERRUPT_READERS; i++) {
671 printk("starting trylock interrupt reader %lu\n", i);
672 trylock_interrupt_reader[i] =
673 kthread_run(trylock_interrupt_reader_thread,
0e0fdeb6 674 (void *)i, "wbiasrwlock_trylock_interrupt_reader");
4fd25765 675 }
f0a36bb1 676 for (i = 0; i < NR_WRITERS; i++) {
677 printk("starting writer thread %lu\n", i);
678 writer_threads[i] = kthread_run(writer_thread, (void *)i,
0e0fdeb6 679 "wbiasrwlock_writer");
f0a36bb1 680 BUG_ON(!writer_threads[i]);
681 }
1c21e42c 682 for (i = 0; i < NR_TRYLOCK_WRITERS; i++) {
683 printk("starting trylock writer thread %lu\n", i);
684 trylock_writer_threads[i] = kthread_run(trylock_writer_thread,
0e0fdeb6 685 (void *)i, "wbiasrwlock_trylock_writer");
1c21e42c 686 BUG_ON(!trylock_writer_threads[i]);
687 }
f0a36bb1 688}
689
0e0fdeb6 690static void wbias_rwlock_stop(void)
f0a36bb1 691{
692 unsigned long i;
693
1c21e42c 694 for (i = 0; i < NR_WRITERS; i++)
7f563886 695 kthread_stop(writer_threads[i]);
1c21e42c 696 for (i = 0; i < NR_TRYLOCK_WRITERS; i++)
697 kthread_stop(trylock_writer_threads[i]);
1f5845d5 698 for (i = 0; i < NR_NPREADERS; i++)
699 kthread_stop(npreader_threads[i]);
700 for (i = 0; i < NR_PREADERS; i++)
701 kthread_stop(preader_threads[i]);
1c21e42c 702 for (i = 0; i < NR_TRYLOCK_READERS; i++)
703 kthread_stop(trylock_reader_threads[i]);
4fd25765 704 for (i = 0; i < NR_INTERRUPT_READERS; i++)
705 kthread_stop(interrupt_reader[i]);
706 for (i = 0; i < NR_TRYLOCK_INTERRUPT_READERS; i++)
707 kthread_stop(trylock_interrupt_reader[i]);
f0a36bb1 708}
709
710
711static void perform_test(const char *name, void (*callback)(void))
712{
713 printk("%s\n", name);
714 callback();
715}
716
717static int my_open(struct inode *inode, struct file *file)
718{
68f25f81 719 unsigned long i;
720 cycles_t time1, time2, delay;
721
722 printk("** get_cycles calibration **\n");
723 cycles_calibration_min = ULLONG_MAX;
724 cycles_calibration_avg = 0;
725 cycles_calibration_max = 0;
726
727 local_irq_disable();
728 for (i = 0; i < 10; i++) {
729 rdtsc_barrier();
730 time1 = get_cycles();
731 rdtsc_barrier();
732 rdtsc_barrier();
733 time2 = get_cycles();
734 rdtsc_barrier();
735 delay = time2 - time1;
736 cycles_calibration_min = min(cycles_calibration_min, delay);
737 cycles_calibration_avg += delay;
738 cycles_calibration_max = max(cycles_calibration_max, delay);
739 }
740 cycles_calibration_avg /= 10;
741 local_irq_enable();
742
743 printk("get_cycles takes [min,avg,max] %llu,%llu,%llu cycles, "
744 "results calibrated on avg\n",
745 cycles_calibration_min,
746 cycles_calibration_avg,
747 cycles_calibration_max);
193771da 748 printk("\n");
68f25f81 749
6ef60a84 750#if (NR_WRITERS)
68f25f81 751 printk("** Single writer test, no contention **\n");
dac86829 752 wbias_rwlock_profile_latency_reset();
68f25f81 753 writer_threads[0] = kthread_run(writer_thread, (void *)0,
0e0fdeb6 754 "wbiasrwlock_writer");
68f25f81 755 BUG_ON(!writer_threads[0]);
756 ssleep(SINGLE_WRITER_TEST_DURATION);
757 kthread_stop(writer_threads[0]);
193771da 758 printk("\n");
68f25f81 759
dac86829 760 wbias_rwlock_profile_latency_print();
6ef60a84 761#endif
dac86829 762
6ef60a84 763#if (NR_TRYLOCK_WRITERS)
4fd25765 764 printk("** Single trylock writer test, no contention **\n");
dac86829 765 wbias_rwlock_profile_latency_reset();
4fd25765 766 trylock_writer_threads[0] = kthread_run(trylock_writer_thread,
767 (void *)0,
0e0fdeb6 768 "trylock_wbiasrwlock_writer");
4fd25765 769 BUG_ON(!trylock_writer_threads[0]);
770 ssleep(SINGLE_WRITER_TEST_DURATION);
771 kthread_stop(trylock_writer_threads[0]);
193771da 772 printk("\n");
4fd25765 773
dac86829 774 wbias_rwlock_profile_latency_print();
6ef60a84 775#endif
dac86829 776
6ef60a84 777#if (TEST_PREEMPT)
1f5845d5 778 printk("** Single preemptable reader test, no contention **\n");
779 wbias_rwlock_profile_latency_reset();
780 preader_threads[0] = kthread_run(preader_thread, (void *)0,
781 "wbiasrwlock_preader");
782 BUG_ON(!preader_threads[0]);
783 ssleep(SINGLE_READER_TEST_DURATION);
784 kthread_stop(preader_threads[0]);
785 printk("\n");
786
787 wbias_rwlock_profile_latency_print();
6ef60a84 788#endif
1f5845d5 789
790 printk("** Single non-preemptable reader test, no contention **\n");
dac86829 791 wbias_rwlock_profile_latency_reset();
1f5845d5 792 npreader_threads[0] = kthread_run(npreader_thread, (void *)0,
793 "wbiasrwlock_npreader");
794 BUG_ON(!npreader_threads[0]);
68f25f81 795 ssleep(SINGLE_READER_TEST_DURATION);
1f5845d5 796 kthread_stop(npreader_threads[0]);
193771da 797 printk("\n");
68f25f81 798
dac86829 799 wbias_rwlock_profile_latency_print();
800
1f5845d5 801 printk("** Multiple p/non-p readers test, no contention **\n");
dac86829 802 wbias_rwlock_profile_latency_reset();
0cb746e2 803#if (TEST_PREEMPT)
1f5845d5 804 for (i = 0; i < NR_PREADERS; i++) {
805 printk("starting preader thread %lu\n", i);
806 preader_threads[i] = kthread_run(preader_thread, (void *)i,
807 "wbiasrwlock_preader");
808 BUG_ON(!preader_threads[i]);
809 }
0cb746e2 810#endif
1f5845d5 811 for (i = 0; i < NR_NPREADERS; i++) {
812 printk("starting npreader thread %lu\n", i);
813 npreader_threads[i] = kthread_run(npreader_thread, (void *)i,
814 "wbiasrwlock_npreader");
815 BUG_ON(!npreader_threads[i]);
68f25f81 816 }
817 ssleep(SINGLE_READER_TEST_DURATION);
1f5845d5 818 for (i = 0; i < NR_NPREADERS; i++)
819 kthread_stop(npreader_threads[i]);
0cb746e2 820#if (TEST_PREEMPT)
1f5845d5 821 for (i = 0; i < NR_PREADERS; i++)
822 kthread_stop(preader_threads[i]);
0cb746e2 823#endif
193771da 824 printk("\n");
68f25f81 825
dac86829 826 wbias_rwlock_profile_latency_print();
827
68f25f81 828 printk("** High contention test **\n");
dac86829 829 wbias_rwlock_profile_latency_reset();
0e0fdeb6 830 perform_test("wbias-rwlock-create", wbias_rwlock_create);
f36c4112 831 ssleep(TEST_DURATION);
0e0fdeb6 832 perform_test("wbias-rwlock-stop", wbias_rwlock_stop);
193771da 833 printk("\n");
dac86829 834 wbias_rwlock_profile_latency_print();
f0a36bb1 835
836 return -EPERM;
837}
838
839
840static struct file_operations my_operations = {
841 .open = my_open,
842};
843
844int init_module(void)
845{
0e0fdeb6 846 pentry = create_proc_entry("testwbiasrwlock", 0444, NULL);
f0a36bb1 847 if (pentry)
848 pentry->proc_fops = &my_operations;
849
6ef60a84 850 printk("UC_READER_MASK : %08X\n", UC_READER_MASK);
851 printk("UC_HARDIRQ_R_MASK: %08X\n", UC_HARDIRQ_READER_MASK);
852 printk("UC_SOFTIRQ_R_MASK: %08X\n", UC_SOFTIRQ_READER_MASK);
853 printk("UC_NPTHREA_R_MASK: %08X\n", UC_NPTHREAD_READER_MASK);
854 printk("UC_PTHREAD_R_MASK: %08X\n", UC_PTHREAD_READER_MASK);
855 printk("UC_WRITER : %08X\n", UC_WRITER);
856 printk("UC_SLOW_WRITER : %08X\n", UC_SLOW_WRITER);
857 printk("UC_WQ_ACTIVE : %08X\n", UC_WQ_ACTIVE);
858 printk("WS_MASK : %08X\n", WS_MASK);
859 printk("WS_WQ_MUTEX : %08X\n", WS_WQ_MUTEX);
860 printk("WS_COUNT_MUTEX : %08X\n", WS_COUNT_MUTEX);
861 printk("WS_LOCK_MUTEX : %08X\n", WS_LOCK_MUTEX);
862 printk("CTX_RMASK : %016lX\n", CTX_RMASK);
863 printk("CTX_WMASK : %016lX\n", CTX_WMASK);
f0a36bb1 864
865 return 0;
866}
867
868void cleanup_module(void)
869{
0e0fdeb6 870 remove_proc_entry("testwbiasrwlock", NULL);
f0a36bb1 871}
872
873MODULE_LICENSE("GPL");
874MODULE_AUTHOR("Mathieu Desnoyers");
0e0fdeb6 875MODULE_DESCRIPTION("wbias rwlock test");
This page took 0.070172 seconds and 4 git commands to generate.