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