[tip: timers/nohz] tick/nohz: Avoid unused timekeeping_max_deferment() calls
From: tip-bot2 for Usama Arif
Date: Tue Sep 29 2026 - 15:09:26 EST
The following commit has been merged into the timers/nohz branch of tip:
Commit-ID: d305927765cf6025bc11db9d96c06ea663230ddd
Gitweb: https://git.kernel.org/tip/d305927765cf6025bc11db9d96c06ea663230ddd
Author: Usama Arif <usama.arif@xxxxxxxxx>
AuthorDate: Fri, 18 Sep 2026 06:34:08 -07:00
Committer: Thomas Gleixner <tglx@xxxxxxxxxx>
CommitterDate: Tue, 29 Sep 2026 21:00:08 +02:00
tick/nohz: Avoid unused timekeeping_max_deferment() calls
tick_nohz_next_event() limits a CPU's sleep interval to the maximum
deferment supported by the current clocksource when that CPU owns the
do_timer() duty. If the duty is unassigned, the limit also applies when
the CPU's TS_FLAG_DO_TIMER_LAST flag is set.
After the early timer checks, the function currently reads the maximum
deferment unconditionally. It then replaces the result with KTIME_MAX
unless one of the two conditions above applies.
timekeeping_max_deferment() performs a seqcount-protected read of the
shared timekeeper and follows its clocksource pointer. Check the do_timer
state first and avoid this work when the result would be discarded. This
leaves the resulting expiry unchanged and reduces accesses to timekeeper
data that is modified regularly.
On x86-64 this removes 18-20 dynamically executed instructions, including
the call, from the common non-owner path when the seqcount does not retry.
Signed-off-by: Usama Arif <usama.arif@xxxxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxx>
Reviewed-by: Rik van Riel <riel@xxxxxxxxxxx>
Link: https://patch.msgid.link/20260918133408.2834751-1-usama.arif@xxxxxxxxx
---
kernel/time/tick-sched.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index c8f2c4a..a7893a0 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -816,7 +816,7 @@ u64 get_jiffies_update(unsigned long *basej)
*/
static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
{
- u64 basemono, next_tick, delta, expires;
+ u64 basemono, next_tick, expires;
unsigned long basejiff;
int tick_cpu;
@@ -856,8 +856,7 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
* If the tick is due in the next period, keep it ticking or
* force prod the timer.
*/
- delta = next_tick - basemono;
- if (delta <= (u64)TICK_NSEC) {
+ if (next_tick - basemono <= (u64)TICK_NSEC) {
/*
* We've not stopped the tick yet, and there's a timer in the
* next period, so no point in stopping it either, bail.
@@ -873,17 +872,19 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
* the sleep time to the timekeeping 'max_deferment' value.
* Otherwise we can sleep as long as we want.
*/
- delta = timekeeping_max_deferment();
tick_cpu = READ_ONCE(tick_do_timer_cpu);
if (tick_cpu != cpu &&
- (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST)))
- delta = KTIME_MAX;
-
- /* Calculate the next expiry time */
- if (delta < (KTIME_MAX - basemono))
- expires = basemono + delta;
- else
+ (tick_cpu != TICK_DO_TIMER_NONE || !tick_sched_flag_test(ts, TS_FLAG_DO_TIMER_LAST))) {
expires = KTIME_MAX;
+ } else {
+ expires = timekeeping_max_deferment();
+
+ /* Calculate the next expiry time */
+ if (expires < (KTIME_MAX - basemono))
+ expires += basemono;
+ else
+ expires = KTIME_MAX;
+ }
ts->timer_expires = min_t(u64, expires, next_tick);