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
89889f86 21/* Test duration, in seconds */
f36c4112 22#define TEST_DURATION 60
89889f86 23
f0a36bb1 24#define THREAD_ROFFSET 1UL
25#define THREAD_RMASK ((NR_CPUS - 1) * THREAD_ROFFSET)
26#define SOFTIRQ_ROFFSET (THREAD_RMASK + 1)
27#define SOFTIRQ_RMASK ((NR_CPUS - 1) * SOFTIRQ_ROFFSET)
28#define HARDIRQ_ROFFSET ((SOFTIRQ_RMASK | THREAD_RMASK) + 1)
29#define HARDIRQ_RMASK ((NR_CPUS - 1) * HARDIRQ_ROFFSET)
30
7f563886 31#define SUBSCRIBERS_WOFFSET \
32 ((HARDIRQ_RMASK | SOFTIRQ_RMASK | THREAD_RMASK) + 1)
33#define SUBSCRIBERS_WMASK \
34 ((NR_CPUS - 1) * SUBSCRIBERS_WOFFSET)
35#define WRITER_MUTEX \
36 ((SUBSCRIBERS_WMASK | HARDIRQ_RMASK | SOFTIRQ_RMASK | THREAD_RMASK) + 1)
37#define SOFTIRQ_WMASK (WRITER_MUTEX << 1)
38#define SOFTIRQ_WOFFSET SOFTIRQ_WMASK
426d6b67 39#define HARDIRQ_WMASK (SOFTIRQ_WMASK << 1)
7f563886 40#define HARDIRQ_WOFFSET HARDIRQ_WMASK
f0a36bb1 41
42#define NR_VARS 100
1c21e42c 43#define NR_WRITERS 2
44#define NR_TRYLOCK_WRITERS 2
45#define NR_READERS 4
46#define NR_TRYLOCK_READERS 2
47#define NR_INTERRUPT_READERS 1
48#define NR_TRYLOCK_INTERRUPT_READERS 1
f0a36bb1 49
4d1751f9 50/*
51 * Writer iteration delay, in us. 0 for busy loop. Caution : writers can
52 * starve readers.
53 */
54#define WRITER_DELAY 10
89889f86 55
f0a36bb1 56static int var[NR_VARS];
57static struct task_struct *reader_threads[NR_READERS];
1c21e42c 58static struct task_struct *trylock_reader_threads[NR_TRYLOCK_READERS];
f0a36bb1 59static struct task_struct *writer_threads[NR_WRITERS];
1c21e42c 60static struct task_struct *trylock_writer_threads[NR_TRYLOCK_WRITERS];
f0a36bb1 61static struct task_struct *interrupt_reader;
1c21e42c 62static struct task_struct *trylock_interrupt_reader;
f0a36bb1 63
64static struct fair_rwlock frwlock = {
65 .value = ATOMIC_LONG_INIT(0),
f0a36bb1 66};
67
68struct proc_dir_entry *pentry = NULL;
69
70static int reader_thread(void *data)
71{
72 int i;
73 int prev, cur;
74 unsigned long iter = 0;
7f563886 75 cycles_t time1, time2, delaymax = 0;
f0a36bb1 76
77 printk("reader_thread/%lu runnning\n", (unsigned long)data);
78 do {
79 iter++;
7f563886 80 preempt_disable(); /* for get_cycles accuracy */
81 time1 = get_cycles();
f0a36bb1 82 fair_read_lock(&frwlock);
7f563886 83 time2 = get_cycles();
84 delaymax = max(delaymax, time2 - time1);
f0a36bb1 85 prev = var[0];
86 for (i = 1; i < NR_VARS; i++) {
87 cur = var[i];
88 if (cur != prev)
89 printk(KERN_ALERT
90 "Unequal cur %d/prev %d at i %d, iter %lu "
91 "in thread\n", cur, prev, i, iter);
92 }
93 fair_read_unlock(&frwlock);
7f563886 94 preempt_enable(); /* for get_cycles accuracy */
f0a36bb1 95 //msleep(100);
96 } while (!kthread_should_stop());
7f563886 97 printk("reader_thread/%lu iterations : %lu, "
98 "max contention %llu cycles\n",
99 (unsigned long)data, iter, delaymax);
f0a36bb1 100 return 0;
101}
102
1c21e42c 103static int trylock_reader_thread(void *data)
104{
105 int i;
106 int prev, cur;
107 unsigned long iter = 0, success_iter = 0;
108
109 printk("trylock_reader_thread/%lu runnning\n", (unsigned long)data);
110 do {
111 while (!fair_read_trylock(&frwlock))
112 iter++;
113 success_iter++;
114 prev = var[0];
115 for (i = 1; i < NR_VARS; i++) {
116 cur = var[i];
117 if (cur != prev)
118 printk(KERN_ALERT
119 "Unequal cur %d/prev %d at i %d, iter %lu "
120 "in thread\n", cur, prev, i, iter);
121 }
122 fair_read_unlock(&frwlock);
123 //msleep(100);
124 } while (!kthread_should_stop());
125 printk("trylock_reader_thread/%lu iterations : %lu, "
126 "successful iterations : %lu\n",
127 (unsigned long)data, iter, success_iter);
128 return 0;
129}
130
7f563886 131DEFINE_PER_CPU(cycles_t, int_delaymax);
132
f0a36bb1 133static void interrupt_reader_ipi(void *data)
134{
135 int i;
136 int prev, cur;
7f563886 137 cycles_t time1, time2;
138 cycles_t *delaymax;
139
140 /*
141 * Skip the ipi caller, not in irq context.
142 */
143 if (!in_irq())
144 return;
f0a36bb1 145
7f563886 146 delaymax = &per_cpu(int_delaymax, smp_processor_id());
147 time1 = get_cycles();
f0a36bb1 148 fair_read_lock(&frwlock);
7f563886 149 time2 = get_cycles();
150 *delaymax = max(*delaymax, time2 - time1);
f0a36bb1 151 prev = var[0];
152 for (i = 1; i < NR_VARS; i++) {
153 cur = var[i];
154 if (cur != prev)
155 printk(KERN_ALERT
156 "Unequal cur %d/prev %d at i %d in interrupt\n",
157 cur, prev, i);
158 }
159 fair_read_unlock(&frwlock);
160}
161
1c21e42c 162DEFINE_PER_CPU(unsigned long, trylock_int_iter);
163DEFINE_PER_CPU(unsigned long, trylock_int_success);
164
165static void trylock_interrupt_reader_ipi(void *data)
166{
167 int i;
168 int prev, cur;
169
170 /*
171 * Skip the ipi caller, not in irq context.
172 */
173 if (!in_irq())
174 return;
175
176 per_cpu(trylock_int_iter, smp_processor_id())++;
177 while (!fair_read_trylock(&frwlock))
178 per_cpu(trylock_int_iter, smp_processor_id())++;
179 per_cpu(trylock_int_success, smp_processor_id())++;
180 prev = var[0];
181 for (i = 1; i < NR_VARS; i++) {
182 cur = var[i];
183 if (cur != prev)
184 printk(KERN_ALERT
185 "Unequal cur %d/prev %d at i %d in interrupt\n",
186 cur, prev, i);
187 }
188 fair_read_unlock(&frwlock);
189}
190
191
f0a36bb1 192static int interrupt_reader_thread(void *data)
193{
194 unsigned long iter = 0;
7f563886 195 int i;
196
f0a36bb1 197 do {
198 iter++;
199 on_each_cpu(interrupt_reader_ipi, NULL, 0);
200 msleep(100);
201 } while (!kthread_should_stop());
202 printk("interrupt_reader_thread/%lu iterations : %lu\n",
203 (unsigned long)data, iter);
7f563886 204 for_each_online_cpu(i) {
205 printk("interrupt readers on CPU %i, "
206 "max contention : %llu cycles\n",
207 i, per_cpu(int_delaymax, i));
208 }
f0a36bb1 209 return 0;
210}
211
1c21e42c 212static int trylock_interrupt_reader_thread(void *data)
213{
214 unsigned long iter = 0;
215 int i;
216
217 do {
218 iter++;
219 on_each_cpu(trylock_interrupt_reader_ipi, NULL, 0);
220 msleep(100);
221 } while (!kthread_should_stop());
222 printk("trylock_interrupt_reader_thread/%lu iterations : %lu\n",
223 (unsigned long)data, iter);
224 for_each_online_cpu(i) {
225 printk("trylock interrupt readers on CPU %i, "
226 "iterations %lu, "
227 "successful iterations : %lu\n",
228 i, per_cpu(trylock_int_iter, i),
229 per_cpu(trylock_int_success, i));
230 }
231 return 0;
232}
233
f0a36bb1 234static int writer_thread(void *data)
235{
236 int i;
237 int new;
238 unsigned long iter = 0;
7f563886 239 cycles_t time1, time2, delaymax = 0;
f0a36bb1 240
241 printk("writer_thread/%lu runnning\n", (unsigned long)data);
242 do {
243 iter++;
7f563886 244 preempt_disable(); /* for get_cycles accuracy */
245 time1 = get_cycles();
f0a36bb1 246 fair_write_lock_irq(&frwlock);
247 //fair_write_lock(&frwlock);
7f563886 248 time2 = get_cycles();
249 delaymax = max(delaymax, time2 - time1);
f0a36bb1 250 new = (int)get_cycles();
251 for (i = 0; i < NR_VARS; i++) {
252 var[i] = new;
253 }
254 //fair_write_unlock(&frwlock);
255 fair_write_unlock_irq(&frwlock);
7f563886 256 preempt_enable(); /* for get_cycles accuracy */
89889f86 257 if (WRITER_DELAY > 0)
4d1751f9 258 udelay(WRITER_DELAY);
f0a36bb1 259 } while (!kthread_should_stop());
7f563886 260 printk("writer_thread/%lu iterations : %lu, "
261 "max contention %llu cycles\n",
262 (unsigned long)data, iter, delaymax);
f0a36bb1 263 return 0;
264}
265
1c21e42c 266static int trylock_writer_thread(void *data)
267{
268 int i;
269 int new;
270 unsigned long iter = 0, success = 0;
271
272 printk("trylock_writer_thread/%lu runnning\n", (unsigned long)data);
273 do {
274 fair_write_subscribe(&frwlock);
275 while (!fair_write_trylock_subscribed_irq(&frwlock)) {
276 iter++;
277 continue;
278 }
279 success++;
280 //fair_write_lock(&frwlock);
281 new = (int)get_cycles();
282 for (i = 0; i < NR_VARS; i++) {
283 var[i] = new;
284 }
285 //fair_write_unlock(&frwlock);
286 fair_write_unlock_irq(&frwlock);
287 if (WRITER_DELAY > 0)
4d1751f9 288 udelay(WRITER_DELAY);
1c21e42c 289 } while (!kthread_should_stop());
290 printk("trylock_writer_thread/%lu iterations : %lu, "
291 "successful iterations : %lu\n",
292 (unsigned long)data, iter, success);
293 return 0;
294}
295
f0a36bb1 296static void fair_rwlock_create(void)
297{
298 unsigned long i;
299
300 for (i = 0; i < NR_READERS; i++) {
301 printk("starting reader thread %lu\n", i);
302 reader_threads[i] = kthread_run(reader_thread, (void *)i,
303 "frwlock_reader");
304 BUG_ON(!reader_threads[i]);
305 }
306
1c21e42c 307 for (i = 0; i < NR_TRYLOCK_READERS; i++) {
308 printk("starting trylock reader thread %lu\n", i);
309 trylock_reader_threads[i] = kthread_run(trylock_reader_thread,
310 (void *)i, "frwlock_trylock_reader");
311 BUG_ON(!trylock_reader_threads[i]);
312 }
313
314
f0a36bb1 315 printk("starting interrupt reader %lu\n", i);
316 interrupt_reader = kthread_run(interrupt_reader_thread, NULL,
317 "frwlock_interrupt_reader");
1c21e42c 318 printk("starting trylock interrupt reader %lu\n", i);
319 trylock_interrupt_reader = kthread_run(trylock_interrupt_reader_thread,
320 NULL, "frwlock_trylock_interrupt_reader");
f0a36bb1 321
322 for (i = 0; i < NR_WRITERS; i++) {
323 printk("starting writer thread %lu\n", i);
324 writer_threads[i] = kthread_run(writer_thread, (void *)i,
325 "frwlock_writer");
326 BUG_ON(!writer_threads[i]);
327 }
1c21e42c 328 for (i = 0; i < NR_TRYLOCK_WRITERS; i++) {
329 printk("starting trylock writer thread %lu\n", i);
330 trylock_writer_threads[i] = kthread_run(trylock_writer_thread,
331 (void *)i, "frwlock_trylock_writer");
332 BUG_ON(!trylock_writer_threads[i]);
333 }
334
f0a36bb1 335}
336
337static void fair_rwlock_stop(void)
338{
339 unsigned long i;
340
1c21e42c 341 for (i = 0; i < NR_WRITERS; i++)
7f563886 342 kthread_stop(writer_threads[i]);
1c21e42c 343 for (i = 0; i < NR_TRYLOCK_WRITERS; i++)
344 kthread_stop(trylock_writer_threads[i]);
345 for (i = 0; i < NR_READERS; i++)
f0a36bb1 346 kthread_stop(reader_threads[i]);
1c21e42c 347 for (i = 0; i < NR_TRYLOCK_READERS; i++)
348 kthread_stop(trylock_reader_threads[i]);
7f563886 349 kthread_stop(interrupt_reader);
1c21e42c 350 kthread_stop(trylock_interrupt_reader);
f0a36bb1 351}
352
353
354static void perform_test(const char *name, void (*callback)(void))
355{
356 printk("%s\n", name);
357 callback();
358}
359
360static int my_open(struct inode *inode, struct file *file)
361{
362 perform_test("fair-rwlock-create", fair_rwlock_create);
f36c4112 363 ssleep(TEST_DURATION);
f0a36bb1 364 perform_test("fair-rwlock-stop", fair_rwlock_stop);
365
366 return -EPERM;
367}
368
369
370static struct file_operations my_operations = {
371 .open = my_open,
372};
373
374int init_module(void)
375{
376 pentry = create_proc_entry("testfrwlock", 0444, NULL);
377 if (pentry)
378 pentry->proc_fops = &my_operations;
379
380 printk("NR_CPUS : %d\n", NR_CPUS);
381 printk("THREAD_ROFFSET : %lX\n", THREAD_ROFFSET);
382 printk("THREAD_RMASK : %lX\n", THREAD_RMASK);
f0a36bb1 383 printk("SOFTIRQ_ROFFSET : %lX\n", SOFTIRQ_ROFFSET);
384 printk("SOFTIRQ_RMASK : %lX\n", SOFTIRQ_RMASK);
f0a36bb1 385 printk("HARDIRQ_ROFFSET : %lX\n", HARDIRQ_ROFFSET);
386 printk("HARDIRQ_RMASK : %lX\n", HARDIRQ_RMASK);
7f563886 387 printk("SUBSCRIBERS_WOFFSET : %lX\n", SUBSCRIBERS_WOFFSET);
388 printk("SUBSCRIBERS_WMASK : %lX\n", SUBSCRIBERS_WMASK);
389 printk("WRITER_MUTEX : %lX\n", WRITER_MUTEX);
390 printk("SOFTIRQ_WMASK : %lX\n", SOFTIRQ_WMASK);
f0a36bb1 391 printk("HARDIRQ_WMASK : %lX\n", HARDIRQ_WMASK);
392
393 return 0;
394}
395
396void cleanup_module(void)
397{
398 remove_proc_entry("testfrwlock", NULL);
399}
400
401MODULE_LICENSE("GPL");
402MODULE_AUTHOR("Mathieu Desnoyers");
403MODULE_DESCRIPTION("Fair rwlock test");
This page took 0.039364 seconds and 4 git commands to generate.