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