]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
sched/hrtick: Avoid tiny hrtick rearms
authorThomas Gleixner <tglx@kernel.org>
Tue, 24 Feb 2026 16:35:56 +0000 (17:35 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 27 Feb 2026 15:40:05 +0000 (16:40 +0100)
Tiny adjustments to the hrtick expiry time below 5 microseconds are just
causing extra work for no real value. Filter them out when restarting the
hrtick.

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

index a868f0a4159e7c6291a5a1747249f9ebe3988558..5bc446e1b3d66d41ad23ebce20764ecac981dd13 100644 (file)
@@ -903,12 +903,24 @@ static enum hrtimer_restart hrtick(struct hrtimer *timer)
        return HRTIMER_NORESTART;
 }
 
-static void __hrtick_restart(struct rq *rq)
+static inline bool hrtick_needs_rearm(struct hrtimer *timer, ktime_t expires)
+{
+       /*
+        * Queued is false when the timer is not started or currently
+        * running the callback. In both cases, restart. If queued check
+        * whether the expiry time actually changes substantially.
+        */
+       return !hrtimer_is_queued(timer) ||
+               abs(expires - hrtimer_get_expires(timer)) > 5000;
+}
+
+static void hrtick_cond_restart(struct rq *rq)
 {
        struct hrtimer *timer = &rq->hrtick_timer;
        ktime_t time = rq->hrtick_time;
 
-       hrtimer_start(timer, time, HRTIMER_MODE_ABS_PINNED_HARD);
+       if (hrtick_needs_rearm(timer, time))
+               hrtimer_start(timer, time, HRTIMER_MODE_ABS_PINNED_HARD);
 }
 
 /*
@@ -920,7 +932,7 @@ static void __hrtick_start(void *arg)
        struct rq_flags rf;
 
        rq_lock(rq, &rf);
-       __hrtick_restart(rq);
+       hrtick_cond_restart(rq);
        rq_unlock(rq, &rf);
 }
 
@@ -950,9 +962,11 @@ void hrtick_start(struct rq *rq, u64 delay)
        }
 
        rq->hrtick_time = ktime_add_ns(ktime_get(), delta);
+       if (!hrtick_needs_rearm(&rq->hrtick_timer, rq->hrtick_time))
+               return;
 
        if (rq == this_rq())
-               __hrtick_restart(rq);
+               hrtimer_start(&rq->hrtick_timer, rq->hrtick_time, HRTIMER_MODE_ABS_PINNED_HARD);
        else
                smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
 }
@@ -966,7 +980,7 @@ static inline void hrtick_schedule_exit(struct rq *rq)
 {
        if (rq->hrtick_sched & HRTICK_SCHED_START) {
                rq->hrtick_time = ktime_add_ns(ktime_get(), rq->hrtick_delay);
-               __hrtick_restart(rq);
+               hrtick_cond_restart(rq);
        } else if (idle_rq(rq)) {
                /*
                 * No need for using hrtimer_is_active(). The timer is CPU local