421991b0 |
1 | /* test-cmpxchg-nolock.c |
2 | * |
3 | * Compare local cmpxchg with irq disable / enable. |
4 | */ |
5 | |
6 | |
7 | #include <linux/jiffies.h> |
8 | #include <linux/compiler.h> |
9 | #include <linux/init.h> |
10 | #include <linux/module.h> |
f6b929e7 |
11 | #include <linux/math64.h> |
421991b0 |
12 | #include <asm/timex.h> |
13 | #include <asm/system.h> |
14 | |
15 | #define NR_LOOPS 20000 |
16 | |
17 | int test_val; |
18 | |
979e6e46 |
19 | static void do_testbaseline(void) |
20 | { |
f6b929e7 |
21 | unsigned long flags; |
979e6e46 |
22 | unsigned int i; |
23 | cycles_t time1, time2, time; |
f6b929e7 |
24 | u32 rem; |
979e6e46 |
25 | |
26 | local_irq_save(flags); |
27 | preempt_disable(); |
28 | time1 = get_cycles(); |
29 | for (i = 0; i < NR_LOOPS; i++) { |
30 | asm volatile (""); |
31 | } |
32 | time2 = get_cycles(); |
33 | local_irq_restore(flags); |
34 | preempt_enable(); |
35 | time = time2 - time1; |
36 | |
37 | printk(KERN_ALERT "test results: time for baseline\n"); |
38 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
39 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
40 | time = div_u64_rem(time, NR_LOOPS, &rem); |
979e6e46 |
41 | printk(KERN_ALERT "-> baseline takes %llu cycles\n", time); |
42 | printk(KERN_ALERT "test end\n"); |
43 | } |
44 | |
f57afc80 |
45 | static void do_test_sync_cmpxchg(void) |
46 | { |
47 | int ret; |
f6b929e7 |
48 | unsigned long flags; |
f57afc80 |
49 | unsigned int i; |
50 | cycles_t time1, time2, time; |
f6b929e7 |
51 | u32 rem; |
f57afc80 |
52 | |
53 | local_irq_save(flags); |
54 | preempt_disable(); |
55 | time1 = get_cycles(); |
56 | for (i = 0; i < NR_LOOPS; i++) { |
57 | #ifdef CONFIG_X86_32 |
58 | ret = sync_cmpxchg(&test_val, 0, 0); |
59 | #else |
60 | ret = cmpxchg(&test_val, 0, 0); |
61 | #endif |
62 | } |
63 | time2 = get_cycles(); |
64 | local_irq_restore(flags); |
65 | preempt_enable(); |
66 | time = time2 - time1; |
67 | |
68 | printk(KERN_ALERT "test results: time for locked cmpxchg\n"); |
69 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
70 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
71 | time = div_u64_rem(time, NR_LOOPS, &rem); |
f57afc80 |
72 | printk(KERN_ALERT "-> locked cmpxchg takes %llu cycles\n", time); |
73 | printk(KERN_ALERT "test end\n"); |
74 | } |
75 | |
421991b0 |
76 | static void do_test_cmpxchg(void) |
77 | { |
78 | int ret; |
f6b929e7 |
79 | unsigned long flags; |
421991b0 |
80 | unsigned int i; |
81 | cycles_t time1, time2, time; |
f6b929e7 |
82 | u32 rem; |
421991b0 |
83 | |
84 | local_irq_save(flags); |
85 | preempt_disable(); |
86 | time1 = get_cycles(); |
87 | for (i = 0; i < NR_LOOPS; i++) { |
88 | ret = cmpxchg_local(&test_val, 0, 0); |
89 | } |
90 | time2 = get_cycles(); |
91 | local_irq_restore(flags); |
92 | preempt_enable(); |
93 | time = time2 - time1; |
94 | |
95 | printk(KERN_ALERT "test results: time for non locked cmpxchg\n"); |
96 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
97 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
98 | time = div_u64_rem(time, NR_LOOPS, &rem); |
421991b0 |
99 | printk(KERN_ALERT "-> non locked cmpxchg takes %llu cycles\n", time); |
100 | printk(KERN_ALERT "test end\n"); |
101 | } |
0c12e051 |
102 | static void do_test_sync_inc(void) |
103 | { |
104 | int ret; |
f6b929e7 |
105 | unsigned long flags; |
0c12e051 |
106 | unsigned int i; |
107 | cycles_t time1, time2, time; |
f6b929e7 |
108 | u32 rem; |
0c12e051 |
109 | atomic_t val; |
110 | |
111 | local_irq_save(flags); |
112 | preempt_disable(); |
113 | time1 = get_cycles(); |
114 | for (i = 0; i < NR_LOOPS; i++) { |
115 | ret = atomic_add_return(10, &val); |
116 | } |
117 | time2 = get_cycles(); |
118 | local_irq_restore(flags); |
119 | preempt_enable(); |
120 | time = time2 - time1; |
121 | |
122 | printk(KERN_ALERT "test results: time for locked add return\n"); |
123 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
124 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
125 | time = div_u64_rem(time, NR_LOOPS, &rem); |
0c12e051 |
126 | printk(KERN_ALERT "-> locked add return takes %llu cycles\n", time); |
127 | printk(KERN_ALERT "test end\n"); |
128 | } |
129 | |
130 | |
131 | static void do_test_inc(void) |
132 | { |
133 | int ret; |
f6b929e7 |
134 | unsigned long flags; |
0c12e051 |
135 | unsigned int i; |
136 | cycles_t time1, time2, time; |
f6b929e7 |
137 | u32 rem; |
0c12e051 |
138 | local_t loc_val; |
139 | |
140 | local_irq_save(flags); |
141 | preempt_disable(); |
142 | time1 = get_cycles(); |
143 | for (i = 0; i < NR_LOOPS; i++) { |
144 | ret = local_add_return(10, &loc_val); |
145 | } |
146 | time2 = get_cycles(); |
147 | local_irq_restore(flags); |
148 | preempt_enable(); |
149 | time = time2 - time1; |
150 | |
151 | printk(KERN_ALERT "test results: time for non locked add return\n"); |
152 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
153 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
154 | time = div_u64_rem(time, NR_LOOPS, &rem); |
0c12e051 |
155 | printk(KERN_ALERT "-> non locked add return takes %llu cycles\n", time); |
156 | printk(KERN_ALERT "test end\n"); |
157 | } |
158 | |
159 | |
421991b0 |
160 | |
161 | /* |
162 | * This test will have a higher standard deviation due to incoming interrupts. |
163 | */ |
164 | static void do_test_enable_int(void) |
165 | { |
f6b929e7 |
166 | unsigned long flags; |
421991b0 |
167 | unsigned int i; |
168 | cycles_t time1, time2, time; |
f6b929e7 |
169 | u32 rem; |
421991b0 |
170 | |
171 | local_irq_save(flags); |
172 | preempt_disable(); |
173 | time1 = get_cycles(); |
174 | for (i = 0; i < NR_LOOPS; i++) { |
175 | local_irq_restore(flags); |
176 | } |
177 | time2 = get_cycles(); |
178 | local_irq_restore(flags); |
179 | preempt_enable(); |
180 | time = time2 - time1; |
181 | |
182 | printk(KERN_ALERT "test results: time for enabling interrupts (STI)\n"); |
183 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
184 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
185 | time = div_u64_rem(time, NR_LOOPS, &rem); |
421991b0 |
186 | printk(KERN_ALERT "-> enabling interrupts (STI) takes %llu cycles\n", |
187 | time); |
188 | printk(KERN_ALERT "test end\n"); |
189 | } |
190 | |
191 | static void do_test_disable_int(void) |
192 | { |
193 | unsigned long flags, flags2; |
194 | unsigned int i; |
195 | cycles_t time1, time2, time; |
f6b929e7 |
196 | u32 rem; |
421991b0 |
197 | |
198 | local_irq_save(flags); |
199 | preempt_disable(); |
200 | time1 = get_cycles(); |
201 | for ( i = 0; i < NR_LOOPS; i++) { |
202 | local_irq_save(flags2); |
203 | } |
204 | time2 = get_cycles(); |
205 | local_irq_restore(flags); |
206 | preempt_enable(); |
207 | time = time2 - time1; |
208 | |
209 | printk(KERN_ALERT "test results: time for disabling interrupts (CLI)\n"); |
210 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
211 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
212 | time = div_u64_rem(time, NR_LOOPS, &rem); |
7de49e3a |
213 | printk(KERN_ALERT "-> disabling interrupts (CLI) takes %llu cycles\n", |
421991b0 |
214 | time); |
215 | printk(KERN_ALERT "test end\n"); |
216 | } |
217 | |
236f9aae |
218 | static void do_test_int(void) |
219 | { |
f6b929e7 |
220 | unsigned long flags; |
236f9aae |
221 | unsigned int i; |
222 | cycles_t time1, time2, time; |
f6b929e7 |
223 | u32 rem; |
236f9aae |
224 | |
225 | local_irq_save(flags); |
226 | preempt_disable(); |
227 | time1 = get_cycles(); |
228 | for (i = 0; i < NR_LOOPS; i++) { |
229 | local_irq_restore(flags); |
230 | local_irq_save(flags); |
231 | } |
232 | time2 = get_cycles(); |
233 | local_irq_restore(flags); |
234 | preempt_enable(); |
235 | time = time2 - time1; |
236 | |
237 | printk(KERN_ALERT "test results: time for disabling/enabling interrupts (STI/CLI)\n"); |
238 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
239 | printk(KERN_ALERT "total time: %llu\n", time); |
f6b929e7 |
240 | time = div_u64_rem(time, NR_LOOPS, &rem); |
236f9aae |
241 | printk(KERN_ALERT "-> enabling/disabling interrupts (STI/CLI) takes %llu cycles\n", |
242 | time); |
243 | printk(KERN_ALERT "test end\n"); |
244 | } |
245 | |
421991b0 |
246 | |
247 | |
248 | static int ltt_test_init(void) |
249 | { |
250 | printk(KERN_ALERT "test init\n"); |
251 | |
979e6e46 |
252 | do_testbaseline(); |
fa2b47dd |
253 | do_test_sync_cmpxchg(); |
421991b0 |
254 | do_test_cmpxchg(); |
0c12e051 |
255 | do_test_sync_inc(); |
256 | do_test_inc(); |
421991b0 |
257 | do_test_enable_int(); |
258 | do_test_disable_int(); |
236f9aae |
259 | do_test_int(); |
421991b0 |
260 | return -EAGAIN; /* Fail will directly unload the module */ |
261 | } |
262 | |
263 | static void ltt_test_exit(void) |
264 | { |
265 | printk(KERN_ALERT "test exit\n"); |
266 | } |
267 | |
268 | module_init(ltt_test_init) |
269 | module_exit(ltt_test_exit) |
270 | |
271 | MODULE_LICENSE("GPL"); |
272 | MODULE_AUTHOR("Mathieu Desnoyers"); |
273 | MODULE_DESCRIPTION("Cmpxchg vs int Test"); |
274 | |