Skip to content

Commit bb8caad

Browse files
committed
timers: Rework idle logic
To improve readability of the code, split base->idle calculation and expires calculation into separate parts. While at it, update the comment about timer base idle marking. Thereby the following subtle change happens if the next event is just one jiffy ahead and the tick was already stopped: Originally base->is_idle remains true in this situation. Now base->is_idle turns to false. This may spare an IPI if a timer is enqueued remotely to an idle CPU that is going to tick on the next jiffy. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Anna-Maria Behnsen <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Frederic Weisbecker <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7a39a50 commit bb8caad

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

kernel/time/timer.c

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,7 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
19241924
struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]);
19251925
u64 expires = KTIME_MAX;
19261926
unsigned long nextevt;
1927+
bool was_idle;
19271928

19281929
/*
19291930
* Pretend that there is no timer pending if the cpu is offline.
@@ -1943,27 +1944,26 @@ u64 get_next_timer_interrupt(unsigned long basej, u64 basem)
19431944
*/
19441945
__forward_timer_base(base, basej);
19451946

1946-
if (time_before_eq(nextevt, basej)) {
1947-
expires = basem;
1948-
if (base->is_idle) {
1949-
base->is_idle = false;
1950-
trace_timer_base_idle(false, base->cpu);
1951-
}
1952-
} else {
1953-
if (base->timers_pending)
1954-
expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
1955-
/*
1956-
* If we expect to sleep more than a tick, mark the base idle.
1957-
* Also the tick is stopped so any added timer must forward
1958-
* the base clk itself to keep granularity small. This idle
1959-
* logic is only maintained for the BASE_STD base, deferrable
1960-
* timers may still see large granularity skew (by design).
1961-
*/
1962-
if ((expires - basem) > TICK_NSEC && !base->is_idle) {
1963-
base->is_idle = true;
1964-
trace_timer_base_idle(true, base->cpu);
1965-
}
1947+
if (base->timers_pending) {
1948+
/* If we missed a tick already, force 0 delta */
1949+
if (time_before(nextevt, basej))
1950+
nextevt = basej;
1951+
expires = basem + (u64)(nextevt - basej) * TICK_NSEC;
19661952
}
1953+
1954+
/*
1955+
* Base is idle if the next event is more than a tick away.
1956+
*
1957+
* If the base is marked idle then any timer add operation must forward
1958+
* the base clk itself to keep granularity small. This idle logic is
1959+
* only maintained for the BASE_STD base, deferrable timers may still
1960+
* see large granularity skew (by design).
1961+
*/
1962+
was_idle = base->is_idle;
1963+
base->is_idle = time_after(nextevt, basej + 1);
1964+
if (was_idle != base->is_idle)
1965+
trace_timer_base_idle(base->is_idle, base->cpu);
1966+
19671967
raw_spin_unlock(&base->lock);
19681968

19691969
return cmp_next_hrtimer_event(basem, expires);

0 commit comments

Comments
 (0)