Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <tglx@linutronix.de>
Signed-off-by: Anna-Maria Behnsen <anna-maria@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Link: https://lore.kernel.org/r/20231201092654.34614-12-anna-maria@linutronix.de

+20 -20
+20 -20
kernel/time/timer.c
··· 1924 1924 struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); 1925 1925 u64 expires = KTIME_MAX; 1926 1926 unsigned long nextevt; 1927 + bool was_idle; 1927 1928 1928 1929 /* 1929 1930 * Pretend that there is no timer pending if the cpu is offline. ··· 1944 1943 */ 1945 1944 __forward_timer_base(base, basej); 1946 1945 1947 - if (time_before_eq(nextevt, basej)) { 1948 - expires = basem; 1949 - if (base->is_idle) { 1950 - base->is_idle = false; 1951 - trace_timer_base_idle(false, base->cpu); 1952 - } 1953 - } else { 1954 - if (base->timers_pending) 1955 - expires = basem + (u64)(nextevt - basej) * TICK_NSEC; 1956 - /* 1957 - * If we expect to sleep more than a tick, mark the base idle. 1958 - * Also the tick is stopped so any added timer must forward 1959 - * the base clk itself to keep granularity small. This idle 1960 - * logic is only maintained for the BASE_STD base, deferrable 1961 - * timers may still see large granularity skew (by design). 1962 - */ 1963 - if ((expires - basem) > TICK_NSEC && !base->is_idle) { 1964 - base->is_idle = true; 1965 - trace_timer_base_idle(true, base->cpu); 1966 - } 1946 + if (base->timers_pending) { 1947 + /* If we missed a tick already, force 0 delta */ 1948 + if (time_before(nextevt, basej)) 1949 + nextevt = basej; 1950 + expires = basem + (u64)(nextevt - basej) * TICK_NSEC; 1967 1951 } 1952 + 1953 + /* 1954 + * Base is idle if the next event is more than a tick away. 1955 + * 1956 + * If the base is marked idle then any timer add operation must forward 1957 + * the base clk itself to keep granularity small. This idle logic is 1958 + * only maintained for the BASE_STD base, deferrable timers may still 1959 + * see large granularity skew (by design). 1960 + */ 1961 + was_idle = base->is_idle; 1962 + base->is_idle = time_after(nextevt, basej + 1); 1963 + if (was_idle != base->is_idle) 1964 + trace_timer_base_idle(base->is_idle, base->cpu); 1965 + 1968 1966 raw_spin_unlock(&base->lock); 1969 1967 1970 1968 return cmp_next_hrtimer_event(basem, expires);