• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /*                                                                            */
3 /* Copyright (c) Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>, 2009       */
4 /*                                                                            */
5 /* This program is free software;  you can redistribute it and/or modify      */
6 /* it under the terms of the GNU General Public License as published by       */
7 /* the Free Software Foundation; either version 2 of the License, or          */
8 /* (at your option) any later version.                                        */
9 /*                                                                            */
10 /* This program is distributed in the hope that it will be useful,            */
11 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
13 /* the GNU General Public License for more details.                           */
14 /*                                                                            */
15 /* You should have received a copy of the GNU General Public License          */
16 /* along with this program;  if not, write to the Free Software               */
17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
18 /*                                                                            */
19 /* usage :
20         make
21         insmod test-cmpxchg-nolock.ko
22         insmod: error inserting 'test-cmpxchg-nolock.ko':
23                 -1 Resource temporarily unavailable
24         dmesg (see dmesg output)                                              */
25 /******************************************************************************/
26 
27 /* test-cmpxchg-nolock.c
28 *
29 * Compare local cmpxchg with irq disable / enable.
30 */
31 
32 #include <linux/jiffies.h>
33 #include <linux/compiler.h>
34 #include <linux/init.h>
35 #include <linux/module.h>
36 #include <linux/math64.h>
37 #include <asm/timex.h>
38 #include <asm/system.h>
39 
40 #define NR_LOOPS 20000
41 
42 int test_val;
43 
do_testbaseline(void)44 static void do_testbaseline(void)
45 {
46 	unsigned long flags;
47 	unsigned int i;
48 	cycles_t time1, time2, time;
49 	u32 rem;
50 
51 	local_irq_save(flags);
52 	preempt_disable();
53 	time1 = get_cycles();
54 	for (i = 0; i < NR_LOOPS; i++) {
55 		asm volatile ("");
56 	}
57 	time2 = get_cycles();
58 	local_irq_restore(flags);
59 	preempt_enable();
60 	time = time2 - time1;
61 
62 	printk(KERN_ALERT "test results: time for baseline\n");
63 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
64 	printk(KERN_ALERT "total time: %llu\n", time);
65 	time = div_u64_rem(time, NR_LOOPS, &rem);
66 	printk(KERN_ALERT "-> baseline takes %llu cycles\n", time);
67 	printk(KERN_ALERT "test end\n");
68 }
69 
do_test_sync_cmpxchg(void)70 static void do_test_sync_cmpxchg(void)
71 {
72 	int ret;
73 	unsigned long flags;
74 	unsigned int i;
75 	cycles_t time1, time2, time;
76 	u32 rem;
77 
78 	local_irq_save(flags);
79 	preempt_disable();
80 	time1 = get_cycles();
81 	for (i = 0; i < NR_LOOPS; i++) {
82 #ifdef CONFIG_X86_32
83 		ret = sync_cmpxchg(&test_val, 0, 0);
84 #else
85 		ret = cmpxchg(&test_val, 0, 0);
86 #endif
87 	}
88 	time2 = get_cycles();
89 	local_irq_restore(flags);
90 	preempt_enable();
91 	time = time2 - time1;
92 
93 	printk(KERN_ALERT "test results: time for locked cmpxchg\n");
94 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
95 	printk(KERN_ALERT "total time: %llu\n", time);
96 	time = div_u64_rem(time, NR_LOOPS, &rem);
97 	printk(KERN_ALERT "-> locked cmpxchg takes %llu cycles\n", time);
98 	printk(KERN_ALERT "test end\n");
99 }
100 
do_test_cmpxchg(void)101 static void do_test_cmpxchg(void)
102 {
103 	int ret;
104 	unsigned long flags;
105 	unsigned int i;
106 	cycles_t time1, time2, time;
107 	u32 rem;
108 
109 	local_irq_save(flags);
110 	preempt_disable();
111 	time1 = get_cycles();
112 	for (i = 0; i < NR_LOOPS; i++) {
113 		ret = cmpxchg_local(&test_val, 0, 0);
114 	}
115 	time2 = get_cycles();
116 	local_irq_restore(flags);
117 	preempt_enable();
118 	time = time2 - time1;
119 
120 	printk(KERN_ALERT "test results: time for non locked cmpxchg\n");
121 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
122 	printk(KERN_ALERT "total time: %llu\n", time);
123 	time = div_u64_rem(time, NR_LOOPS, &rem);
124 	printk(KERN_ALERT "-> non locked cmpxchg takes %llu cycles\n", time);
125 	printk(KERN_ALERT "test end\n");
126 }
127 
do_test_sync_inc(void)128 static void do_test_sync_inc(void)
129 {
130 	int ret;
131 	unsigned long flags;
132 	unsigned int i;
133 	cycles_t time1, time2, time;
134 	u32 rem;
135 	atomic_t val;
136 
137 	local_irq_save(flags);
138 	preempt_disable();
139 	time1 = get_cycles();
140 	for (i = 0; i < NR_LOOPS; i++) {
141 		ret = atomic_add_return(10, &val);
142 	}
143 	time2 = get_cycles();
144 	local_irq_restore(flags);
145 	preempt_enable();
146 	time = time2 - time1;
147 
148 	printk(KERN_ALERT "test results: time for locked add return\n");
149 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
150 	printk(KERN_ALERT "total time: %llu\n", time);
151 	time = div_u64_rem(time, NR_LOOPS, &rem);
152 	printk(KERN_ALERT "-> locked add return takes %llu cycles\n", time);
153 	printk(KERN_ALERT "test end\n");
154 }
155 
do_test_inc(void)156 static void do_test_inc(void)
157 {
158 	int ret;
159 	unsigned long flags;
160 	unsigned int i;
161 	cycles_t time1, time2, time;
162 	u32 rem;
163 	local_t loc_val;
164 
165 	local_irq_save(flags);
166 	preempt_disable();
167 	time1 = get_cycles();
168 	for (i = 0; i < NR_LOOPS; i++) {
169 		ret = local_add_return(10, &loc_val);
170 	}
171 	time2 = get_cycles();
172 	local_irq_restore(flags);
173 	preempt_enable();
174 	time = time2 - time1;
175 
176 	printk(KERN_ALERT "test results: time for non locked add return\n");
177 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
178 	printk(KERN_ALERT "total time: %llu\n", time);
179 	time = div_u64_rem(time, NR_LOOPS, &rem);
180 	printk(KERN_ALERT "-> non locked add return takes %llu cycles\n", time);
181 	printk(KERN_ALERT "test end\n");
182 }
183 
184 /*
185  * This test will have a higher standard deviation due to incoming interrupts.
186  */
do_test_enable_int(void)187 static void do_test_enable_int(void)
188 {
189 	unsigned long flags;
190 	unsigned int i;
191 	cycles_t time1, time2, time;
192 	u32 rem;
193 
194 	local_irq_save(flags);
195 	preempt_disable();
196 	time1 = get_cycles();
197 	for (i = 0; i < NR_LOOPS; i++) {
198 		local_irq_restore(flags);
199 	}
200 	time2 = get_cycles();
201 	local_irq_restore(flags);
202 	preempt_enable();
203 	time = time2 - time1;
204 
205 	printk(KERN_ALERT "test results: time for enabling interrupts (STI)\n");
206 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
207 	printk(KERN_ALERT "total time: %llu\n", time);
208 	time = div_u64_rem(time, NR_LOOPS, &rem);
209 	printk(KERN_ALERT "-> enabling interrupts (STI) takes %llu cycles\n",
210 	       time);
211 	printk(KERN_ALERT "test end\n");
212 }
213 
do_test_disable_int(void)214 static void do_test_disable_int(void)
215 {
216 	unsigned long flags, flags2;
217 	unsigned int i;
218 	cycles_t time1, time2, time;
219 	u32 rem;
220 
221 	local_irq_save(flags);
222 	preempt_disable();
223 	time1 = get_cycles();
224 	for (i = 0; i < NR_LOOPS; i++) {
225 		local_irq_save(flags2);
226 	}
227 	time2 = get_cycles();
228 	local_irq_restore(flags);
229 	preempt_enable();
230 	time = time2 - time1;
231 
232 	printk(KERN_ALERT
233 	       "test results: time for disabling interrupts (CLI)\n");
234 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
235 	printk(KERN_ALERT "total time: %llu\n", time);
236 	time = div_u64_rem(time, NR_LOOPS, &rem);
237 	printk(KERN_ALERT "-> disabling interrupts (CLI) takes %llu cycles\n",
238 	       time);
239 	printk(KERN_ALERT "test end\n");
240 }
241 
do_test_int(void)242 static void do_test_int(void)
243 {
244 	unsigned long flags;
245 	unsigned int i;
246 	cycles_t time1, time2, time;
247 	u32 rem;
248 
249 	local_irq_save(flags);
250 	preempt_disable();
251 	time1 = get_cycles();
252 	for (i = 0; i < NR_LOOPS; i++) {
253 		local_irq_restore(flags);
254 		local_irq_save(flags);
255 	}
256 	time2 = get_cycles();
257 	local_irq_restore(flags);
258 	preempt_enable();
259 	time = time2 - time1;
260 
261 	printk(KERN_ALERT
262 	       "test results: time for disabling/enabling interrupts (STI/CLI)\n");
263 	printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS);
264 	printk(KERN_ALERT "total time: %llu\n", time);
265 	time = div_u64_rem(time, NR_LOOPS, &rem);
266 	printk(KERN_ALERT
267 	       "-> enabling/disabling interrupts (STI/CLI) takes %llu cycles\n",
268 	       time);
269 	printk(KERN_ALERT "test end\n");
270 }
271 
ltt_test_init(void)272 static int ltt_test_init(void)
273 {
274 	printk(KERN_ALERT "test init\n");
275 
276 	do_testbaseline();
277 	do_test_sync_cmpxchg();
278 	do_test_cmpxchg();
279 	do_test_sync_inc();
280 	do_test_inc();
281 	do_test_enable_int();
282 	do_test_disable_int();
283 	do_test_int();
284 	return -EAGAIN;		/* Fail will directly unload the module */
285 }
286 
ltt_test_exit(void)287 static void ltt_test_exit(void)
288 {
289 	printk(KERN_ALERT "test exit\n");
290 }
291 
292 module_init(ltt_test_init)
293     module_exit(ltt_test_exit)
294 
295     MODULE_LICENSE("GPL");
296 MODULE_AUTHOR("Mathieu Desnoyers");
297 MODULE_DESCRIPTION("Cmpxchg vs int Test");
298