979f1bc8cba91575a8b3dc0d856598d5cbe86d04
[lttv.git] / trunk / tests / kernel / test-read-lock-speed.c
1 /*
2 * test-read-lock-speed.c
3 *
4 * Compare speed of :
5 * - spin lock irqsave / spin unlock irqrestore (protects from interrupts)
6 * - rwlock read lock (not disabling interrupts, can deal with nesting)
7 * - using a sequence read lock (uncontended)
8 * - preempt disable/enable (RCU)
9 *
10 * Copyright 2009 - Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
11 * Distributed under GPLv2
12 */
13
14 #include <linux/jiffies.h>
15 #include <linux/compiler.h>
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/math64.h>
19 #include <linux/spinlock.h>
20 #include <linux/seqlock.h>
21 #include <linux/cpumask.h>
22 #include <asm/timex.h>
23 #include <asm/system.h>
24
25 #define NR_LOOPS 20000
26
27 #ifndef CONFIG_PREEMPT
28 #error "Your kernel should be built with preemption enabled"
29 #endif
30
31 #ifdef CONFIG_DEBUG_PREEMPT
32 #error "Please disable CONFIG_DEBUG_PREEMPT"
33 #endif
34
35 #ifdef CONFIG_DEBUG_SPINLOCK
36 #error "Please disable CONFIG_DEBUG_SPINLOCK"
37 #endif
38
39 #ifdef CONFIG_LOCKDEP
40 #error "Please disable CONFIG_LOCKDEP"
41 #endif
42
43 int test_val;
44
45 static void do_testbaseline(void)
46 {
47 unsigned long flags;
48 unsigned int i;
49 cycles_t time1, time2, time;
50 u32 rem;
51
52 local_irq_save(flags);
53 preempt_disable();
54 time1 = get_cycles();
55 for (i = 0; i < NR_LOOPS; i++) {
56 asm volatile ("");
57 }
58 time2 = get_cycles();
59 local_irq_restore(flags);
60 preempt_enable();
61 time = time2 - time1;
62
63 printk(KERN_ALERT "test results: time for baseline\n");
64 printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
65 printk(KERN_ALERT "total time: %llu\n", time);
66 time = div_u64_rem(time, NR_LOOPS, &rem);
67 printk(KERN_ALERT "-> baseline takes %llu cycles\n", time);
68 printk(KERN_ALERT "test end\n");
69 }
70
71 static void do_test_spinlock(void)
72 {
73 static DEFINE_SPINLOCK(mylock);
74 unsigned long flags;
75 unsigned int i;
76 cycles_t time1, time2, time;
77 u32 rem;
78
79 preempt_disable();
80 spin_lock_irqsave(&mylock, flags);
81 time1 = get_cycles();
82 for (i = 0; i < NR_LOOPS; i++) {
83 spin_unlock(&mylock);
84 spin_lock(&mylock);
85 }
86 time2 = get_cycles();
87 spin_unlock_irqrestore(&mylock, flags);
88 preempt_enable();
89 time = time2 - time1;
90
91 printk(KERN_ALERT "test results: time for spinlock\n");
92 printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
93 printk(KERN_ALERT "total time: %llu\n", time);
94 time = div_u64_rem(time, NR_LOOPS, &rem);
95 printk(KERN_ALERT "-> spinlock takes %llu cycles\n", time);
96 printk(KERN_ALERT "test end\n");
97 }
98
99 static void do_test_read_rwlock(void)
100 {
101 static DEFINE_RWLOCK(mylock);
102 unsigned long flags;
103 unsigned int i;
104 cycles_t time1, time2, time;
105 u32 rem;
106
107 preempt_disable();
108 local_irq_save(flags);
109 read_lock(&mylock);
110 time1 = get_cycles();
111 for (i = 0; i < NR_LOOPS; i++) {
112 read_unlock(&mylock);
113 read_lock(&mylock);
114 }
115 time2 = get_cycles();
116 read_unlock(&mylock);
117 local_irq_restore(flags);
118 preempt_enable();
119 time = time2 - time1;
120
121 printk(KERN_ALERT "test results: time for read rwlock\n");
122 printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
123 printk(KERN_ALERT "total time: %llu\n", time);
124 time = div_u64_rem(time, NR_LOOPS, &rem);
125 printk(KERN_ALERT "-> read rwlock takes %llu cycles\n", time);
126 printk(KERN_ALERT "test end\n");
127 }
128
129 static void do_test_seqlock(void)
130 {
131 static seqlock_t test_lock;
132 unsigned long seq;
133 unsigned long flags;
134 unsigned int i;
135 cycles_t time1, time2, time;
136 u32 rem;
137
138 local_irq_save(flags);
139 time1 = get_cycles();
140 for (i = 0; i < NR_LOOPS; i++) {
141 do {
142 seq = read_seqbegin(&test_lock);
143 } while (read_seqretry(&test_lock, seq));
144 }
145 time2 = get_cycles();
146 time = time2 - time1;
147 local_irq_restore(flags);
148
149 printk(KERN_ALERT "test results: time for seqlock\n");
150 printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
151 printk(KERN_ALERT "total time: %llu\n", time);
152 time = div_u64_rem(time, NR_LOOPS, &rem);
153 printk(KERN_ALERT "-> seqlock takes %llu cycles\n", time);
154 printk(KERN_ALERT "test end\n");
155 }
156
157 /*
158 * Note : This test _should_ trigger lockdep errors due to preemption
159 * disabling/enabling within irq off section. Given we are only interested in
160 * having the most precise measurement for preemption disable/enable, we don't
161 * care about this.
162 */
163 static void do_test_preempt(void)
164 {
165 unsigned long flags;
166 unsigned int i;
167 cycles_t time1, time2, time;
168 u32 rem;
169
170 local_irq_save(flags);
171 preempt_disable();
172 time1 = get_cycles();
173 for (i = 0; i < NR_LOOPS; i++) {
174 preempt_disable();
175 preempt_enable();
176 }
177 time2 = get_cycles();
178 preempt_enable();
179 time = time2 - time1;
180 local_irq_restore(flags);
181
182 printk(KERN_ALERT
183 "test results: time for preempt disable/enable pairs\n");
184 printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
185 printk(KERN_ALERT "total time: %llu\n", time);
186 time = div_u64_rem(time, NR_LOOPS, &rem);
187 printk(KERN_ALERT "-> preempt disable/enable pair takes %llu cycles\n",
188 time);
189 printk(KERN_ALERT "test end\n");
190 }
191
192 static int ltt_test_init(void)
193 {
194 printk(KERN_ALERT "test init\n");
195
196 printk(KERN_ALERT "Number of active CPUs : %d\n", num_online_cpus());
197 do_testbaseline();
198 do_test_spinlock();
199 do_test_read_rwlock();
200 do_test_seqlock();
201 do_test_preempt();
202 return -EAGAIN; /* Fail will directly unload the module */
203 }
204
205 static void ltt_test_exit(void)
206 {
207 printk(KERN_ALERT "test exit\n");
208 }
209
210 module_init(ltt_test_init)
211 module_exit(ltt_test_exit)
212
213 MODULE_LICENSE("GPL");
214 MODULE_AUTHOR("Mathieu Desnoyers");
215 MODULE_DESCRIPTION("Test read lock speed");
This page took 0.041903 seconds and 3 git commands to generate.