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.

tick/sched: Avoid hrtimer_cancel/start() sequence

The sequence of cancel and start is inefficient. It has to do the timer
lock/unlock twice and in the worst case has to reprogram the underlying
clock event device twice.

The reason why it is done this way is the usage of hrtimer_forward_now(),
which requires the timer to be inactive.

But that can be completely avoided as the forward can be done on a variable
and does not need any of the overrun accounting provided by
hrtimer_forward_now().

Implement a trivial forwarding mechanism and replace the cancel/reprogram
sequence with hrtimer_start(..., new_expiry).

For the non high resolution case the timer is not actually armed, but used
for storage so that code checking for expiry times can unconditially look
it up in the timer. So it is safe for that case to set the new expiry time
directly.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.542178086@kernel.org

authored by

Thomas Gleixner and committed by
Peter Zijlstra
adcec6a7 0abec32a

+20 -7
+20 -7
kernel/time/tick-sched.c
··· 864 864 } 865 865 EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); 866 866 867 + /* Simplified variant of hrtimer_forward_now() */ 868 + static ktime_t tick_forward_now(ktime_t expires, ktime_t now) 869 + { 870 + ktime_t delta = now - expires; 871 + 872 + if (likely(delta < TICK_NSEC)) 873 + return expires + TICK_NSEC; 874 + 875 + expires += TICK_NSEC * ktime_divns(delta, TICK_NSEC); 876 + if (expires > now) 877 + return expires; 878 + return expires + TICK_NSEC; 879 + } 880 + 867 881 static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) 868 882 { 869 - hrtimer_cancel(&ts->sched_timer); 870 - hrtimer_set_expires(&ts->sched_timer, ts->last_tick); 883 + ktime_t expires = ts->last_tick; 871 884 872 - /* Forward the time to expire in the future */ 873 - hrtimer_forward(&ts->sched_timer, now, TICK_NSEC); 885 + if (now >= expires) 886 + expires = tick_forward_now(expires, now); 874 887 875 888 if (tick_sched_flag_test(ts, TS_FLAG_HIGHRES)) { 876 - hrtimer_start_expires(&ts->sched_timer, 877 - HRTIMER_MODE_ABS_PINNED_HARD); 889 + hrtimer_start(&ts->sched_timer, expires, HRTIMER_MODE_ABS_PINNED_HARD); 878 890 } else { 879 - tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1); 891 + hrtimer_set_expires(&ts->sched_timer, expires); 892 + tick_program_event(expires, 1); 880 893 } 881 894 882 895 /*