Skip to content

Commit 31cd0e1

Browse files
Frederic WeisbeckerKAGA-KOKO
authored andcommitted
timers: Recalculate next timer interrupt only when necessary
The nohz tick code recalculates the timer wheel's next expiry on each idle loop iteration. On the other hand, the base next expiry is now always cached and updated upon timer enqueue and execution. Only timer dequeue may leave base->next_expiry out of date (but then its stale value won't ever go past the actual next expiry to be recalculated). Since recalculating the next_expiry isn't a free operation, especially when the last wheel level is reached to find out that no timer has been enqueued at all, reuse the next expiry cache when it is known to be reliable, which it is most of the time. Signed-off-by: Frederic Weisbecker <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 1b7efaa commit 31cd0e1

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

kernel/time/timer.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ struct timer_base {
204204
unsigned long clk;
205205
unsigned long next_expiry;
206206
unsigned int cpu;
207+
bool next_expiry_recalc;
207208
bool is_idle;
208209
DECLARE_BITMAP(pending_map, WHEEL_SIZE);
209210
struct hlist_head vectors[WHEEL_SIZE];
@@ -593,6 +594,7 @@ static void enqueue_timer(struct timer_base *base, struct timer_list *timer,
593594
* can reevaluate the wheel:
594595
*/
595596
base->next_expiry = bucket_expiry;
597+
base->next_expiry_recalc = false;
596598
trigger_dyntick_cpu(base, timer);
597599
}
598600
}
@@ -836,8 +838,10 @@ static int detach_if_pending(struct timer_list *timer, struct timer_base *base,
836838
if (!timer_pending(timer))
837839
return 0;
838840

839-
if (hlist_is_singular_node(&timer->entry, base->vectors + idx))
841+
if (hlist_is_singular_node(&timer->entry, base->vectors + idx)) {
840842
__clear_bit(idx, base->pending_map);
843+
base->next_expiry_recalc = true;
844+
}
841845

842846
detach_timer(timer, clear_pending);
843847
return 1;
@@ -1571,6 +1575,9 @@ static unsigned long __next_timer_interrupt(struct timer_base *base)
15711575
clk >>= LVL_CLK_SHIFT;
15721576
clk += adj;
15731577
}
1578+
1579+
base->next_expiry_recalc = false;
1580+
15741581
return next;
15751582
}
15761583

@@ -1631,9 +1638,11 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
16311638
return expires;
16321639

16331640
raw_spin_lock(&base->lock);
1634-
nextevt = __next_timer_interrupt(base);
1641+
if (base->next_expiry_recalc)
1642+
base->next_expiry = __next_timer_interrupt(base);
1643+
nextevt = base->next_expiry;
16351644
is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA);
1636-
base->next_expiry = nextevt;
1645+
16371646
/*
16381647
* We have a fresh next event. Check whether we can forward the
16391648
* base. We can only do that when @basej is past base->clk
@@ -1725,6 +1734,12 @@ static inline void __run_timers(struct timer_base *base)
17251734
while (time_after_eq(jiffies, base->clk) &&
17261735
time_after_eq(jiffies, base->next_expiry)) {
17271736
levels = collect_expired_timers(base, heads);
1737+
/*
1738+
* The only possible reason for not finding any expired
1739+
* timer at this clk is that all matching timers have been
1740+
* dequeued.
1741+
*/
1742+
WARN_ON_ONCE(!levels && !base->next_expiry_recalc);
17281743
base->clk++;
17291744
base->next_expiry = __next_timer_interrupt(base);
17301745

0 commit comments

Comments
 (0)