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