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 | |
f57afc80 |
19 | static void do_test_sync_cmpxchg(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 | #ifdef CONFIG_X86_32 |
32 | ret = sync_cmpxchg(&test_val, 0, 0); |
33 | #else |
34 | ret = cmpxchg(&test_val, 0, 0); |
35 | #endif |
36 | } |
37 | time2 = get_cycles(); |
38 | local_irq_restore(flags); |
39 | preempt_enable(); |
40 | time = time2 - time1; |
41 | |
42 | printk(KERN_ALERT "test results: time for locked cmpxchg\n"); |
43 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
44 | printk(KERN_ALERT "total time: %llu\n", time); |
45 | time = div_long_long_rem(time, NR_LOOPS, &rem); |
46 | printk(KERN_ALERT "-> locked cmpxchg takes %llu cycles\n", time); |
47 | printk(KERN_ALERT "test end\n"); |
48 | } |
49 | |
421991b0 |
50 | static void do_test_cmpxchg(void) |
51 | { |
52 | int ret; |
53 | long flags; |
54 | unsigned int i; |
55 | cycles_t time1, time2, time; |
56 | long rem; |
57 | |
58 | local_irq_save(flags); |
59 | preempt_disable(); |
60 | time1 = get_cycles(); |
61 | for (i = 0; i < NR_LOOPS; i++) { |
62 | ret = cmpxchg_local(&test_val, 0, 0); |
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 non 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 "-> non locked cmpxchg takes %llu cycles\n", time); |
74 | printk(KERN_ALERT "test end\n"); |
75 | } |
76 | |
77 | /* |
78 | * This test will have a higher standard deviation due to incoming interrupts. |
79 | */ |
80 | static void do_test_enable_int(void) |
81 | { |
82 | long flags; |
83 | unsigned int i; |
84 | cycles_t time1, time2, time; |
85 | long rem; |
86 | |
87 | local_irq_save(flags); |
88 | preempt_disable(); |
89 | time1 = get_cycles(); |
90 | for (i = 0; i < NR_LOOPS; i++) { |
91 | local_irq_restore(flags); |
92 | } |
93 | time2 = get_cycles(); |
94 | local_irq_restore(flags); |
95 | preempt_enable(); |
96 | time = time2 - time1; |
97 | |
98 | printk(KERN_ALERT "test results: time for enabling interrupts (STI)\n"); |
99 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
100 | printk(KERN_ALERT "total time: %llu\n", time); |
101 | time = div_long_long_rem(time, NR_LOOPS, &rem); |
102 | printk(KERN_ALERT "-> enabling interrupts (STI) takes %llu cycles\n", |
103 | time); |
104 | printk(KERN_ALERT "test end\n"); |
105 | } |
106 | |
107 | static void do_test_disable_int(void) |
108 | { |
109 | unsigned long flags, flags2; |
110 | unsigned int i; |
111 | cycles_t time1, time2, time; |
112 | long rem; |
113 | |
114 | local_irq_save(flags); |
115 | preempt_disable(); |
116 | time1 = get_cycles(); |
117 | for ( i = 0; i < NR_LOOPS; i++) { |
118 | local_irq_save(flags2); |
119 | } |
120 | time2 = get_cycles(); |
121 | local_irq_restore(flags); |
122 | preempt_enable(); |
123 | time = time2 - time1; |
124 | |
125 | printk(KERN_ALERT "test results: time for disabling interrupts (CLI)\n"); |
126 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
127 | printk(KERN_ALERT "total time: %llu\n", time); |
128 | time = div_long_long_rem(time, NR_LOOPS, &rem); |
7de49e3a |
129 | printk(KERN_ALERT "-> disabling interrupts (CLI) takes %llu cycles\n", |
421991b0 |
130 | time); |
131 | printk(KERN_ALERT "test end\n"); |
132 | } |
133 | |
236f9aae |
134 | static void do_test_int(void) |
135 | { |
136 | long flags; |
137 | unsigned int i; |
138 | cycles_t time1, time2, time; |
139 | long rem; |
140 | |
141 | local_irq_save(flags); |
142 | preempt_disable(); |
143 | time1 = get_cycles(); |
144 | for (i = 0; i < NR_LOOPS; i++) { |
145 | local_irq_restore(flags); |
146 | local_irq_save(flags); |
147 | } |
148 | time2 = get_cycles(); |
149 | local_irq_restore(flags); |
150 | preempt_enable(); |
151 | time = time2 - time1; |
152 | |
153 | printk(KERN_ALERT "test results: time for disabling/enabling interrupts (STI/CLI)\n"); |
154 | printk(KERN_ALERT "number of loops: %d\n", NR_LOOPS); |
155 | printk(KERN_ALERT "total time: %llu\n", time); |
156 | time = div_long_long_rem(time, NR_LOOPS, &rem); |
157 | printk(KERN_ALERT "-> enabling/disabling interrupts (STI/CLI) takes %llu cycles\n", |
158 | time); |
159 | printk(KERN_ALERT "test end\n"); |
160 | } |
161 | |
421991b0 |
162 | |
163 | |
164 | static int ltt_test_init(void) |
165 | { |
166 | printk(KERN_ALERT "test init\n"); |
167 | |
fa2b47dd |
168 | do_test_sync_cmpxchg(); |
421991b0 |
169 | do_test_cmpxchg(); |
170 | do_test_enable_int(); |
171 | do_test_disable_int(); |
236f9aae |
172 | do_test_int(); |
421991b0 |
173 | return -EAGAIN; /* Fail will directly unload the module */ |
174 | } |
175 | |
176 | static void ltt_test_exit(void) |
177 | { |
178 | printk(KERN_ALERT "test exit\n"); |
179 | } |
180 | |
181 | module_init(ltt_test_init) |
182 | module_exit(ltt_test_exit) |
183 | |
184 | MODULE_LICENSE("GPL"); |
185 | MODULE_AUTHOR("Mathieu Desnoyers"); |
186 | MODULE_DESCRIPTION("Cmpxchg vs int Test"); |
187 | |