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