Skip to content

Commit 1471ac6

Browse files
committed
time_bench_sample: measure spin_lock_irqsave + spin_unlock_irqrestore
Add some measurements to determine the cost of the spinlock variant that disable/enable interrupts, with save/restore flags. This should help us determine: 1. How expensive is this compared to the basic spinlock, 2. is a "manual" save/restore before spinlock as expensive or is there some advantage of the combined func call Measured on my laptop CPU i7-2620M CPU @ 2.70GHz: (kernel 3.17.8-200.fc20.x86_64) * 12.775 ns - "clean" spin_lock_unlock * 21.099 ns - irqsave variant spinlock * 22.808 ns - "manual" irqsave before spin_lock * 14.618 ns - "manual" local_irq_disable + spin_lock The clean spin_lock_unlock is 8.324 ns faster than irqsave variant. The irqsave variant is actually faster than expected, as the measurement of an isolated local_irq_save_restore were 13.256 ns. The difference to the "manual" irqsave is only 1.709 ns, which is approx the cost of an extra function call. If one can use the non-flags-save version of local_irq_disable, then one can save 6.481 ns (on this specific CPU and kernel config). Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
1 parent bd5a36a commit 1471ac6

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

kernel/lib/time_bench_sample.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,72 @@ static int time_lock_unlock(
4949
return loops_cnt;
5050
}
5151

52+
static int time_lock_unlock_irqsave(
53+
struct time_bench_record *rec, void *data)
54+
{
55+
int i;
56+
unsigned long flags;
57+
uint64_t loops_cnt = 0;
58+
59+
time_bench_start(rec);
60+
/** Loop to measure **/
61+
for (i = 0; i < rec->loops; i++) {
62+
spin_lock_irqsave(&my_lock, flags);
63+
loops_cnt++;
64+
barrier();
65+
spin_unlock_irqrestore(&my_lock, flags);
66+
}
67+
time_bench_stop(rec, loops_cnt);
68+
return loops_cnt;
69+
}
70+
71+
/* Purpose of this func, is to determine of the combined
72+
* spin_lock_irqsave() call is more efficient than "manually" irqsave
73+
* before calling lock.
74+
*/
75+
static int time_irqsave_before_lock(
76+
struct time_bench_record *rec, void *data)
77+
{
78+
int i;
79+
unsigned long flags;
80+
uint64_t loops_cnt = 0;
81+
82+
time_bench_start(rec);
83+
/** Loop to measure **/
84+
for (i = 0; i < rec->loops; i++) {
85+
local_irq_save(flags);
86+
spin_lock(&my_lock);
87+
loops_cnt++;
88+
barrier();
89+
spin_unlock(&my_lock);
90+
local_irq_restore(flags);
91+
}
92+
time_bench_stop(rec, loops_cnt);
93+
return loops_cnt;
94+
}
95+
96+
/* How much is there to save when using non-flags save variant of
97+
* disabling interrupts */
98+
static int time_simple_irq_disable_before_lock(
99+
struct time_bench_record *rec, void *data)
100+
{
101+
int i;
102+
uint64_t loops_cnt = 0;
103+
104+
time_bench_start(rec);
105+
/** Loop to measure **/
106+
for (i = 0; i < rec->loops; i++) {
107+
local_irq_disable();
108+
spin_lock(&my_lock);
109+
loops_cnt++;
110+
barrier();
111+
spin_unlock(&my_lock);
112+
local_irq_enable();
113+
}
114+
time_bench_stop(rec, loops_cnt);
115+
return loops_cnt;
116+
}
117+
52118
static int time_local_bh(
53119
struct time_bench_record *rec, void *data)
54120
{
@@ -203,6 +269,15 @@ int run_timing_tests(void)
203269
time_bench_loop(loops, 0, "spin_lock_unlock",
204270
NULL, time_lock_unlock);
205271

272+
time_bench_loop(loops/2, 0, "spin_lock_unlock_irqsave",
273+
NULL, time_lock_unlock_irqsave);
274+
275+
time_bench_loop(loops/2, 0, "irqsave_before_lock",
276+
NULL, time_irqsave_before_lock);
277+
278+
time_bench_loop(loops/2, 0, "simple_irq_disable_before_lock",
279+
NULL, time_simple_irq_disable_before_lock);
280+
206281
/* Cost for local_bh_{disable,enable}
207282
* 7.387 ns with CONFIG_PREEMPT=n PREEMPT_COUNT=n
208283
* 7.459 ns with CONFIG_PREEMPT=n PREEMPT_COUNT=y

0 commit comments

Comments
 (0)