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>
14 #include <linux/percpu.h>
15 #include <asm/ptrace.h>
17 #if (NR_CPUS > 64 && (BITS_PER_LONG == 32 || NR_CPUS > 32768))
18 #error "fair rwlock needs more bits per long to deal with that many CPUs"
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
26 /* Test duration, in seconds */
27 #define TEST_DURATION 60
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)
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
44 #define HARDIRQ_WMASK (SOFTIRQ_WMASK << 1)
45 #define HARDIRQ_WOFFSET HARDIRQ_WMASK
49 #define NR_TRYLOCK_WRITERS 2
51 #define NR_TRYLOCK_READERS 2
52 #define NR_INTERRUPT_READERS 1
53 #define NR_TRYLOCK_INTERRUPT_READERS 1
56 * Writer iteration delay, in us. 0 for busy loop. Caution : writers can
59 #define WRITER_DELAY 10
61 static int var
[NR_VARS
];
62 static struct task_struct
*reader_threads
[NR_READERS
];
63 static struct task_struct
*trylock_reader_threads
[NR_TRYLOCK_READERS
];
64 static struct task_struct
*writer_threads
[NR_WRITERS
];
65 static struct task_struct
*trylock_writer_threads
[NR_TRYLOCK_WRITERS
];
66 static struct task_struct
*interrupt_reader
;
67 static struct task_struct
*trylock_interrupt_reader
;
69 static struct fair_rwlock frwlock
= {
70 .value
= ATOMIC_LONG_INIT(0),
73 static cycles_t cycles_calibration_min
,
74 cycles_calibration_avg
,
75 cycles_calibration_max
;
77 static inline cycles_t
calibrate_cycles(cycles_t cycles
)
79 return cycles
- cycles_calibration_avg
;
82 struct proc_dir_entry
*pentry
= NULL
;
84 static int reader_thread(void *data
)
88 unsigned long iter
= 0;
89 cycles_t time1
, time2
, delay
, delaymax
= 0, delaymin
= ULLONG_MAX
,
92 printk("reader_thread/%lu runnning\n", (unsigned long)data
);
95 preempt_disable(); /* for get_cycles accuracy */
100 fair_read_lock(&frwlock
);
103 time2
= get_cycles();
105 delay
= time2
- time1
;
106 delaymax
= max(delaymax
, delay
);
107 delaymin
= min(delaymin
, delay
);
110 for (i
= 1; i
< NR_VARS
; i
++) {
114 "Unequal cur %d/prev %d at i %d, iter %lu "
115 "in thread\n", cur
, prev
, i
, iter
);
117 fair_read_unlock(&frwlock
);
118 preempt_enable(); /* for get_cycles accuracy */
120 } while (!kthread_should_stop());
122 printk("reader_thread/%lu iterations : %lu, "
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
));
131 static int trylock_reader_thread(void *data
)
135 unsigned long iter
= 0, success_iter
= 0;
137 printk("trylock_reader_thread/%lu runnning\n", (unsigned long)data
);
139 while (!fair_read_trylock(&frwlock
))
143 for (i
= 1; i
< NR_VARS
; i
++) {
147 "Unequal cur %d/prev %d at i %d, iter %lu "
148 "in thread\n", cur
, prev
, i
, iter
);
150 fair_read_unlock(&frwlock
);
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
);
159 DEFINE_PER_CPU(cycles_t
, int_delaymin
);
160 DEFINE_PER_CPU(cycles_t
, int_delayavg
);
161 DEFINE_PER_CPU(cycles_t
, int_delaymax
);
162 DEFINE_PER_CPU(cycles_t
, int_ipi_nr
);
164 static void interrupt_reader_ipi(void *data
)
168 cycles_t time1
, time2
;
169 cycles_t
*delaymax
, *delaymin
, *delayavg
, *ipi_nr
, delay
;
172 * Skip the ipi caller, not in irq context.
177 delaymax
= &per_cpu(int_delaymax
, smp_processor_id());
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());
183 time1
= get_cycles();
186 fair_read_lock(&frwlock
);
189 time2
= get_cycles();
191 delay
= time2
- time1
;
192 *delaymax
= max(*delaymax
, delay
);
193 *delaymin
= min(*delaymin
, delay
);
197 for (i
= 1; i
< NR_VARS
; i
++) {
201 "Unequal cur %d/prev %d at i %d in interrupt\n",
204 fair_read_unlock(&frwlock
);
207 DEFINE_PER_CPU(unsigned long, trylock_int_iter
);
208 DEFINE_PER_CPU(unsigned long, trylock_int_success
);
210 static void trylock_interrupt_reader_ipi(void *data
)
216 * Skip the ipi caller, not in irq context.
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())++;
226 for (i
= 1; i
< NR_VARS
; i
++) {
230 "Unequal cur %d/prev %d at i %d in interrupt\n",
233 fair_read_unlock(&frwlock
);
237 static int interrupt_reader_thread(void *data
)
239 unsigned long iter
= 0;
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;
250 on_each_cpu(interrupt_reader_ipi
, NULL
, 0);
252 } while (!kthread_should_stop());
253 printk("interrupt_reader_thread/%lu iterations : %lu\n",
254 (unsigned long)data
, iter
);
255 for_each_online_cpu(i
) {
256 per_cpu(int_delayavg
, i
) /= per_cpu(int_ipi_nr
, i
);
257 printk("interrupt readers on CPU %i, "
258 "lock delay [min,avg,max] %llu,%llu,%llu cycles\n",
260 calibrate_cycles(per_cpu(int_delaymin
, i
)),
261 calibrate_cycles(per_cpu(int_delayavg
, i
)),
262 calibrate_cycles(per_cpu(int_delaymax
, i
)));
267 static int trylock_interrupt_reader_thread(void *data
)
269 unsigned long iter
= 0;
274 on_each_cpu(trylock_interrupt_reader_ipi
, NULL
, 0);
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, "
282 "successful iterations : %lu\n",
283 i
, per_cpu(trylock_int_iter
, i
),
284 per_cpu(trylock_int_success
, i
));
285 per_cpu(trylock_int_iter
, i
) = 0;
286 per_cpu(trylock_int_success
, i
) = 0;
291 static int writer_thread(void *data
)
295 unsigned long iter
= 0;
296 cycles_t time1
, time2
, delay
, delaymax
= 0, delaymin
= ULLONG_MAX
,
299 printk("writer_thread/%lu runnning\n", (unsigned long)data
);
302 preempt_disable(); /* for get_cycles accuracy */
304 time1
= get_cycles();
307 fair_write_lock_irq(&frwlock
);
308 //fair_write_lock(&frwlock);
311 time2
= get_cycles();
313 delay
= time2
- time1
;
314 delaymax
= max(delaymax
, delay
);
315 delaymin
= min(delaymin
, delay
);
317 new = (int)get_cycles();
318 for (i
= 0; i
< NR_VARS
; i
++) {
321 //fair_write_unlock(&frwlock);
322 fair_write_unlock_irq(&frwlock
);
323 preempt_enable(); /* for get_cycles accuracy */
324 if (WRITER_DELAY
> 0)
325 udelay(WRITER_DELAY
);
326 } while (!kthread_should_stop());
328 printk("writer_thread/%lu iterations : %lu, "
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
));
337 static int trylock_writer_thread(void *data
)
341 unsigned long iter
= 0, success
= 0;
343 printk("trylock_writer_thread/%lu runnning\n", (unsigned long)data
);
345 fair_write_subscribe(&frwlock
);
346 while (!fair_write_trylock_subscribed_irq(&frwlock
)) {
351 //fair_write_lock(&frwlock);
352 new = (int)get_cycles();
353 for (i
= 0; i
< NR_VARS
; i
++) {
356 //fair_write_unlock(&frwlock);
357 fair_write_unlock_irq(&frwlock
);
358 if (WRITER_DELAY
> 0)
359 udelay(WRITER_DELAY
);
360 } while (!kthread_should_stop());
361 printk("trylock_writer_thread/%lu iterations : %lu, "
362 "successful iterations : %lu\n",
363 (unsigned long)data
, iter
, success
);
367 static void fair_rwlock_create(void)
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
,
375 BUG_ON(!reader_threads
[i
]);
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
]);
386 printk("starting interrupt reader %lu\n", i
);
387 interrupt_reader
= kthread_run(interrupt_reader_thread
, NULL
,
388 "frwlock_interrupt_reader");
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");
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
,
397 BUG_ON(!writer_threads
[i
]);
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
]);
407 static void fair_rwlock_stop(void)
411 for (i
= 0; i
< NR_WRITERS
; i
++)
412 kthread_stop(writer_threads
[i
]);
413 for (i
= 0; i
< NR_TRYLOCK_WRITERS
; i
++)
414 kthread_stop(trylock_writer_threads
[i
]);
415 for (i
= 0; i
< NR_READERS
; i
++)
416 kthread_stop(reader_threads
[i
]);
417 for (i
= 0; i
< NR_TRYLOCK_READERS
; i
++)
418 kthread_stop(trylock_reader_threads
[i
]);
419 kthread_stop(interrupt_reader
);
420 kthread_stop(trylock_interrupt_reader
);
424 static void perform_test(const char *name
, void (*callback
)(void))
426 printk("%s\n", name
);
430 static int my_open(struct inode
*inode
, struct file
*file
)
433 cycles_t time1
, time2
, delay
;
435 printk("** get_cycles calibration **\n");
436 cycles_calibration_min
= ULLONG_MAX
;
437 cycles_calibration_avg
= 0;
438 cycles_calibration_max
= 0;
441 for (i
= 0; i
< 10; i
++) {
443 time1
= get_cycles();
446 time2
= get_cycles();
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
);
453 cycles_calibration_avg
/= 10;
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
);
462 printk("** Single writer test, no contention **\n");
463 writer_threads
[0] = kthread_run(writer_thread
, (void *)0,
465 BUG_ON(!writer_threads
[0]);
466 ssleep(SINGLE_WRITER_TEST_DURATION
);
467 kthread_stop(writer_threads
[0]);
469 printk("** Single reader test, no contention **\n");
470 reader_threads
[0] = kthread_run(reader_thread
, (void *)0,
472 BUG_ON(!reader_threads
[0]);
473 ssleep(SINGLE_READER_TEST_DURATION
);
474 kthread_stop(reader_threads
[0]);
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
,
481 BUG_ON(!reader_threads
[i
]);
483 ssleep(SINGLE_READER_TEST_DURATION
);
484 for (i
= 0; i
< NR_READERS
; i
++)
485 kthread_stop(reader_threads
[i
]);
487 printk("** High contention test **\n");
488 perform_test("fair-rwlock-create", fair_rwlock_create
);
489 ssleep(TEST_DURATION
);
490 perform_test("fair-rwlock-stop", fair_rwlock_stop
);
496 static struct file_operations my_operations
= {
500 int init_module(void)
502 pentry
= create_proc_entry("testfrwlock", 0444, NULL
);
504 pentry
->proc_fops
= &my_operations
;
506 printk("NR_CPUS : %d\n", NR_CPUS
);
507 printk("THREAD_ROFFSET : %lX\n", THREAD_ROFFSET
);
508 printk("THREAD_RMASK : %lX\n", THREAD_RMASK
);
509 printk("SOFTIRQ_ROFFSET : %lX\n", SOFTIRQ_ROFFSET
);
510 printk("SOFTIRQ_RMASK : %lX\n", SOFTIRQ_RMASK
);
511 printk("HARDIRQ_ROFFSET : %lX\n", HARDIRQ_ROFFSET
);
512 printk("HARDIRQ_RMASK : %lX\n", HARDIRQ_RMASK
);
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
);
517 printk("HARDIRQ_WMASK : %lX\n", HARDIRQ_WMASK
);
522 void cleanup_module(void)
524 remove_proc_entry("testfrwlock", NULL
);
527 MODULE_LICENSE("GPL");
528 MODULE_AUTHOR("Mathieu Desnoyers");
529 MODULE_DESCRIPTION("Fair rwlock test");