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