* [patch 01/48] sched/eevdf: Fix HRTICK duration
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:37 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra
2026-02-24 16:35 ` [patch 02/48] sched/fair: Simplify hrtick_update() Thomas Gleixner
` (48 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
From: Peter Zijlstra <peterz@infradead.org>
The nominal duration for an EEVDF task to run is until its deadline. At
which point the deadline is moved ahead and a new task selection is done.
Try and predict the time 'lost' to higher scheduling classes. Since this is
an estimate, the timer can be both early or late. In case it is early
task_tick_fair() will take the !need_resched() path and restarts the timer.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
---
kernel/sched/fair.c | 43 ++++++++++++++++++++++++++++---------------
1 file changed, 28 insertions(+), 15 deletions(-)
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6735,21 +6735,37 @@ static inline void sched_fair_update_sto
static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
{
struct sched_entity *se = &p->se;
+ unsigned long scale = 1024;
+ unsigned long util = 0;
+ u64 vdelta;
+ u64 delta;
WARN_ON_ONCE(task_rq(p) != rq);
- if (rq->cfs.h_nr_queued > 1) {
- u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
- u64 slice = se->slice;
- s64 delta = slice - ran;
-
- if (delta < 0) {
- if (task_current_donor(rq, p))
- resched_curr(rq);
- return;
- }
- hrtick_start(rq, delta);
+ if (rq->cfs.h_nr_queued <= 1)
+ return;
+
+ /*
+ * Compute time until virtual deadline
+ */
+ vdelta = se->deadline - se->vruntime;
+ if ((s64)vdelta < 0) {
+ if (task_current_donor(rq, p))
+ resched_curr(rq);
+ return;
}
+ delta = (se->load.weight * vdelta) / NICE_0_LOAD;
+
+ /*
+ * Correct for instantaneous load of other classes.
+ */
+ util += cpu_util_irq(rq);
+ if (util && util < 1024) {
+ scale *= 1024;
+ scale /= (1024 - util);
+ }
+
+ hrtick_start(rq, (scale * delta) / 1024);
}
/*
@@ -13365,11 +13381,8 @@ static void task_tick_fair(struct rq *rq
entity_tick(cfs_rq, se, queued);
}
- if (queued) {
- if (!need_resched())
- hrtick_start_fair(rq, curr);
+ if (queued)
return;
- }
if (static_branch_unlikely(&sched_numa_balancing))
task_tick_numa(rq, curr);
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched/eevdf: Fix HRTICK duration
2026-02-24 16:35 ` [patch 01/48] sched/eevdf: Fix HRTICK duration Thomas Gleixner
@ 2026-02-28 15:37 ` tip-bot2 for Peter Zijlstra
2026-03-20 14:59 ` Shrikanth Hegde
0 siblings, 1 reply; 130+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2026-02-28 15:37 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Thomas Gleixner, Juri Lelli, x86,
linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: 558c18d3fbb6c5b9c0b42629d7fe34476363ac00
Gitweb: https://git.kernel.org/tip/558c18d3fbb6c5b9c0b42629d7fe34476363ac00
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 24 Feb 2026 17:35:17 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:03 +01:00
sched/eevdf: Fix HRTICK duration
The nominal duration for an EEVDF task to run is until its deadline. At
which point the deadline is moved ahead and a new task selection is done.
Try and predict the time 'lost' to higher scheduling classes. Since this is
an estimate, the timer can be both early or late. In case it is early
task_tick_fair() will take the !need_resched() path and restarts the timer.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
Link: https://patch.msgid.link/20260224163428.798198874@kernel.org
---
kernel/sched/fair.c | 41 +++++++++++++++++++++++++++--------------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index eea99ec..247fecd 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6735,21 +6735,37 @@ static inline void sched_fair_update_stop_tick(struct rq *rq, struct task_struct
static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
{
struct sched_entity *se = &p->se;
+ unsigned long scale = 1024;
+ unsigned long util = 0;
+ u64 vdelta;
+ u64 delta;
WARN_ON_ONCE(task_rq(p) != rq);
- if (rq->cfs.h_nr_queued > 1) {
- u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
- u64 slice = se->slice;
- s64 delta = slice - ran;
+ if (rq->cfs.h_nr_queued <= 1)
+ return;
- if (delta < 0) {
- if (task_current_donor(rq, p))
- resched_curr(rq);
- return;
- }
- hrtick_start(rq, delta);
+ /*
+ * Compute time until virtual deadline
+ */
+ vdelta = se->deadline - se->vruntime;
+ if ((s64)vdelta < 0) {
+ if (task_current_donor(rq, p))
+ resched_curr(rq);
+ return;
}
+ delta = (se->load.weight * vdelta) / NICE_0_LOAD;
+
+ /*
+ * Correct for instantaneous load of other classes.
+ */
+ util += cpu_util_irq(rq);
+ if (util && util < 1024) {
+ scale *= 1024;
+ scale /= (1024 - util);
+ }
+
+ hrtick_start(rq, (scale * delta) / 1024);
}
/*
@@ -13365,11 +13381,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
entity_tick(cfs_rq, se, queued);
}
- if (queued) {
- if (!need_resched())
- hrtick_start_fair(rq, curr);
+ if (queued)
return;
- }
if (static_branch_unlikely(&sched_numa_balancing))
task_tick_numa(rq, curr);
^ permalink raw reply related [flat|nested] 130+ messages in thread* Re: [tip: sched/hrtick] sched/eevdf: Fix HRTICK duration
2026-02-28 15:37 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra
@ 2026-03-20 14:59 ` Shrikanth Hegde
2026-03-20 15:38 ` Peter Zijlstra
0 siblings, 1 reply; 130+ messages in thread
From: Shrikanth Hegde @ 2026-03-20 14:59 UTC (permalink / raw)
To: Thomas Gleixner, Peter Zijlstra (Intel)
Cc: linux-kernel, Juri Lelli, x86, linux-tip-commits
Sorry for very very late reply. I was trying to go through this.
On 2/28/26 9:07 PM, tip-bot2 for Peter Zijlstra wrote:
> The following commit has been merged into the sched/hrtick branch of tip:
>
> Commit-ID: 558c18d3fbb6c5b9c0b42629d7fe34476363ac00
> Gitweb: https://git.kernel.org/tip/558c18d3fbb6c5b9c0b42629d7fe34476363ac00
> Author: Peter Zijlstra <peterz@infradead.org>
> AuthorDate: Tue, 24 Feb 2026 17:35:17 +01:00
> Committer: Peter Zijlstra <peterz@infradead.org>
> CommitterDate: Fri, 27 Feb 2026 16:40:03 +01:00
>
> sched/eevdf: Fix HRTICK duration
>
> The nominal duration for an EEVDF task to run is until its deadline. At
> which point the deadline is moved ahead and a new task selection is done.
>
> Try and predict the time 'lost' to higher scheduling classes. Since this is
> an estimate, the timer can be both early or late. In case it is early
> task_tick_fair() will take the !need_resched() path and restarts the timer.
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Signed-off-by: Thomas Gleixner <tglx@kernel.org>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
> Link: https://patch.msgid.link/20260224163428.798198874@kernel.org
> ---
> kernel/sched/fair.c | 41 +++++++++++++++++++++++++++--------------
> 1 file changed, 27 insertions(+), 14 deletions(-)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index eea99ec..247fecd 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -6735,21 +6735,37 @@ static inline void sched_fair_update_stop_tick(struct rq *rq, struct task_struct
> static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
> {
> struct sched_entity *se = &p->se;
> + unsigned long scale = 1024;
> + unsigned long util = 0;
> + u64 vdelta;
> + u64 delta;
>
> WARN_ON_ONCE(task_rq(p) != rq);
>
> - if (rq->cfs.h_nr_queued > 1) {
> - u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
> - u64 slice = se->slice;
> - s64 delta = slice - ran;
> + if (rq->cfs.h_nr_queued <= 1)
> + return;
>
> - if (delta < 0) {
> - if (task_current_donor(rq, p))
> - resched_curr(rq);
> - return;
> - }
> - hrtick_start(rq, delta);
> + /*
> + * Compute time until virtual deadline
> + */
> + vdelta = se->deadline - se->vruntime;
> + if ((s64)vdelta < 0) {
> + if (task_current_donor(rq, p))
> + resched_curr(rq);
> + return;
> }
> + delta = (se->load.weight * vdelta) / NICE_0_LOAD;
> +
> + /*
> + * Correct for instantaneous load of other classes.
> + */
> + util += cpu_util_irq(rq);
> + if (util && util < 1024) {
> + scale *= 1024;
> + scale /= (1024 - util);
> + }
Comments/Changelog says other classes.
Then why not consider cpu_util_dl, cpu_util_rq too?
Is there a reason why these are not taken into calculations?
> +
> + hrtick_start(rq, (scale * delta) / 1024);
> }
>
> /*
> @@ -13365,11 +13381,8 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
> entity_tick(cfs_rq, se, queued);
> }
>
> - if (queued) {
> - if (!need_resched())
> - hrtick_start_fair(rq, curr);
> + if (queued)
> return;
> - }
>
> if (static_branch_unlikely(&sched_numa_balancing))
> task_tick_numa(rq, curr);
^ permalink raw reply [flat|nested] 130+ messages in thread* Re: [tip: sched/hrtick] sched/eevdf: Fix HRTICK duration
2026-03-20 14:59 ` Shrikanth Hegde
@ 2026-03-20 15:38 ` Peter Zijlstra
2026-03-20 15:40 ` Shrikanth Hegde
0 siblings, 1 reply; 130+ messages in thread
From: Peter Zijlstra @ 2026-03-20 15:38 UTC (permalink / raw)
To: Shrikanth Hegde
Cc: Thomas Gleixner, linux-kernel, Juri Lelli, x86, linux-tip-commits
On Fri, Mar 20, 2026 at 08:29:11PM +0530, Shrikanth Hegde wrote:
> > + /*
> > + * Correct for instantaneous load of other classes.
> > + */
> > + util += cpu_util_irq(rq);
> > + if (util && util < 1024) {
> > + scale *= 1024;
> > + scale /= (1024 - util);
> > + }
>
> Comments/Changelog says other classes.
>
> Then why not consider cpu_util_dl, cpu_util_rq too?
> Is there a reason why these are not taken into calculations?
Damn, forgot to fix that comment.
So yes, it used to correct for those, but then I realized that the
hrtick is strictly for current. So running RT/DL tasks means current is
different.
The only thing that can actually interrupt current and soak time are
interrupts.
Does that make sense?
^ permalink raw reply [flat|nested] 130+ messages in thread* Re: [tip: sched/hrtick] sched/eevdf: Fix HRTICK duration
2026-03-20 15:38 ` Peter Zijlstra
@ 2026-03-20 15:40 ` Shrikanth Hegde
0 siblings, 0 replies; 130+ messages in thread
From: Shrikanth Hegde @ 2026-03-20 15:40 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Thomas Gleixner, linux-kernel, Juri Lelli, x86, linux-tip-commits
On 3/20/26 9:08 PM, Peter Zijlstra wrote:
> On Fri, Mar 20, 2026 at 08:29:11PM +0530, Shrikanth Hegde wrote:
>
>>> + /*
>>> + * Correct for instantaneous load of other classes.
>>> + */
>>> + util += cpu_util_irq(rq);
>>> + if (util && util < 1024) {
>>> + scale *= 1024;
>>> + scale /= (1024 - util);
>>> + }
>>
>> Comments/Changelog says other classes.
>>
>> Then why not consider cpu_util_dl, cpu_util_rq too?
>> Is there a reason why these are not taken into calculations?
>
> Damn, forgot to fix that comment.
>
> So yes, it used to correct for those, but then I realized that the
> hrtick is strictly for current. So running RT/DL tasks means current is
> different.
>
> The only thing that can actually interrupt current and soak time are
> interrupts.
>
> Does that make sense?
Yes. That helps.
^ permalink raw reply [flat|nested] 130+ messages in thread
* [patch 02/48] sched/fair: Simplify hrtick_update()
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
2026-02-24 16:35 ` [patch 01/48] sched/eevdf: Fix HRTICK duration Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:37 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra (Intel)
2026-02-24 16:35 ` [patch 03/48] sched/fair: Make hrtick resched hard Thomas Gleixner
` (47 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
From: Peter Zijlstra (Intel) <peterz@infradead.org>
hrtick_update() was needed when the slice depended on nr_running, all that
code is gone. All that remains is starting the hrtick when nr_running
becomes more than 1.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
---
kernel/sched/fair.c | 12 ++++--------
kernel/sched/sched.h | 4 ++++
2 files changed, 8 insertions(+), 8 deletions(-)
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6769,9 +6769,7 @@ static void hrtick_start_fair(struct rq
}
/*
- * called from enqueue/dequeue and updates the hrtick when the
- * current task is from our class and nr_running is low enough
- * to matter.
+ * Called on enqueue to start the hrtick when h_nr_queued becomes more than 1.
*/
static void hrtick_update(struct rq *rq)
{
@@ -6780,6 +6778,9 @@ static void hrtick_update(struct rq *rq)
if (!hrtick_enabled_fair(rq) || donor->sched_class != &fair_sched_class)
return;
+ if (hrtick_active(rq))
+ return;
+
hrtick_start_fair(rq, donor);
}
#else /* !CONFIG_SCHED_HRTICK: */
@@ -7102,9 +7103,6 @@ static int dequeue_entities(struct rq *r
WARN_ON_ONCE(!task_sleep);
WARN_ON_ONCE(p->on_rq != 1);
- /* Fix-up what dequeue_task_fair() skipped */
- hrtick_update(rq);
-
/*
* Fix-up what block_task() skipped.
*
@@ -7138,8 +7136,6 @@ static bool dequeue_task_fair(struct rq
/*
* Must not reference @p after dequeue_entities(DEQUEUE_DELAYED).
*/
-
- hrtick_update(rq);
return true;
}
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -3041,6 +3041,10 @@ static inline int hrtick_enabled_dl(stru
}
extern void hrtick_start(struct rq *rq, u64 delay);
+static inline bool hrtick_active(struct rq *rq)
+{
+ return hrtimer_active(&rq->hrtick_timer);
+}
#else /* !CONFIG_SCHED_HRTICK: */
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched/fair: Simplify hrtick_update()
2026-02-24 16:35 ` [patch 02/48] sched/fair: Simplify hrtick_update() Thomas Gleixner
@ 2026-02-28 15:37 ` tip-bot2 for Peter Zijlstra (Intel)
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Peter Zijlstra (Intel) @ 2026-02-28 15:37 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: 97015376642f3cb7aa5c3cdb13bf094e94fbcd81
Gitweb: https://git.kernel.org/tip/97015376642f3cb7aa5c3cdb13bf094e94fbcd81
Author: Peter Zijlstra (Intel) <peterz@infradead.org>
AuthorDate: Tue, 24 Feb 2026 17:35:22 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:03 +01:00
sched/fair: Simplify hrtick_update()
hrtick_update() was needed when the slice depended on nr_running, all that
code is gone. All that remains is starting the hrtick when nr_running
becomes more than 1.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163428.866374835@kernel.org
---
kernel/sched/fair.c | 12 ++++--------
kernel/sched/sched.h | 4 ++++
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 247fecd..0b6ce88 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6769,9 +6769,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
}
/*
- * called from enqueue/dequeue and updates the hrtick when the
- * current task is from our class and nr_running is low enough
- * to matter.
+ * Called on enqueue to start the hrtick when h_nr_queued becomes more than 1.
*/
static void hrtick_update(struct rq *rq)
{
@@ -6780,6 +6778,9 @@ static void hrtick_update(struct rq *rq)
if (!hrtick_enabled_fair(rq) || donor->sched_class != &fair_sched_class)
return;
+ if (hrtick_active(rq))
+ return;
+
hrtick_start_fair(rq, donor);
}
#else /* !CONFIG_SCHED_HRTICK: */
@@ -7102,9 +7103,6 @@ static int dequeue_entities(struct rq *rq, struct sched_entity *se, int flags)
WARN_ON_ONCE(!task_sleep);
WARN_ON_ONCE(p->on_rq != 1);
- /* Fix-up what dequeue_task_fair() skipped */
- hrtick_update(rq);
-
/*
* Fix-up what block_task() skipped.
*
@@ -7138,8 +7136,6 @@ static bool dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
/*
* Must not reference @p after dequeue_entities(DEQUEUE_DELAYED).
*/
-
- hrtick_update(rq);
return true;
}
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index b82fb70..73bc20c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -3041,6 +3041,10 @@ static inline int hrtick_enabled_dl(struct rq *rq)
}
extern void hrtick_start(struct rq *rq, u64 delay);
+static inline bool hrtick_active(struct rq *rq)
+{
+ return hrtimer_active(&rq->hrtick_timer);
+}
#else /* !CONFIG_SCHED_HRTICK: */
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 03/48] sched/fair: Make hrtick resched hard
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
2026-02-24 16:35 ` [patch 01/48] sched/eevdf: Fix HRTICK duration Thomas Gleixner
2026-02-24 16:35 ` [patch 02/48] sched/fair: Simplify hrtick_update() Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:37 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra (Intel)
2026-02-24 16:35 ` [patch 04/48] sched: Avoid ktime_get() indirection Thomas Gleixner
` (46 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
From: Peter Zijlstra (Intel) <peterz@infradead.org>
Since the tick causes hard preemption, the hrtick should too.
Letting the hrtick do lazy preemption completely defeats the purpose, since
it will then still be delayed until a old tick and be dependent on
CONFIG_HZ.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
---
kernel/sched/fair.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5530,7 +5530,7 @@ entity_tick(struct cfs_rq *cfs_rq, struc
* validating it and just reschedule.
*/
if (queued) {
- resched_curr_lazy(rq_of(cfs_rq));
+ resched_curr(rq_of(cfs_rq));
return;
}
#endif
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched/fair: Make hrtick resched hard
2026-02-24 16:35 ` [patch 03/48] sched/fair: Make hrtick resched hard Thomas Gleixner
@ 2026-02-28 15:37 ` tip-bot2 for Peter Zijlstra (Intel)
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Peter Zijlstra (Intel) @ 2026-02-28 15:37 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: 5d88e424ec1b3ea7f552bd14d932f510146c45c7
Gitweb: https://git.kernel.org/tip/5d88e424ec1b3ea7f552bd14d932f510146c45c7
Author: Peter Zijlstra (Intel) <peterz@infradead.org>
AuthorDate: Tue, 24 Feb 2026 17:35:27 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:04 +01:00
sched/fair: Make hrtick resched hard
Since the tick causes hard preemption, the hrtick should too.
Letting the hrtick do lazy preemption completely defeats the purpose, since
it will then still be delayed until a old tick and be dependent on
CONFIG_HZ.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163428.933894105@kernel.org
---
kernel/sched/fair.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 0b6ce88..e9e5fe4 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5530,7 +5530,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
* validating it and just reschedule.
*/
if (queued) {
- resched_curr_lazy(rq_of(cfs_rq));
+ resched_curr(rq_of(cfs_rq));
return;
}
#endif
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 04/48] sched: Avoid ktime_get() indirection
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (2 preceding siblings ...)
2026-02-24 16:35 ` [patch 03/48] sched/fair: Make hrtick resched hard Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:37 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:35 ` [patch 05/48] hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() Thomas Gleixner
` (45 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
The clock of the hrtick and deadline timers is known to be CLOCK_MONOTONIC.
No point in looking it up via hrtimer_cb_get_time().
Just use ktime_get() directly.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
kernel/sched/core.c | 3 +--
kernel/sched/deadline.c | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -925,7 +925,6 @@ static void __hrtick_start(void *arg)
*/
void hrtick_start(struct rq *rq, u64 delay)
{
- struct hrtimer *timer = &rq->hrtick_timer;
s64 delta;
/*
@@ -933,7 +932,7 @@ void hrtick_start(struct rq *rq, u64 del
* doesn't make sense and can cause timer DoS.
*/
delta = max_t(s64, delay, 10000LL);
- rq->hrtick_time = ktime_add_ns(hrtimer_cb_get_time(timer), delta);
+ rq->hrtick_time = ktime_add_ns(ktime_get(), delta);
if (rq == this_rq())
__hrtick_restart(rq);
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1097,7 +1097,7 @@ static int start_dl_timer(struct sched_d
act = ns_to_ktime(dl_next_period(dl_se));
}
- now = hrtimer_cb_get_time(timer);
+ now = ktime_get();
delta = ktime_to_ns(now) - rq_clock(rq);
act = ktime_add_ns(act, delta);
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched: Avoid ktime_get() indirection
2026-02-24 16:35 ` [patch 04/48] sched: Avoid ktime_get() indirection Thomas Gleixner
@ 2026-02-28 15:37 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2026-02-28 15:37 UTC (permalink / raw)
To: linux-tip-commits
Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: d70c1080a957a5144e6c40e95bcbe04ab542fe05
Gitweb: https://git.kernel.org/tip/d70c1080a957a5144e6c40e95bcbe04ab542fe05
Author: Thomas Gleixner <tglx@kernel.org>
AuthorDate: Tue, 24 Feb 2026 17:35:32 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:04 +01:00
sched: Avoid ktime_get() indirection
The clock of the hrtick and deadline timers is known to be CLOCK_MONOTONIC.
No point in looking it up via hrtimer_cb_get_time().
Just use ktime_get() directly.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.001511662@kernel.org
---
kernel/sched/core.c | 3 +--
kernel/sched/deadline.c | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7597776..a716cc6 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -925,7 +925,6 @@ static void __hrtick_start(void *arg)
*/
void hrtick_start(struct rq *rq, u64 delay)
{
- struct hrtimer *timer = &rq->hrtick_timer;
s64 delta;
/*
@@ -933,7 +932,7 @@ void hrtick_start(struct rq *rq, u64 delay)
* doesn't make sense and can cause timer DoS.
*/
delta = max_t(s64, delay, 10000LL);
- rq->hrtick_time = ktime_add_ns(hrtimer_cb_get_time(timer), delta);
+ rq->hrtick_time = ktime_add_ns(ktime_get(), delta);
if (rq == this_rq())
__hrtick_restart(rq);
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index d08b004..9d619a4 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -1097,7 +1097,7 @@ static int start_dl_timer(struct sched_dl_entity *dl_se)
act = ns_to_ktime(dl_next_period(dl_se));
}
- now = hrtimer_cb_get_time(timer);
+ now = ktime_get();
delta = ktime_to_ns(now) - rq_clock(rq);
act = ktime_add_ns(act, delta);
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 05/48] hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns()
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (3 preceding siblings ...)
2026-02-24 16:35 ` [patch 04/48] sched: Avoid ktime_get() indirection Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra
2026-02-24 16:35 ` [patch 06/48] hrtimer: Provide a static branch based hrtimer_hres_enabled() Thomas Gleixner
` (44 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
From: Peter Zijlstra <peterz@infradead.org>
Much like hrtimer_reprogram(), skip programming if the cpu_base is running
the hrtimer interrupt.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
Reviewed-by: Thomas Gleixner <tglx@kernel.org>
---
kernel/time/hrtimer.c | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1269,6 +1269,14 @@ static int __hrtimer_start_range_ns(stru
}
first = enqueue_hrtimer(timer, new_base, mode);
+
+ /*
+ * If the hrtimer interrupt is running, then it will reevaluate the
+ * clock bases and reprogram the clock event device.
+ */
+ if (new_base->cpu_base->in_hrtirq)
+ return false;
+
if (!force_local) {
/*
* If the current CPU base is online, then the timer is
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns()
2026-02-24 16:35 ` [patch 05/48] hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Peter Zijlstra
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Thomas Gleixner, Juri Lelli, x86,
linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: d19ff16c11db38f3ee179d72751fb9b340174330
Gitweb: https://git.kernel.org/tip/d19ff16c11db38f3ee179d72751fb9b340174330
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 24 Feb 2026 17:35:37 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:04 +01:00
hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns()
Much like hrtimer_reprogram(), skip programming if the cpu_base is running
the hrtimer interrupt.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Juri Lelli <juri.lelli@redhat.com>
Reviewed-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260224163429.069535561@kernel.org
---
kernel/time/hrtimer.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 860af7a..3088db4 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1269,6 +1269,14 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
}
first = enqueue_hrtimer(timer, new_base, mode);
+
+ /*
+ * If the hrtimer interrupt is running, then it will reevaluate the
+ * clock bases and reprogram the clock event device.
+ */
+ if (new_base->cpu_base->in_hrtirq)
+ return false;
+
if (!force_local) {
/*
* If the current CPU base is online, then the timer is
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 06/48] hrtimer: Provide a static branch based hrtimer_hres_enabled()
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (4 preceding siblings ...)
2026-02-24 16:35 ` [patch 05/48] hrtimer: Avoid pointless reprogramming in __hrtimer_start_range_ns() Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:35 ` [patch 07/48] sched: Use hrtimer_highres_enabled() Thomas Gleixner
` (43 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
The scheduler evaluates this via hrtimer_is_hres_active() every time it has
to update HRTICK. This needs to follow three pointers, which is expensive.
Provide a static branch based mechanism to avoid that.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
include/linux/hrtimer.h | 13 +++++++++----
kernel/time/hrtimer.c | 28 +++++++++++++++++++++++++---
2 files changed, 34 insertions(+), 7 deletions(-)
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -153,17 +153,22 @@ static inline int hrtimer_is_hres_active
}
#ifdef CONFIG_HIGH_RES_TIMERS
+extern unsigned int hrtimer_resolution;
struct clock_event_device;
extern void hrtimer_interrupt(struct clock_event_device *dev);
-extern unsigned int hrtimer_resolution;
+extern struct static_key_false hrtimer_highres_enabled_key;
-#else
+static inline bool hrtimer_highres_enabled(void)
+{
+ return static_branch_likely(&hrtimer_highres_enabled_key);
+}
+#else /* CONFIG_HIGH_RES_TIMERS */
#define hrtimer_resolution (unsigned int)LOW_RES_NSEC
-
-#endif
+static inline bool hrtimer_highres_enabled(void) { return false; }
+#endif /* !CONFIG_HIGH_RES_TIMERS */
static inline ktime_t
__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now)
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -126,6 +126,25 @@ static inline bool hrtimer_base_is_onlin
return likely(base->online);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+DEFINE_STATIC_KEY_FALSE(hrtimer_highres_enabled_key);
+
+static void hrtimer_hres_workfn(struct work_struct *work)
+{
+ static_branch_enable(&hrtimer_highres_enabled_key);
+}
+
+static DECLARE_WORK(hrtimer_hres_work, hrtimer_hres_workfn);
+
+static inline void hrtimer_schedule_hres_work(void)
+{
+ if (!hrtimer_highres_enabled())
+ schedule_work(&hrtimer_hres_work);
+}
+#else
+static inline void hrtimer_schedule_hres_work(void) { }
+#endif
+
/*
* Functions and macros which are different for UP/SMP systems are kept in a
* single place
@@ -649,7 +668,9 @@ static inline ktime_t hrtimer_update_bas
}
/*
- * Is the high resolution mode active ?
+ * Is the high resolution mode active in the CPU base. This cannot use the
+ * static key as the CPUs are switched to high resolution mode
+ * asynchronously.
*/
static inline int hrtimer_hres_active(struct hrtimer_cpu_base *cpu_base)
{
@@ -750,6 +771,7 @@ static void hrtimer_switch_to_hres(void)
tick_setup_sched_timer(true);
/* "Retrigger" the interrupt to get things going */
retrigger_next_event(NULL);
+ hrtimer_schedule_hres_work();
}
#else
@@ -947,11 +969,10 @@ static bool update_needs_ipi(struct hrti
*/
void clock_was_set(unsigned int bases)
{
- struct hrtimer_cpu_base *cpu_base = raw_cpu_ptr(&hrtimer_bases);
cpumask_var_t mask;
int cpu;
- if (!hrtimer_hres_active(cpu_base) && !tick_nohz_is_active())
+ if (!hrtimer_highres_enabled() && !tick_nohz_is_active())
goto out_timerfd;
if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
@@ -962,6 +983,7 @@ void clock_was_set(unsigned int bases)
/* Avoid interrupting CPUs if possible */
cpus_read_lock();
for_each_online_cpu(cpu) {
+ struct hrtimer_cpu_base *cpu_base;
unsigned long flags;
cpu_base = &per_cpu(hrtimer_bases, cpu);
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] hrtimer: Provide a static branch based hrtimer_hres_enabled()
2026-02-24 16:35 ` [patch 06/48] hrtimer: Provide a static branch based hrtimer_hres_enabled() Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: 0a93d30861617ecf207dcc4c6c736435fac36dae
Gitweb: https://git.kernel.org/tip/0a93d30861617ecf207dcc4c6c736435fac36dae
Author: Thomas Gleixner <tglx@kernel.org>
AuthorDate: Tue, 24 Feb 2026 17:35:42 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:04 +01:00
hrtimer: Provide a static branch based hrtimer_hres_enabled()
The scheduler evaluates this via hrtimer_is_hres_active() every time it has
to update HRTICK. This needs to follow three pointers, which is expensive.
Provide a static branch based mechanism to avoid that.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.136503358@kernel.org
---
include/linux/hrtimer.h | 13 +++++++++----
kernel/time/hrtimer.c | 28 +++++++++++++++++++++++++---
2 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 74adbd4..c9ca105 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -153,17 +153,22 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer)
}
#ifdef CONFIG_HIGH_RES_TIMERS
+extern unsigned int hrtimer_resolution;
struct clock_event_device;
extern void hrtimer_interrupt(struct clock_event_device *dev);
-extern unsigned int hrtimer_resolution;
+extern struct static_key_false hrtimer_highres_enabled_key;
-#else
+static inline bool hrtimer_highres_enabled(void)
+{
+ return static_branch_likely(&hrtimer_highres_enabled_key);
+}
+#else /* CONFIG_HIGH_RES_TIMERS */
#define hrtimer_resolution (unsigned int)LOW_RES_NSEC
-
-#endif
+static inline bool hrtimer_highres_enabled(void) { return false; }
+#endif /* !CONFIG_HIGH_RES_TIMERS */
static inline ktime_t
__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now)
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 3088db4..67917ce 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -126,6 +126,25 @@ static inline bool hrtimer_base_is_online(struct hrtimer_cpu_base *base)
return likely(base->online);
}
+#ifdef CONFIG_HIGH_RES_TIMERS
+DEFINE_STATIC_KEY_FALSE(hrtimer_highres_enabled_key);
+
+static void hrtimer_hres_workfn(struct work_struct *work)
+{
+ static_branch_enable(&hrtimer_highres_enabled_key);
+}
+
+static DECLARE_WORK(hrtimer_hres_work, hrtimer_hres_workfn);
+
+static inline void hrtimer_schedule_hres_work(void)
+{
+ if (!hrtimer_highres_enabled())
+ schedule_work(&hrtimer_hres_work);
+}
+#else
+static inline void hrtimer_schedule_hres_work(void) { }
+#endif
+
/*
* Functions and macros which are different for UP/SMP systems are kept in a
* single place
@@ -649,7 +668,9 @@ static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base)
}
/*
- * Is the high resolution mode active ?
+ * Is the high resolution mode active in the CPU base. This cannot use the
+ * static key as the CPUs are switched to high resolution mode
+ * asynchronously.
*/
static inline int hrtimer_hres_active(struct hrtimer_cpu_base *cpu_base)
{
@@ -750,6 +771,7 @@ static void hrtimer_switch_to_hres(void)
tick_setup_sched_timer(true);
/* "Retrigger" the interrupt to get things going */
retrigger_next_event(NULL);
+ hrtimer_schedule_hres_work();
}
#else
@@ -947,11 +969,10 @@ static bool update_needs_ipi(struct hrtimer_cpu_base *cpu_base,
*/
void clock_was_set(unsigned int bases)
{
- struct hrtimer_cpu_base *cpu_base = raw_cpu_ptr(&hrtimer_bases);
cpumask_var_t mask;
int cpu;
- if (!hrtimer_hres_active(cpu_base) && !tick_nohz_is_active())
+ if (!hrtimer_highres_enabled() && !tick_nohz_is_active())
goto out_timerfd;
if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
@@ -962,6 +983,7 @@ void clock_was_set(unsigned int bases)
/* Avoid interrupting CPUs if possible */
cpus_read_lock();
for_each_online_cpu(cpu) {
+ struct hrtimer_cpu_base *cpu_base;
unsigned long flags;
cpu_base = &per_cpu(hrtimer_bases, cpu);
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 07/48] sched: Use hrtimer_highres_enabled()
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (5 preceding siblings ...)
2026-02-24 16:35 ` [patch 06/48] hrtimer: Provide a static branch based hrtimer_hres_enabled() Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:35 ` [patch 08/48] sched: Optimize hrtimer handling Thomas Gleixner
` (42 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
Use the static branch based variant and thereby avoid following three
pointers.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
include/linux/hrtimer.h | 6 ------
kernel/sched/sched.h | 37 +++++++++----------------------------
2 files changed, 9 insertions(+), 34 deletions(-)
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -146,12 +146,6 @@ static inline ktime_t hrtimer_expires_re
return ktime_sub(timer->node.expires, hrtimer_cb_get_time(timer));
}
-static inline int hrtimer_is_hres_active(struct hrtimer *timer)
-{
- return IS_ENABLED(CONFIG_HIGH_RES_TIMERS) ?
- timer->base->cpu_base->hres_active : 0;
-}
-
#ifdef CONFIG_HIGH_RES_TIMERS
extern unsigned int hrtimer_resolution;
struct clock_event_device;
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -3019,25 +3019,19 @@ extern unsigned int sysctl_numa_balancin
* - enabled by features
* - hrtimer is actually high res
*/
-static inline int hrtick_enabled(struct rq *rq)
+static inline bool hrtick_enabled(struct rq *rq)
{
- if (!cpu_active(cpu_of(rq)))
- return 0;
- return hrtimer_is_hres_active(&rq->hrtick_timer);
+ return cpu_active(cpu_of(rq)) && hrtimer_highres_enabled();
}
-static inline int hrtick_enabled_fair(struct rq *rq)
+static inline bool hrtick_enabled_fair(struct rq *rq)
{
- if (!sched_feat(HRTICK))
- return 0;
- return hrtick_enabled(rq);
+ return sched_feat(HRTICK) && hrtick_enabled(rq);
}
-static inline int hrtick_enabled_dl(struct rq *rq)
+static inline bool hrtick_enabled_dl(struct rq *rq)
{
- if (!sched_feat(HRTICK_DL))
- return 0;
- return hrtick_enabled(rq);
+ return sched_feat(HRTICK_DL) && hrtick_enabled(rq);
}
extern void hrtick_start(struct rq *rq, u64 delay);
@@ -3047,22 +3041,9 @@ static inline bool hrtick_active(struct
}
#else /* !CONFIG_SCHED_HRTICK: */
-
-static inline int hrtick_enabled_fair(struct rq *rq)
-{
- return 0;
-}
-
-static inline int hrtick_enabled_dl(struct rq *rq)
-{
- return 0;
-}
-
-static inline int hrtick_enabled(struct rq *rq)
-{
- return 0;
-}
-
+static inline bool hrtick_enabled_fair(struct rq *rq) { return false; }
+static inline bool hrtick_enabled_dl(struct rq *rq) { return false; }
+static inline bool hrtick_enabled(struct rq *rq) { return false; }
#endif /* !CONFIG_SCHED_HRTICK */
#ifndef arch_scale_freq_tick
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched: Use hrtimer_highres_enabled()
2026-02-24 16:35 ` [patch 07/48] sched: Use hrtimer_highres_enabled() Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: c3a92213eb3dd8ea6f664d16a08eda800e34eaad
Gitweb: https://git.kernel.org/tip/c3a92213eb3dd8ea6f664d16a08eda800e34eaad
Author: Thomas Gleixner <tglx@kernel.org>
AuthorDate: Tue, 24 Feb 2026 17:35:47 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:05 +01:00
sched: Use hrtimer_highres_enabled()
Use the static branch based variant and thereby avoid following three
pointers.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.203610956@kernel.org
---
include/linux/hrtimer.h | 6 ------
kernel/sched/sched.h | 37 +++++++++----------------------------
2 files changed, 9 insertions(+), 34 deletions(-)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index c9ca105..b500385 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -146,12 +146,6 @@ static inline ktime_t hrtimer_expires_remaining(const struct hrtimer *timer)
return ktime_sub(timer->node.expires, hrtimer_cb_get_time(timer));
}
-static inline int hrtimer_is_hres_active(struct hrtimer *timer)
-{
- return IS_ENABLED(CONFIG_HIGH_RES_TIMERS) ?
- timer->base->cpu_base->hres_active : 0;
-}
-
#ifdef CONFIG_HIGH_RES_TIMERS
extern unsigned int hrtimer_resolution;
struct clock_event_device;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 73bc20c..0aa089d 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -3019,25 +3019,19 @@ extern unsigned int sysctl_numa_balancing_hot_threshold;
* - enabled by features
* - hrtimer is actually high res
*/
-static inline int hrtick_enabled(struct rq *rq)
+static inline bool hrtick_enabled(struct rq *rq)
{
- if (!cpu_active(cpu_of(rq)))
- return 0;
- return hrtimer_is_hres_active(&rq->hrtick_timer);
+ return cpu_active(cpu_of(rq)) && hrtimer_highres_enabled();
}
-static inline int hrtick_enabled_fair(struct rq *rq)
+static inline bool hrtick_enabled_fair(struct rq *rq)
{
- if (!sched_feat(HRTICK))
- return 0;
- return hrtick_enabled(rq);
+ return sched_feat(HRTICK) && hrtick_enabled(rq);
}
-static inline int hrtick_enabled_dl(struct rq *rq)
+static inline bool hrtick_enabled_dl(struct rq *rq)
{
- if (!sched_feat(HRTICK_DL))
- return 0;
- return hrtick_enabled(rq);
+ return sched_feat(HRTICK_DL) && hrtick_enabled(rq);
}
extern void hrtick_start(struct rq *rq, u64 delay);
@@ -3047,22 +3041,9 @@ static inline bool hrtick_active(struct rq *rq)
}
#else /* !CONFIG_SCHED_HRTICK: */
-
-static inline int hrtick_enabled_fair(struct rq *rq)
-{
- return 0;
-}
-
-static inline int hrtick_enabled_dl(struct rq *rq)
-{
- return 0;
-}
-
-static inline int hrtick_enabled(struct rq *rq)
-{
- return 0;
-}
-
+static inline bool hrtick_enabled_fair(struct rq *rq) { return false; }
+static inline bool hrtick_enabled_dl(struct rq *rq) { return false; }
+static inline bool hrtick_enabled(struct rq *rq) { return false; }
#endif /* !CONFIG_SCHED_HRTICK */
#ifndef arch_scale_freq_tick
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 08/48] sched: Optimize hrtimer handling
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (6 preceding siblings ...)
2026-02-24 16:35 ` [patch 07/48] sched: Use hrtimer_highres_enabled() Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:35 ` [patch 09/48] sched/hrtick: Avoid tiny hrtick rearms Thomas Gleixner
` (41 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
schedule() provides several mechanisms to update the hrtick timer:
1) When the next task is picked
2) When the balance callbacks are invoked before rq::lock is released
Each of them can result in a first expiring timer and cause a reprogram of
the clock event device.
Solve this by deferring the rearm to the end of schedule() right before
releasing rq::lock by setting a flag on entry which tells hrtick_start() to
cache the runtime constraint in rq::hrtick_delay without touching the timer
itself.
Right before releasing rq::lock evaluate the flags and either rearm or
cancel the hrtick timer.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
kernel/sched/core.c | 57 ++++++++++++++++++++++++++++++++++++++++++---------
kernel/sched/sched.h | 2 +
2 files changed, 50 insertions(+), 9 deletions(-)
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -872,6 +872,12 @@ void update_rq_clock(struct rq *rq)
* Use HR-timers to deliver accurate preemption points.
*/
+enum {
+ HRTICK_SCHED_NONE = 0,
+ HRTICK_SCHED_DEFER = BIT(1),
+ HRTICK_SCHED_START = BIT(2),
+};
+
static void hrtick_clear(struct rq *rq)
{
if (hrtimer_active(&rq->hrtick_timer))
@@ -932,6 +938,17 @@ void hrtick_start(struct rq *rq, u64 del
* doesn't make sense and can cause timer DoS.
*/
delta = max_t(s64, delay, 10000LL);
+
+ /*
+ * If this is in the middle of schedule() only note the delay
+ * and let hrtick_schedule_exit() deal with it.
+ */
+ if (rq->hrtick_sched) {
+ rq->hrtick_sched |= HRTICK_SCHED_START;
+ rq->hrtick_delay = delta;
+ return;
+ }
+
rq->hrtick_time = ktime_add_ns(ktime_get(), delta);
if (rq == this_rq())
@@ -940,19 +957,40 @@ void hrtick_start(struct rq *rq, u64 del
smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
}
-static void hrtick_rq_init(struct rq *rq)
+static inline void hrtick_schedule_enter(struct rq *rq)
{
- INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
- hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
+ rq->hrtick_sched = HRTICK_SCHED_DEFER;
}
-#else /* !CONFIG_SCHED_HRTICK: */
-static inline void hrtick_clear(struct rq *rq)
+
+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);
+ } else if (idle_rq(rq)) {
+ /*
+ * No need for using hrtimer_is_active(). The timer is CPU local
+ * and interrupts are disabled, so the callback cannot be
+ * running and the queued state is valid.
+ */
+ if (hrtimer_is_queued(&rq->hrtick_timer))
+ hrtimer_cancel(&rq->hrtick_timer);
+ }
+
+ rq->hrtick_sched = HRTICK_SCHED_NONE;
}
-static inline void hrtick_rq_init(struct rq *rq)
+static void hrtick_rq_init(struct rq *rq)
{
+ INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
+ rq->hrtick_sched = HRTICK_SCHED_NONE;
+ hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
}
+#else /* !CONFIG_SCHED_HRTICK: */
+static inline void hrtick_clear(struct rq *rq) { }
+static inline void hrtick_rq_init(struct rq *rq) { }
+static inline void hrtick_schedule_enter(struct rq *rq) { }
+static inline void hrtick_schedule_exit(struct rq *rq) { }
#endif /* !CONFIG_SCHED_HRTICK */
/*
@@ -5028,6 +5066,7 @@ static inline void finish_lock_switch(st
*/
spin_acquire(&__rq_lockp(rq)->dep_map, 0, 0, _THIS_IP_);
__balance_callbacks(rq, NULL);
+ hrtick_schedule_exit(rq);
raw_spin_rq_unlock_irq(rq);
}
@@ -6781,9 +6820,6 @@ static void __sched notrace __schedule(i
schedule_debug(prev, preempt);
- if (sched_feat(HRTICK) || sched_feat(HRTICK_DL))
- hrtick_clear(rq);
-
klp_sched_try_switch(prev);
local_irq_disable();
@@ -6810,6 +6846,8 @@ static void __sched notrace __schedule(i
rq_lock(rq, &rf);
smp_mb__after_spinlock();
+ hrtick_schedule_enter(rq);
+
/* Promote REQ to ACT */
rq->clock_update_flags <<= 1;
update_rq_clock(rq);
@@ -6911,6 +6949,7 @@ static void __sched notrace __schedule(i
rq_unpin_lock(rq, &rf);
__balance_callbacks(rq, NULL);
+ hrtick_schedule_exit(rq);
raw_spin_rq_unlock_irq(rq);
}
trace_sched_exit_tp(is_switch);
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1285,6 +1285,8 @@ struct rq {
call_single_data_t hrtick_csd;
struct hrtimer hrtick_timer;
ktime_t hrtick_time;
+ ktime_t hrtick_delay;
+ unsigned int hrtick_sched;
#endif
#ifdef CONFIG_SCHEDSTATS
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched: Optimize hrtimer handling
2026-02-24 16:35 ` [patch 08/48] sched: Optimize hrtimer handling Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: 96d1610e0b20b5a627773874b4514ae922ad98f6
Gitweb: https://git.kernel.org/tip/96d1610e0b20b5a627773874b4514ae922ad98f6
Author: Thomas Gleixner <tglx@kernel.org>
AuthorDate: Tue, 24 Feb 2026 17:35:52 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:05 +01:00
sched: Optimize hrtimer handling
schedule() provides several mechanisms to update the hrtick timer:
1) When the next task is picked
2) When the balance callbacks are invoked before rq::lock is released
Each of them can result in a first expiring timer and cause a reprogram of
the clock event device.
Solve this by deferring the rearm to the end of schedule() right before
releasing rq::lock by setting a flag on entry which tells hrtick_start() to
cache the runtime constraint in rq::hrtick_delay without touching the timer
itself.
Right before releasing rq::lock evaluate the flags and either rearm or
cancel the hrtick timer.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.273068659@kernel.org
---
kernel/sched/core.c | 57 ++++++++++++++++++++++++++++++++++++-------
kernel/sched/sched.h | 2 ++-
2 files changed, 50 insertions(+), 9 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a716cc6..a868f0a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -872,6 +872,12 @@ void update_rq_clock(struct rq *rq)
* Use HR-timers to deliver accurate preemption points.
*/
+enum {
+ HRTICK_SCHED_NONE = 0,
+ HRTICK_SCHED_DEFER = BIT(1),
+ HRTICK_SCHED_START = BIT(2),
+};
+
static void hrtick_clear(struct rq *rq)
{
if (hrtimer_active(&rq->hrtick_timer))
@@ -932,6 +938,17 @@ void hrtick_start(struct rq *rq, u64 delay)
* doesn't make sense and can cause timer DoS.
*/
delta = max_t(s64, delay, 10000LL);
+
+ /*
+ * If this is in the middle of schedule() only note the delay
+ * and let hrtick_schedule_exit() deal with it.
+ */
+ if (rq->hrtick_sched) {
+ rq->hrtick_sched |= HRTICK_SCHED_START;
+ rq->hrtick_delay = delta;
+ return;
+ }
+
rq->hrtick_time = ktime_add_ns(ktime_get(), delta);
if (rq == this_rq())
@@ -940,19 +957,40 @@ void hrtick_start(struct rq *rq, u64 delay)
smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
}
-static void hrtick_rq_init(struct rq *rq)
+static inline void hrtick_schedule_enter(struct rq *rq)
{
- INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
- hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
+ rq->hrtick_sched = HRTICK_SCHED_DEFER;
}
-#else /* !CONFIG_SCHED_HRTICK: */
-static inline void hrtick_clear(struct rq *rq)
+
+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);
+ } else if (idle_rq(rq)) {
+ /*
+ * No need for using hrtimer_is_active(). The timer is CPU local
+ * and interrupts are disabled, so the callback cannot be
+ * running and the queued state is valid.
+ */
+ if (hrtimer_is_queued(&rq->hrtick_timer))
+ hrtimer_cancel(&rq->hrtick_timer);
+ }
+
+ rq->hrtick_sched = HRTICK_SCHED_NONE;
}
-static inline void hrtick_rq_init(struct rq *rq)
+static void hrtick_rq_init(struct rq *rq)
{
+ INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
+ rq->hrtick_sched = HRTICK_SCHED_NONE;
+ hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
}
+#else /* !CONFIG_SCHED_HRTICK: */
+static inline void hrtick_clear(struct rq *rq) { }
+static inline void hrtick_rq_init(struct rq *rq) { }
+static inline void hrtick_schedule_enter(struct rq *rq) { }
+static inline void hrtick_schedule_exit(struct rq *rq) { }
#endif /* !CONFIG_SCHED_HRTICK */
/*
@@ -5028,6 +5066,7 @@ static inline void finish_lock_switch(struct rq *rq)
*/
spin_acquire(&__rq_lockp(rq)->dep_map, 0, 0, _THIS_IP_);
__balance_callbacks(rq, NULL);
+ hrtick_schedule_exit(rq);
raw_spin_rq_unlock_irq(rq);
}
@@ -6781,9 +6820,6 @@ static void __sched notrace __schedule(int sched_mode)
schedule_debug(prev, preempt);
- if (sched_feat(HRTICK) || sched_feat(HRTICK_DL))
- hrtick_clear(rq);
-
klp_sched_try_switch(prev);
local_irq_disable();
@@ -6810,6 +6846,8 @@ static void __sched notrace __schedule(int sched_mode)
rq_lock(rq, &rf);
smp_mb__after_spinlock();
+ hrtick_schedule_enter(rq);
+
/* Promote REQ to ACT */
rq->clock_update_flags <<= 1;
update_rq_clock(rq);
@@ -6911,6 +6949,7 @@ keep_resched:
rq_unpin_lock(rq, &rf);
__balance_callbacks(rq, NULL);
+ hrtick_schedule_exit(rq);
raw_spin_rq_unlock_irq(rq);
}
trace_sched_exit_tp(is_switch);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 0aa089d..6774fb5 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1285,6 +1285,8 @@ struct rq {
call_single_data_t hrtick_csd;
struct hrtimer hrtick_timer;
ktime_t hrtick_time;
+ ktime_t hrtick_delay;
+ unsigned int hrtick_sched;
#endif
#ifdef CONFIG_SCHEDSTATS
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 09/48] sched/hrtick: Avoid tiny hrtick rearms
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (7 preceding siblings ...)
2026-02-24 16:35 ` [patch 08/48] sched: Optimize hrtimer handling Thomas Gleixner
@ 2026-02-24 16:35 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:36 ` [patch 10/48] hrtimer: Provide LAZY_REARM mode Thomas Gleixner
` (40 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:35 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
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>
---
kernel/sched/core.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -903,12 +903,24 @@ static enum hrtimer_restart hrtick(struc
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 del
}
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(
{
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
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched/hrtick: Avoid tiny hrtick rearms
2026-02-24 16:35 ` [patch 09/48] sched/hrtick: Avoid tiny hrtick rearms Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: c8cdb9b516407a0b8c653c9c1d6f0931c3864384
Gitweb: https://git.kernel.org/tip/c8cdb9b516407a0b8c653c9c1d6f0931c3864384
Author: Thomas Gleixner <tglx@kernel.org>
AuthorDate: Tue, 24 Feb 2026 17:35:56 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:05 +01:00
sched/hrtick: Avoid tiny hrtick rearms
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 | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index a868f0a..5bc446e 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -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
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 10/48] hrtimer: Provide LAZY_REARM mode
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (8 preceding siblings ...)
2026-02-24 16:35 ` [patch 09/48] sched/hrtick: Avoid tiny hrtick rearms Thomas Gleixner
@ 2026-02-24 16:36 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra
2026-02-24 16:36 ` [patch 11/48] sched/hrtick: Mark hrtick timer LAZY_REARM Thomas Gleixner
` (39 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:36 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
From: Peter Zijlstra <peterz@infradead.org>
The hrtick timer is frequently rearmed before expiry and most of the time
the new expiry is past the armed one. As this happens on every context
switch it becomes expensive with scheduling heavy work loads especially in
virtual machines as the "hardware" reprogamming implies a VM exit.
Add a lazy rearm mode flag which skips the reprogamming if:
1) The timer was the first expiring timer before the rearm
2) The new expiry time is farther out than the armed time
This avoids a massive amount of reprogramming operations of the hrtick
timer for the price of eventually taking the alredy armed interrupt for
nothing.
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
include/linux/hrtimer.h | 8 ++++++++
include/linux/hrtimer_types.h | 3 +++
kernel/time/hrtimer.c | 17 ++++++++++++++++-
3 files changed, 27 insertions(+), 1 deletion(-)
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -31,6 +31,13 @@
* soft irq context
* HRTIMER_MODE_HARD - Timer callback function will be executed in
* hard irq context even on PREEMPT_RT.
+ * HRTIMER_MODE_LAZY_REARM - Avoid reprogramming if the timer was the
+ * first expiring timer and is moved into the
+ * future. Special mode for the HRTICK timer to
+ * avoid extensive reprogramming of the hardware,
+ * which is expensive in virtual machines. Risks
+ * a pointless expiry, but that's better than
+ * reprogramming on every context switch,
*/
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0x00,
@@ -38,6 +45,7 @@ enum hrtimer_mode {
HRTIMER_MODE_PINNED = 0x02,
HRTIMER_MODE_SOFT = 0x04,
HRTIMER_MODE_HARD = 0x08,
+ HRTIMER_MODE_LAZY_REARM = 0x10,
HRTIMER_MODE_ABS_PINNED = HRTIMER_MODE_ABS | HRTIMER_MODE_PINNED,
HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL | HRTIMER_MODE_PINNED,
--- a/include/linux/hrtimer_types.h
+++ b/include/linux/hrtimer_types.h
@@ -33,6 +33,8 @@ enum hrtimer_restart {
* @is_soft: Set if hrtimer will be expired in soft interrupt context.
* @is_hard: Set if hrtimer will be expired in hard interrupt context
* even on RT.
+ * @is_lazy: Set if the timer is frequently rearmed to avoid updates
+ * of the clock event device
*
* The hrtimer structure must be initialized by hrtimer_setup()
*/
@@ -45,6 +47,7 @@ struct hrtimer {
u8 is_rel;
u8 is_soft;
u8 is_hard;
+ u8 is_lazy;
};
#endif /* _LINUX_HRTIMER_TYPES_H */
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1152,7 +1152,7 @@ static void __remove_hrtimer(struct hrti
* an superfluous call to hrtimer_force_reprogram() on the
* remote cpu later on if the same timer gets enqueued again.
*/
- if (reprogram && timer == cpu_base->next_timer)
+ if (reprogram && timer == cpu_base->next_timer && !timer->is_lazy)
hrtimer_force_reprogram(cpu_base, 1);
}
@@ -1322,6 +1322,20 @@ static int __hrtimer_start_range_ns(stru
}
/*
+ * Special case for the HRTICK timer. It is frequently rearmed and most
+ * of the time moves the expiry into the future. That's expensive in
+ * virtual machines and it's better to take the pointless already armed
+ * interrupt than reprogramming the hardware on every context switch.
+ *
+ * If the new expiry is before the armed time, then reprogramming is
+ * required.
+ */
+ if (timer->is_lazy) {
+ if (new_base->cpu_base->expires_next <= hrtimer_get_expires(timer))
+ return 0;
+ }
+
+ /*
* Timer was forced to stay on the current CPU to avoid
* reprogramming on removal and enqueue. Force reprogram the
* hardware by evaluating the new first expiring timer.
@@ -1675,6 +1689,7 @@ static void __hrtimer_setup(struct hrtim
base += hrtimer_clockid_to_base(clock_id);
timer->is_soft = softtimer;
timer->is_hard = !!(mode & HRTIMER_MODE_HARD);
+ timer->is_lazy = !!(mode & HRTIMER_MODE_LAZY_REARM);
timer->base = &cpu_base->clock_base[base];
timerqueue_init(&timer->node);
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] hrtimer: Provide LAZY_REARM mode
2026-02-24 16:36 ` [patch 10/48] hrtimer: Provide LAZY_REARM mode Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Peter Zijlstra
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: b7dd64778aa3f89de9afa1e81171cfe110ddc525
Gitweb: https://git.kernel.org/tip/b7dd64778aa3f89de9afa1e81171cfe110ddc525
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 24 Feb 2026 17:36:01 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:06 +01:00
hrtimer: Provide LAZY_REARM mode
The hrtick timer is frequently rearmed before expiry and most of the time
the new expiry is past the armed one. As this happens on every context
switch it becomes expensive with scheduling heavy work loads especially in
virtual machines as the "hardware" reprogamming implies a VM exit.
Add a lazy rearm mode flag which skips the reprogamming if:
1) The timer was the first expiring timer before the rearm
2) The new expiry time is farther out than the armed time
This avoids a massive amount of reprogramming operations of the hrtick
timer for the price of eventually taking the alredy armed interrupt for
nothing.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.408524456@kernel.org
---
include/linux/hrtimer.h | 8 ++++++++
include/linux/hrtimer_types.h | 3 +++
kernel/time/hrtimer.c | 17 ++++++++++++++++-
3 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index b500385..c924bb2 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -31,6 +31,13 @@
* soft irq context
* HRTIMER_MODE_HARD - Timer callback function will be executed in
* hard irq context even on PREEMPT_RT.
+ * HRTIMER_MODE_LAZY_REARM - Avoid reprogramming if the timer was the
+ * first expiring timer and is moved into the
+ * future. Special mode for the HRTICK timer to
+ * avoid extensive reprogramming of the hardware,
+ * which is expensive in virtual machines. Risks
+ * a pointless expiry, but that's better than
+ * reprogramming on every context switch,
*/
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0x00,
@@ -38,6 +45,7 @@ enum hrtimer_mode {
HRTIMER_MODE_PINNED = 0x02,
HRTIMER_MODE_SOFT = 0x04,
HRTIMER_MODE_HARD = 0x08,
+ HRTIMER_MODE_LAZY_REARM = 0x10,
HRTIMER_MODE_ABS_PINNED = HRTIMER_MODE_ABS | HRTIMER_MODE_PINNED,
HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL | HRTIMER_MODE_PINNED,
diff --git a/include/linux/hrtimer_types.h b/include/linux/hrtimer_types.h
index 8fbbb6b..64381c6 100644
--- a/include/linux/hrtimer_types.h
+++ b/include/linux/hrtimer_types.h
@@ -33,6 +33,8 @@ enum hrtimer_restart {
* @is_soft: Set if hrtimer will be expired in soft interrupt context.
* @is_hard: Set if hrtimer will be expired in hard interrupt context
* even on RT.
+ * @is_lazy: Set if the timer is frequently rearmed to avoid updates
+ * of the clock event device
*
* The hrtimer structure must be initialized by hrtimer_setup()
*/
@@ -45,6 +47,7 @@ struct hrtimer {
u8 is_rel;
u8 is_soft;
u8 is_hard;
+ u8 is_lazy;
};
#endif /* _LINUX_HRTIMER_TYPES_H */
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 67917ce..e54f8b5 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -1152,7 +1152,7 @@ static void __remove_hrtimer(struct hrtimer *timer,
* an superfluous call to hrtimer_force_reprogram() on the
* remote cpu later on if the same timer gets enqueued again.
*/
- if (reprogram && timer == cpu_base->next_timer)
+ if (reprogram && timer == cpu_base->next_timer && !timer->is_lazy)
hrtimer_force_reprogram(cpu_base, 1);
}
@@ -1322,6 +1322,20 @@ static int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
}
/*
+ * Special case for the HRTICK timer. It is frequently rearmed and most
+ * of the time moves the expiry into the future. That's expensive in
+ * virtual machines and it's better to take the pointless already armed
+ * interrupt than reprogramming the hardware on every context switch.
+ *
+ * If the new expiry is before the armed time, then reprogramming is
+ * required.
+ */
+ if (timer->is_lazy) {
+ if (new_base->cpu_base->expires_next <= hrtimer_get_expires(timer))
+ return 0;
+ }
+
+ /*
* Timer was forced to stay on the current CPU to avoid
* reprogramming on removal and enqueue. Force reprogram the
* hardware by evaluating the new first expiring timer.
@@ -1675,6 +1689,7 @@ static void __hrtimer_setup(struct hrtimer *timer,
base += hrtimer_clockid_to_base(clock_id);
timer->is_soft = softtimer;
timer->is_hard = !!(mode & HRTIMER_MODE_HARD);
+ timer->is_lazy = !!(mode & HRTIMER_MODE_LAZY_REARM);
timer->base = &cpu_base->clock_base[base];
timerqueue_init(&timer->node);
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 11/48] sched/hrtick: Mark hrtick timer LAZY_REARM
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (9 preceding siblings ...)
2026-02-24 16:36 ` [patch 10/48] hrtimer: Provide LAZY_REARM mode Thomas Gleixner
@ 2026-02-24 16:36 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Peter Zijlstra
2026-02-24 16:36 ` [patch 12/48] tick/sched: Avoid hrtimer_cancel/start() sequence Thomas Gleixner
` (38 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:36 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
From: Peter Zijlstra <peterz@infradead.org>
The hrtick timer is frequently rearmed before expiry and most of the time
the new expiry is past the armed one. As this happens on every context
switch it becomes expensive with scheduling heavy work loads especially in
virtual machines as the "hardware" reprogamming implies a VM exit.
hrtimer now provide a lazy rearm mode flag which skips the reprogamming if:
1) The timer was the first expiring timer before the rearm
2) The new expiry time is farther out than the armed time
This avoids a massive amount of reprogramming operations of the hrtick
timer for the price of eventually taking the alredy armed interrupt for
nothing.
Mark the hrtick timer accordingly.
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
kernel/sched/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -998,7 +998,8 @@ static void hrtick_rq_init(struct rq *rq
{
INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
rq->hrtick_sched = HRTICK_SCHED_NONE;
- hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
+ hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_HARD | HRTIMER_MODE_LAZY_REARM);
}
#else /* !CONFIG_SCHED_HRTICK: */
static inline void hrtick_clear(struct rq *rq) { }
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] sched/hrtick: Mark hrtick timer LAZY_REARM
2026-02-24 16:36 ` [patch 11/48] sched/hrtick: Mark hrtick timer LAZY_REARM Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Peter Zijlstra
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Peter Zijlstra (Intel), Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: 0abec32a6836eca6b61ae81e4829f94abd4647c7
Gitweb: https://git.kernel.org/tip/0abec32a6836eca6b61ae81e4829f94abd4647c7
Author: Peter Zijlstra <peterz@infradead.org>
AuthorDate: Tue, 24 Feb 2026 17:36:06 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:06 +01:00
sched/hrtick: Mark hrtick timer LAZY_REARM
The hrtick timer is frequently rearmed before expiry and most of the time
the new expiry is past the armed one. As this happens on every context
switch it becomes expensive with scheduling heavy work loads especially in
virtual machines as the "hardware" reprogamming implies a VM exit.
hrtimer now provide a lazy rearm mode flag which skips the reprogamming if:
1) The timer was the first expiring timer before the rearm
2) The new expiry time is farther out than the armed time
This avoids a massive amount of reprogramming operations of the hrtick
timer for the price of eventually taking the alredy armed interrupt for
nothing.
Mark the hrtick timer accordingly.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260224163429.475409346@kernel.org
---
kernel/sched/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 5bc446e..2d1239a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -998,7 +998,8 @@ static void hrtick_rq_init(struct rq *rq)
{
INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
rq->hrtick_sched = HRTICK_SCHED_NONE;
- hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
+ hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL_HARD | HRTIMER_MODE_LAZY_REARM);
}
#else /* !CONFIG_SCHED_HRTICK: */
static inline void hrtick_clear(struct rq *rq) { }
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 12/48] tick/sched: Avoid hrtimer_cancel/start() sequence
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (10 preceding siblings ...)
2026-02-24 16:36 ` [patch 11/48] sched/hrtick: Mark hrtick timer LAZY_REARM Thomas Gleixner
@ 2026-02-24 16:36 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:36 ` [patch 13/48] clockevents: Remove redundant CLOCK_EVT_FEAT_KTIME Thomas Gleixner
` (37 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:36 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
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
Cc: Frederic Weisbecker <frederic@kernel.org>
---
kernel/time/tick-sched.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -864,19 +864,32 @@ u64 get_cpu_iowait_time_us(int cpu, u64
}
EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
+/* Simplified variant of hrtimer_forward_now() */
+static ktime_t tick_forward_now(ktime_t expires, ktime_t now)
+{
+ ktime_t delta = now - expires;
+
+ if (likely(delta < TICK_NSEC))
+ return expires + TICK_NSEC;
+
+ expires += TICK_NSEC * ktime_divns(delta, TICK_NSEC);
+ if (expires > now)
+ return expires;
+ return expires + TICK_NSEC;
+}
+
static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
{
- hrtimer_cancel(&ts->sched_timer);
- hrtimer_set_expires(&ts->sched_timer, ts->last_tick);
+ ktime_t expires = ts->last_tick;
- /* Forward the time to expire in the future */
- hrtimer_forward(&ts->sched_timer, now, TICK_NSEC);
+ if (now >= expires)
+ expires = tick_forward_now(expires, now);
if (tick_sched_flag_test(ts, TS_FLAG_HIGHRES)) {
- hrtimer_start_expires(&ts->sched_timer,
- HRTIMER_MODE_ABS_PINNED_HARD);
+ hrtimer_start(&ts->sched_timer, expires, HRTIMER_MODE_ABS_PINNED_HARD);
} else {
- tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
+ hrtimer_set_expires(&ts->sched_timer, expires);
+ tick_program_event(expires, 1);
}
/*
^ permalink raw reply [flat|nested] 130+ messages in thread* [tip: sched/hrtick] tick/sched: Avoid hrtimer_cancel/start() sequence
2026-02-24 16:36 ` [patch 12/48] tick/sched: Avoid hrtimer_cancel/start() sequence Thomas Gleixner
@ 2026-02-28 15:36 ` tip-bot2 for Thomas Gleixner
0 siblings, 0 replies; 130+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2026-02-28 15:36 UTC (permalink / raw)
To: linux-tip-commits
Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel
The following commit has been merged into the sched/hrtick branch of tip:
Commit-ID: adcec6a7f566aa237db211f2947b039418450b92
Gitweb: https://git.kernel.org/tip/adcec6a7f566aa237db211f2947b039418450b92
Author: Thomas Gleixner <tglx@kernel.org>
AuthorDate: Tue, 24 Feb 2026 17:36:10 +01:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 27 Feb 2026 16:40:06 +01:00
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
---
kernel/time/tick-sched.c | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index f7907fa..9e52644 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -864,19 +864,32 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time)
}
EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us);
+/* Simplified variant of hrtimer_forward_now() */
+static ktime_t tick_forward_now(ktime_t expires, ktime_t now)
+{
+ ktime_t delta = now - expires;
+
+ if (likely(delta < TICK_NSEC))
+ return expires + TICK_NSEC;
+
+ expires += TICK_NSEC * ktime_divns(delta, TICK_NSEC);
+ if (expires > now)
+ return expires;
+ return expires + TICK_NSEC;
+}
+
static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
{
- hrtimer_cancel(&ts->sched_timer);
- hrtimer_set_expires(&ts->sched_timer, ts->last_tick);
+ ktime_t expires = ts->last_tick;
- /* Forward the time to expire in the future */
- hrtimer_forward(&ts->sched_timer, now, TICK_NSEC);
+ if (now >= expires)
+ expires = tick_forward_now(expires, now);
if (tick_sched_flag_test(ts, TS_FLAG_HIGHRES)) {
- hrtimer_start_expires(&ts->sched_timer,
- HRTIMER_MODE_ABS_PINNED_HARD);
+ hrtimer_start(&ts->sched_timer, expires, HRTIMER_MODE_ABS_PINNED_HARD);
} else {
- tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);
+ hrtimer_set_expires(&ts->sched_timer, expires);
+ tick_program_event(expires, 1);
}
/*
^ permalink raw reply related [flat|nested] 130+ messages in thread
* [patch 13/48] clockevents: Remove redundant CLOCK_EVT_FEAT_KTIME
2026-02-24 16:35 [patch 00/48] hrtimer,sched: General optimizations and hrtick enablement Thomas Gleixner
` (11 preceding siblings ...)
2026-02-24 16:36 ` [patch 12/48] tick/sched: Avoid hrtimer_cancel/start() sequence Thomas Gleixner
@ 2026-02-24 16:36 ` Thomas Gleixner
2026-02-28 15:36 ` [tip: sched/hrtick] " tip-bot2 for Thomas Gleixner
2026-02-24 16:36 ` [patch 14/48] timekeeping: Allow inlining clocksource::read() Thomas Gleixner
` (36 subsequent siblings)
49 siblings, 1 reply; 130+ messages in thread
From: Thomas Gleixner @ 2026-02-24 16:36 UTC (permalink / raw)
To: LKML
Cc: Anna-Maria Behnsen, John Stultz, Stephen Boyd, Daniel Lezcano,
Juri Lelli, Vincent Guittot, Dietmar Eggemann, Steven Rostedt,
Ben Segall, Mel Gorman, Valentin Schneider, x86, Peter Zijlstra,
Frederic Weisbecker, Eric Dumazet
The only real usecase for this is the hrtimer based broadcast device.
No point in using two different feature flags for this.
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
include/linux/clockchips.h | 1 -
kernel/time/clockevents.c | 4 ++--
kernel/time/tick-broadcast-hrtimer.c | 1 -
3 files changed, 2 insertions(+), 4 deletions(-)
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -45,7 +45,6 @@ enum clock_event_state {
*/
# define CLOCK_EVT_FEAT_PERIODIC 0x000001
# define CLOCK_EVT_FEAT_ONESHOT 0x000002
-# define CLOCK_EVT_FEAT_KTIME 0x000004
/*
* x86(64) specific (mis)features:
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -319,8 +319,8 @@ int clockevents_program_event(struct clo
WARN_ONCE(!clockevent_state_oneshot(dev), "Current state: %d\n",
clockevent_get_state(dev));
- /* Shortcut for clockevent devices that can deal with ktime. */
- if (dev->features & CLOCK_EVT_FEAT_KTIME)
+ /* ktime_t based reprogramming for the broadcast hrtimer device */
+ if (unlikely(dev->features & CLOCK_EVT_FEAT_HRTIMER))
return dev->set_next_ktime(expires, dev);
delta = ktime_to_ns(ktime_sub(expires, ktime_get()));
--- a/kernel/time/tick-broadcast-hrtimer.c
+++ b/kernel/time/tick-broadcast-hrtimer.c
@@ -78,7 +78,6 @@ static struct clock_event_device ce_broa
.set_state_shutdown = bc_shutdown,
.set_next_ktime = bc_set_next,
.features = CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_KTIME |
CLOCK_EVT_FEAT_HRTIMER,
.rating = 0,
.bound_on = -1,
^ permalink raw reply [flat|nested] 130+ messages in thread