mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] sched/fair: Restart hrtick after same-task repicks
@ 2026-08-13 21:23 Shubhang Kaushik (Ampere)
  2026-08-26  1:13 ` Shubhang
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Shubhang Kaushik (Ampere) @ 2026-08-13 21:23 UTC (permalink / raw)
  To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
	Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, K Prateek Nayak, Shubhang Kaushik,
	Christoph Lameter
  Cc: linux-kernel, Shubhang Kaushik (Ampere)

Fair hrtick is implemented with a one-shot timer, so each precise
preemption point has to be programmed explicitly. The usual fair path
does this from set_next_task_fair(), which calls hrtick_start_fair().

The missed path is:

  hrtick
    -> task_tick_fair(..., queued=1)
       -> entity_tick()
	  -> resched_curr()
    -> schedule()
       -> pick_task_fair() picks current again
       -> put_prev_set_next_task()
	  -> next == prev
	  -> return

Since set_next_task_fair() is skipped, hrtick_start_fair() is not called
and no new fair hrtick is started.

Record when a queued fair hrtick may need a restart, and consume that
state only from the same-task fast path. Limit this to cases where more
than one fair entity is runnable and all queued fair entities are
runnable, avoiding extra hrticks for delayed-dequeue and pipe-like cases
where queued entities are not all competing for CPU time.

Signed-off-by: Shubhang Kaushik (Ampere) <sh@gentwo.org>
---
On v7.2-rc7 mainline (3aa1dcaa4f6f), with HRTICK enabled,
base_slice_ns=3000000, and two CPU-bound tasks pinned to one CPU, the
nice-0 task's runtime intervals above 8ms dropped from 228 in a 10s
perf sched capture to 34-38 across repeated runs with this change.

A similar missed hrtick start was previously reported for the older
pick_next_task_fair() flow:
  Message-ID: <20241111074841.8802-1-shijie@os.amperecomputing.com>
---
 kernel/sched/core.c  |  2 ++
 kernel/sched/fair.c  | 29 ++++++++++++++++++++++++++++-
 kernel/sched/sched.h | 21 ++++++++++++++++++++-
 3 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 96226707c2f6135341aa779b8262f113e103d8ad..5ec8c3f752fa48149469907edb595ede0769e94a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1013,12 +1013,14 @@ static inline void hrtick_schedule_exit(struct rq *rq)
 		__hrtimer_rearm_deferred();
 
 	rq->hrtick_sched = HRTICK_SCHED_NONE;
+	rq->hrtick_rearm_fair = false;
 }
 
 static void hrtick_rq_init(struct rq *rq)
 {
 	INIT_CSD(&rq->hrtick_csd, __hrtick_start, rq);
 	rq->hrtick_sched = HRTICK_SCHED_NONE;
+	rq->hrtick_rearm_fair = false;
 	hrtimer_setup(&rq->hrtick_timer, hrtick, CLOCK_MONOTONIC,
 		      HRTIMER_MODE_REL_HARD | HRTIMER_MODE_LAZY_REARM);
 }
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d78467ec6ee1343050fcc2794dafb38ade3599e5..2d90a9a84175833bdb78f6f78d23b124105fcb82 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7681,6 +7681,22 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
 	hrtick_start(rq, (scale * delta) / 1024);
 }
 
+void __hrtick_rearm_fair(struct rq *rq, struct task_struct *p)
+{
+	rq->hrtick_rearm_fair = false;
+
+	if (!hrtick_enabled_fair(rq))
+		return;
+
+	if (hrtick_active(rq))
+		return;
+
+	if (p->sched_class != &fair_sched_class)
+		return;
+
+	hrtick_start_fair(rq, p);
+}
+
 /*
  * Called on enqueue to start the hrtick when h_nr_queued becomes more than 1.
  */
@@ -14858,8 +14874,19 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
 		entity_tick(cfs_rq, se, queued);
 	}
 
-	if (queued)
+	if (queued) {
+		/*
+		 * Fair hrtick is one-shot. If this hrtick-triggered
+		 * reschedule picks the same task again, set_next_task_fair()
+		 * will be skipped. Mark that path for a possible restart, but
+		 * avoid delayed-dequeue cases where queued entities are not all
+		 * runnable.
+		 */
+		rq->hrtick_rearm_fair = hrtick_enabled_fair(rq) &&
+					rq->cfs.h_nr_runnable > 1 &&
+					rq->cfs.h_nr_runnable == rq->cfs.h_nr_queued;
 		return;
+	}
 
 	if (static_branch_unlikely(&sched_numa_balancing))
 		task_tick_numa(rq, curr);
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 56acf502ba260ab18bacd7a4c2efdec612d50125..faf63eea233981fbd7e0a13b652f0c37d292ef35 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1313,6 +1313,7 @@ struct rq {
 	ktime_t			hrtick_time;
 	ktime_t			hrtick_delay;
 	unsigned int		hrtick_sched;
+	bool			hrtick_rearm_fair;
 #endif
 
 #ifdef CONFIG_SCHEDSTATS
@@ -2745,6 +2746,18 @@ static inline void set_next_task(struct rq *rq, struct task_struct *next)
 	next->sched_class->set_next_task(rq, next, false);
 }
 
+#ifdef CONFIG_SCHED_HRTICK
+void __hrtick_rearm_fair(struct rq *rq, struct task_struct *p);
+
+static inline void hrtick_rearm_fair(struct rq *rq, struct task_struct *p)
+{
+	if (rq->hrtick_rearm_fair)
+		__hrtick_rearm_fair(rq, p);
+}
+#else
+static inline void hrtick_rearm_fair(struct rq *rq, struct task_struct *p) { }
+#endif
+
 static inline void
 __put_prev_set_next_dl_server(struct rq *rq,
 			      struct task_struct *prev,
@@ -2763,8 +2776,14 @@ static inline void put_prev_set_next_task(struct rq *rq,
 
 	__put_prev_set_next_dl_server(rq, prev, next);
 
-	if (next == prev)
+	if (next == prev) {
+		/*
+		 * Same-task repicks skip class callbacks. Restart fair hrtick
+		 * if the queued tick path marked it as needed.
+		 */
+		hrtick_rearm_fair(rq, next);
 		return;
+	}
 
 	prev->sched_class->put_prev_task(rq, prev, next);
 	next->sched_class->set_next_task(rq, next, true);

---
base-commit: 3aa1dcaa4f6f5ae08936491e08bd456f331f2d40
change-id: 20260813-sched-fair-hrtick-restart-ab9d3d47ef78

Best regards,
-- 
Shubhang Kaushik (Ampere) <sh@gentwo.org>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-08-13 21:23 [PATCH] sched/fair: Restart hrtick after same-task repicks Shubhang Kaushik (Ampere)
@ 2026-08-26  1:13 ` Shubhang
  2026-08-26  4:00 ` Zhan Xusheng
  2026-09-11 11:20 ` Peter Zijlstra
  2 siblings, 0 replies; 9+ messages in thread
From: Shubhang @ 2026-08-26  1:13 UTC (permalink / raw)
  To: Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot,
	Dietmar Eggemann, Steven Rostedt, Ben Segall, Mel Gorman,
	Valentin Schneider, K Prateek Nayak, Shubhang Kaushik,
	Christoph Lameter
  Cc: linux-kernel

Hello everyone,

A gentle ping for this patch, sent on August 13.

A fair hrtick is one-shot. When it expires and schedule() selects the
current fair task again, the next == prev path skips
set_next_task_fair(), which normally starts the next fair hrtick.
Consequently, no new fair hrtick is armed after that same-task repick.

The patch starts a new one-shot fair hrtick only in this next == prev
path, and only when all queued fair entities are runnable
(h_nr_runnable == h_nr_queued).

Could you please comment on whether this is the appropriate point and
condition for starting the next fair hrtick?

Thanks,
Shubhang Kaushik

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-08-13 21:23 [PATCH] sched/fair: Restart hrtick after same-task repicks Shubhang Kaushik (Ampere)
  2026-08-26  1:13 ` Shubhang
@ 2026-08-26  4:00 ` Zhan Xusheng
  2026-09-10 21:14   ` Shubhang
  2026-09-11 11:20 ` Peter Zijlstra
  2 siblings, 1 reply; 9+ messages in thread
From: Zhan Xusheng @ 2026-08-26  4:00 UTC (permalink / raw)
  To: sh
  Cc: mingo, peterz, juri.lelli, vincent.guittot, dietmar.eggemann,
	rostedt, bsegall, mgorman, vschneid, kprateek.nayak, shubhang,
	cl, linux-kernel, zhanxusheng

From: Zhan Xusheng <zhanxusheng@xiaomi.com>

On Thu, 13 Aug 2026 14:23:48 -0700, Shubhang Kaushik (Ampere) wrote:
> +		rq->hrtick_rearm_fair = hrtick_enabled_fair(rq) &&
> +				rq->cfs.h_nr_runnable > 1 &&
> +				rq->cfs.h_nr_runnable == rq->cfs.h_nr_queued;

The last term switches the fix off whenever anything on the rq sits in
delayed dequeue.  set_delayed() decrements h_nr_runnable and leaves
h_nr_queued alone (kernel/sched/fair.c:6398), clear_delayed() puts it
back (6418), so the two differ exactly while a delay-dequeued entity is
present.  With DELAY_DEQUEUE that is routine, and it says nothing about
whether the running task still needs its slice bounded.

Your test cannot show that either way: two CPU-bound tasks pinned to one
CPU never sleep, so nothing is ever delay-dequeued there and the term is
true for the whole run.  Adding a third task that sleeps in a loop should
bring the missed hrtick back while the term is false.

If the intent is only to skip rqs whose other queued entities are not
competing for the CPU, h_nr_runnable > 1 already says that by itself.

> +static inline void hrtick_rearm_fair(struct rq *rq, struct task_struct *p)
> +{
> +	if (rq->hrtick_rearm_fair)
> +		__hrtick_rearm_fair(rq, p);
> +}

What does the rq field buy?  __hrtick_rearm_fair() already tests
hrtick_enabled_fair(), hrtick_active() and the class, and a same-task
repick that finds no hrtick armed wants one regardless of what triggered
the repick.  If there is a same-task repick that must not arm one, the
changelog is the place to name it.

Last one is only a question.  entity_tick() -> update_curr() ->
update_deadline() has already pushed se->deadline by a slice before
task_tick_fair() reaches the queued branch, so hrtick_start_fair() would
compute a valid delay if called right there, with no new field and no
change to put_prev_set_next_task().  The difference I can see is that the
tick callback runs with rq->hrtick_sched == 0, so hrtick_start() would
program the hrtimer immediately from inside its own callback instead of
leaving it to hrtick_schedule_exit().  Is that what moved you to the pick
side?

Thanks,
Zhan Xusheng

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-08-26  4:00 ` Zhan Xusheng
@ 2026-09-10 21:14   ` Shubhang
  0 siblings, 0 replies; 9+ messages in thread
From: Shubhang @ 2026-09-10 21:14 UTC (permalink / raw)
  To: Zhan Xusheng
  Cc: mingo, peterz, juri.lelli, vincent.guittot, dietmar.eggemann,
	rostedt, bsegall, mgorman, vschneid, kprateek.nayak, shubhang,
	cl, linux-kernel, zhanxusheng

Hi Zhan,

Thanks for the review.

My original intent behind h_nr_runnable == h_nr_queued was to avoid
rearming an hrtick merely because delayed dequeued entities remain
queued. However, that condition also suppresses the rearm when there is
a real competing runnable entity plus an unrelated delayed entity. Which 
makes it be restrictive. I will change this to h_nr_runnable > 1 and add
a mixed workload test that exercises delayed dequeue.

Ack, I will also rework the rq flag. The reason I put the rearm on the
same task repick path was to retain the normal schedule side deferred
hrtick programming, rather than start a timer directly from the hrtick
callback. But the extra state does not appear necessary: the same task
path can check whether fair hrtick is enabled, inactive, and has another
runnable fair entity, then rearm directly.

Thanks,
Shubhang Kaushik

On Wed, 26 Aug 2026, Zhan Xusheng wrote:

> From: Zhan Xusheng <zhanxusheng@xiaomi.com>
>
> On Thu, 13 Aug 2026 14:23:48 -0700, Shubhang Kaushik (Ampere) wrote:
>> +		rq->hrtick_rearm_fair = hrtick_enabled_fair(rq) &&
>> +				rq->cfs.h_nr_runnable > 1 &&
>> +				rq->cfs.h_nr_runnable == rq->cfs.h_nr_queued;
>
> The last term switches the fix off whenever anything on the rq sits in
> delayed dequeue.  set_delayed() decrements h_nr_runnable and leaves
> h_nr_queued alone (kernel/sched/fair.c:6398), clear_delayed() puts it
> back (6418), so the two differ exactly while a delay-dequeued entity is
> present.  With DELAY_DEQUEUE that is routine, and it says nothing about
> whether the running task still needs its slice bounded.
>
> Your test cannot show that either way: two CPU-bound tasks pinned to one
> CPU never sleep, so nothing is ever delay-dequeued there and the term is
> true for the whole run.  Adding a third task that sleeps in a loop should
> bring the missed hrtick back while the term is false.
>
> If the intent is only to skip rqs whose other queued entities are not
> competing for the CPU, h_nr_runnable > 1 already says that by itself.
>
>> +static inline void hrtick_rearm_fair(struct rq *rq, struct task_struct *p)
>> +{
>> +	if (rq->hrtick_rearm_fair)
>> +		__hrtick_rearm_fair(rq, p);
>> +}
>
> What does the rq field buy?  __hrtick_rearm_fair() already tests
> hrtick_enabled_fair(), hrtick_active() and the class, and a same-task
> repick that finds no hrtick armed wants one regardless of what triggered
> the repick.  If there is a same-task repick that must not arm one, the
> changelog is the place to name it.
>
> Last one is only a question.  entity_tick() -> update_curr() ->
> update_deadline() has already pushed se->deadline by a slice before
> task_tick_fair() reaches the queued branch, so hrtick_start_fair() would
> compute a valid delay if called right there, with no new field and no
> change to put_prev_set_next_task().  The difference I can see is that the
> tick callback runs with rq->hrtick_sched == 0, so hrtick_start() would
> program the hrtimer immediately from inside its own callback instead of
> leaving it to hrtick_schedule_exit().  Is that what moved you to the pick
> side?
>
> Thanks,
> Zhan Xusheng
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-08-13 21:23 [PATCH] sched/fair: Restart hrtick after same-task repicks Shubhang Kaushik (Ampere)
  2026-08-26  1:13 ` Shubhang
  2026-08-26  4:00 ` Zhan Xusheng
@ 2026-09-11 11:20 ` Peter Zijlstra
  2026-09-11 12:36   ` Vincent Guittot
  2026-09-11 18:56   ` Shubhang
  2 siblings, 2 replies; 9+ messages in thread
From: Peter Zijlstra @ 2026-09-11 11:20 UTC (permalink / raw)
  To: Shubhang Kaushik (Ampere)
  Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
	Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
	K Prateek Nayak, Shubhang Kaushik, Christoph Lameter,
	linux-kernel

On Thu, Aug 13, 2026 at 02:23:48PM -0700, Shubhang Kaushik (Ampere) wrote:
> Fair hrtick is implemented with a one-shot timer, so each precise
> preemption point has to be programmed explicitly. The usual fair path
> does this from set_next_task_fair(), which calls hrtick_start_fair().
> 
> The missed path is:
> 
>   hrtick
>     -> task_tick_fair(..., queued=1)
>        -> entity_tick()
> 	  -> resched_curr()
>     -> schedule()
>        -> pick_task_fair() picks current again
>        -> put_prev_set_next_task()
> 	  -> next == prev
> 	  -> return
> 
> Since set_next_task_fair() is skipped, hrtick_start_fair() is not called
> and no new fair hrtick is started.

Indeed. However, you missed this is also true for DL.

Does something like the below work for you?

---
 kernel/sched/core.c      |  2 +-
 kernel/sched/deadline.c  |  8 ++++++--
 kernel/sched/ext/ext.c   |  5 ++++-
 kernel/sched/fair.c      | 15 ++++++++++-----
 kernel/sched/idle.c      |  5 ++++-
 kernel/sched/rt.c        |  7 +++++--
 kernel/sched/sched.h     | 16 ++++++++++++----
 kernel/sched/stop_task.c |  5 ++++-
 8 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 91f059a55695..a39d12d38070 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7241,7 +7241,7 @@ static void __sched notrace __schedule(int sched_mode)
 			 * on_cpu.
 			 */
 			donor->sched_class->put_prev_task(rq, donor, donor);
-			donor->sched_class->set_next_task(rq, donor, true);
+			donor->sched_class->set_next_task(rq, donor, SNT_PICK);
 		}
 	} else {
 		rq_set_donor(rq, next);
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index de6a361a87c7..21d904d92c64 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -2773,11 +2773,14 @@ static void start_hrtick_dl(struct rq *rq, struct sched_dl_entity *dl_se)
  * DL keeps current in tree, because ->deadline is not typically changed while
  * a task is runnable.
  */
-static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
+static void set_next_task_dl(struct rq *rq, struct task_struct *p, enum snt_e type)
 {
 	struct sched_dl_entity *dl_se = &p->dl;
 	struct dl_rq *dl_rq = &rq->dl;
 
+	if (type == SNT_REPICK)
+		goto repick;
+
 	p->se.exec_start = rq_clock_task(rq);
 	if (on_dl_rq(&p->dl))
 		update_stats_wait_end_dl(dl_rq, dl_se);
@@ -2788,7 +2791,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
 	WARN_ON_ONCE(dl_rq->curr);
 	dl_rq->curr = dl_se;
 
-	if (!first)
+	if (type != SNT_PICK)
 		return;
 
 	if (rq->donor->sched_class != &dl_sched_class)
@@ -2796,6 +2799,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
 
 	deadline_queue_push_tasks(rq);
 
+repick:
 	if (hrtick_enabled_dl(rq))
 		start_hrtick_dl(rq, &p->dl);
 }
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index 51de1d8b72a1..31a300f2d3b2 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -3003,10 +3003,13 @@ static enum scx_dsp_verdict dispatch_one(struct rq *rq, struct task_struct *prev
 	return verdict;
 }
 
-static void set_next_task_scx(struct rq *rq, struct task_struct *p, bool first)
+static void set_next_task_scx(struct rq *rq, struct task_struct *p, enum snt_e type)
 {
 	struct scx_sched *sch = scx_task_sched(p);
 
+	if (type == SNT_REPICK)
+		return;
+
 	if (p->scx.flags & SCX_TASK_QUEUED) {
 		/*
 		 * Core-sched might decide to execute @p before it is
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 4d0b94465d19..f469e469b402 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -15242,14 +15242,18 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p)
 	}
 }
 
-static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
+static void set_next_task_fair(struct rq *rq, struct task_struct *p, enum snt_e type)
 {
 	struct sched_entity *se = &p->se;
-	bool throttled = false;
 	struct cfs_rq *cfs_rq = &rq->cfs;
 	unsigned long weight = NICE_0_LOAD;
+	bool first = type == SNT_PICK;
+	bool throttled = false;
 	bool on_rq = se->on_rq;
 
+	if (type == SNT_REPICK)
+		goto repick;
+
 	clear_buddies(cfs_rq, se);
 
 	if (on_rq)
@@ -15293,11 +15297,12 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
 
 	WARN_ON_ONCE(se->sched_delayed);
 
-	if (hrtick_enabled_fair(rq))
-		hrtick_start_fair(rq, p);
-
 	update_misfit_status(p, rq);
 	sched_fair_update_stop_tick(rq, p);
+
+repick:
+	if (hrtick_enabled_fair(rq))
+		hrtick_start_fair(rq, p);
 }
 
 void init_cfs_rq(struct cfs_rq *cfs_rq)
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index eb73b65ce6c4..76f3c84ca684 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -487,8 +487,11 @@ static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, struct t
 	update_rq_avg_idle(rq);
 }
 
-static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
+static void set_next_task_idle(struct rq *rq, struct task_struct *next, enum snt_e type)
 {
+	if (type == SNT_REPICK)
+		return;
+
 	update_idle_core(rq);
 	scx_update_idle(rq, true, true);
 	schedstat_inc(rq->sched_goidle);
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 85303add726d..1535046a23ff 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1654,11 +1654,14 @@ static void wakeup_preempt_rt(struct rq *rq, struct task_struct *p, int flags)
 		check_preempt_equal_prio(rq, p);
 }
 
-static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool first)
+static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, enum snt_e type)
 {
 	struct sched_rt_entity *rt_se = &p->rt;
 	struct rt_rq *rt_rq = &rq->rt;
 
+	if (type == SNT_REPICK)
+		return;
+
 	p->se.exec_start = rq_clock_task(rq);
 	if (on_rt_rq(&p->rt))
 		update_stats_wait_end_rt(rt_rq, rt_se);
@@ -1666,7 +1669,7 @@ static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool f
 	/* The running task is never eligible for pushing */
 	dequeue_pushable_task(rq, p);
 
-	if (!first)
+	if (type != SNT_PICK)
 		return;
 
 	/*
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 6c3ad70e58b8..944366e2d142 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -2630,6 +2630,12 @@ struct affinity_context {
 
 extern s64 update_curr_common(struct rq *rq);
 
+enum snt_e {
+	SNT_NORMAL,
+	SNT_PICK,
+	SNT_REPICK,
+};
+
 struct sched_class {
 
 #ifdef CONFIG_UCLAMP_TASK
@@ -2687,7 +2693,7 @@ struct sched_class {
 	 * __schedule: rq->lock
 	 */
 	void (*put_prev_task)(struct rq *rq, struct task_struct *p, struct task_struct *next);
-	void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);
+	void (*set_next_task)(struct rq *rq, struct task_struct *p, enum snt_e type);
 
 	/*
 	 * select_task_rq: p->pi_lock
@@ -2790,7 +2796,7 @@ static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 
 static inline void set_next_task(struct rq *rq, struct task_struct *next)
 {
-	next->sched_class->set_next_task(rq, next, false);
+	next->sched_class->set_next_task(rq, next, SNT_NORMAL);
 }
 
 static inline void
@@ -2811,11 +2817,13 @@ static inline void put_prev_set_next_task(struct rq *rq,
 
 	__put_prev_set_next_dl_server(rq, prev, next);
 
-	if (next == prev)
+	if (next == prev) {
+		next->sched_class->set_next_task(rq, next, SNT_REPICK);
 		return;
+	}
 
 	prev->sched_class->put_prev_task(rq, prev, next);
-	next->sched_class->set_next_task(rq, next, true);
+	next->sched_class->set_next_task(rq, next, SNT_PICK);
 }
 
 /*
diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c
index c909ca0d8c87..1e0109ec36b3 100644
--- a/kernel/sched/stop_task.c
+++ b/kernel/sched/stop_task.c
@@ -27,8 +27,11 @@ wakeup_preempt_stop(struct rq *rq, struct task_struct *p, int flags)
 	/* we're never preempted */
 }
 
-static void set_next_task_stop(struct rq *rq, struct task_struct *stop, bool first)
+static void set_next_task_stop(struct rq *rq, struct task_struct *stop, enum snt_e type)
 {
+	if (type == SNT_REPICK)
+		return;
+
 	stop->se.exec_start = rq_clock_task(rq);
 }
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-09-11 11:20 ` Peter Zijlstra
@ 2026-09-11 12:36   ` Vincent Guittot
  2026-09-11 13:59     ` Peter Zijlstra
  2026-09-11 18:56   ` Shubhang
  1 sibling, 1 reply; 9+ messages in thread
From: Vincent Guittot @ 2026-09-11 12:36 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Shubhang Kaushik (Ampere),
	Ingo Molnar, Juri Lelli, Dietmar Eggemann, Steven Rostedt,
	Ben Segall, Mel Gorman, Valentin Schneider, K Prateek Nayak,
	Shubhang Kaushik, Christoph Lameter, linux-kernel

On Fri, 11 Sept 2026 at 13:21, Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Thu, Aug 13, 2026 at 02:23:48PM -0700, Shubhang Kaushik (Ampere) wrote:
> > Fair hrtick is implemented with a one-shot timer, so each precise
> > preemption point has to be programmed explicitly. The usual fair path
> > does this from set_next_task_fair(), which calls hrtick_start_fair().
> >
> > The missed path is:
> >
> >   hrtick
> >     -> task_tick_fair(..., queued=1)
> >        -> entity_tick()
> >         -> resched_curr()
> >     -> schedule()
> >        -> pick_task_fair() picks current again
> >        -> put_prev_set_next_task()
> >         -> next == prev
> >         -> return
> >
> > Since set_next_task_fair() is skipped, hrtick_start_fair() is not called
> > and no new fair hrtick is started.
>
> Indeed. However, you missed this is also true for DL.
>
> Does something like the below work for you?
>
> ---
>  kernel/sched/core.c      |  2 +-
>  kernel/sched/deadline.c  |  8 ++++++--
>  kernel/sched/ext/ext.c   |  5 ++++-
>  kernel/sched/fair.c      | 15 ++++++++++-----
>  kernel/sched/idle.c      |  5 ++++-
>  kernel/sched/rt.c        |  7 +++++--
>  kernel/sched/sched.h     | 16 ++++++++++++----
>  kernel/sched/stop_task.c |  5 ++++-
>  8 files changed, 46 insertions(+), 17 deletions(-)
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 91f059a55695..a39d12d38070 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -7241,7 +7241,7 @@ static void __sched notrace __schedule(int sched_mode)
>                          * on_cpu.
>                          */
>                         donor->sched_class->put_prev_task(rq, donor, donor);
> -                       donor->sched_class->set_next_task(rq, donor, true);
> +                       donor->sched_class->set_next_task(rq, donor, SNT_PICK);
>                 }
>         } else {
>                 rq_set_donor(rq, next);
> diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
> index de6a361a87c7..21d904d92c64 100644
> --- a/kernel/sched/deadline.c
> +++ b/kernel/sched/deadline.c
> @@ -2773,11 +2773,14 @@ static void start_hrtick_dl(struct rq *rq, struct sched_dl_entity *dl_se)
>   * DL keeps current in tree, because ->deadline is not typically changed while
>   * a task is runnable.
>   */
> -static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
> +static void set_next_task_dl(struct rq *rq, struct task_struct *p, enum snt_e type)
>  {
>         struct sched_dl_entity *dl_se = &p->dl;
>         struct dl_rq *dl_rq = &rq->dl;
>
> +       if (type == SNT_REPICK)
> +               goto repick;
> +
>         p->se.exec_start = rq_clock_task(rq);
>         if (on_dl_rq(&p->dl))
>                 update_stats_wait_end_dl(dl_rq, dl_se);
> @@ -2788,7 +2791,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
>         WARN_ON_ONCE(dl_rq->curr);
>         dl_rq->curr = dl_se;
>
> -       if (!first)
> +       if (type != SNT_PICK)
>                 return;
>
>         if (rq->donor->sched_class != &dl_sched_class)
> @@ -2796,6 +2799,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
>
>         deadline_queue_push_tasks(rq);
>
> +repick:
>         if (hrtick_enabled_dl(rq))
>                 start_hrtick_dl(rq, &p->dl);
>  }
> diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
> index 51de1d8b72a1..31a300f2d3b2 100644
> --- a/kernel/sched/ext/ext.c
> +++ b/kernel/sched/ext/ext.c
> @@ -3003,10 +3003,13 @@ static enum scx_dsp_verdict dispatch_one(struct rq *rq, struct task_struct *prev
>         return verdict;
>  }
>
> -static void set_next_task_scx(struct rq *rq, struct task_struct *p, bool first)
> +static void set_next_task_scx(struct rq *rq, struct task_struct *p, enum snt_e type)
>  {
>         struct scx_sched *sch = scx_task_sched(p);
>
> +       if (type == SNT_REPICK)
> +               return;
> +
>         if (p->scx.flags & SCX_TASK_QUEUED) {
>                 /*
>                  * Core-sched might decide to execute @p before it is
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 4d0b94465d19..f469e469b402 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -15242,14 +15242,18 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p)
>         }
>  }
>
> -static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
> +static void set_next_task_fair(struct rq *rq, struct task_struct *p, enum snt_e type)
>  {
>         struct sched_entity *se = &p->se;
> -       bool throttled = false;
>         struct cfs_rq *cfs_rq = &rq->cfs;
>         unsigned long weight = NICE_0_LOAD;
> +       bool first = type == SNT_PICK;
> +       bool throttled = false;
>         bool on_rq = se->on_rq;
>
> +       if (type == SNT_REPICK)
> +               goto repick;
> +
>         clear_buddies(cfs_rq, se);
>
>         if (on_rq)
> @@ -15293,11 +15297,12 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
>
>         WARN_ON_ONCE(se->sched_delayed);
>
> -       if (hrtick_enabled_fair(rq))
> -               hrtick_start_fair(rq, p);
> -
>         update_misfit_status(p, rq);
>         sched_fair_update_stop_tick(rq, p);
> +
> +repick:
> +       if (hrtick_enabled_fair(rq))
> +               hrtick_start_fair(rq, p);

While at it, you might want to replace:
vdelta = se->deadline - se->vruntime;
by
vdelta = se->vprot - se->vruntime;
in hrtick_start_fair()

>  }
>
>  void init_cfs_rq(struct cfs_rq *cfs_rq)
> diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
> index eb73b65ce6c4..76f3c84ca684 100644
> --- a/kernel/sched/idle.c
> +++ b/kernel/sched/idle.c
> @@ -487,8 +487,11 @@ static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, struct t
>         update_rq_avg_idle(rq);
>  }
>
> -static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
> +static void set_next_task_idle(struct rq *rq, struct task_struct *next, enum snt_e type)
>  {
> +       if (type == SNT_REPICK)
> +               return;
> +
>         update_idle_core(rq);
>         scx_update_idle(rq, true, true);
>         schedstat_inc(rq->sched_goidle);
> diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
> index 85303add726d..1535046a23ff 100644
> --- a/kernel/sched/rt.c
> +++ b/kernel/sched/rt.c
> @@ -1654,11 +1654,14 @@ static void wakeup_preempt_rt(struct rq *rq, struct task_struct *p, int flags)
>                 check_preempt_equal_prio(rq, p);
>  }
>
> -static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool first)
> +static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, enum snt_e type)
>  {
>         struct sched_rt_entity *rt_se = &p->rt;
>         struct rt_rq *rt_rq = &rq->rt;
>
> +       if (type == SNT_REPICK)
> +               return;
> +
>         p->se.exec_start = rq_clock_task(rq);
>         if (on_rt_rq(&p->rt))
>                 update_stats_wait_end_rt(rt_rq, rt_se);
> @@ -1666,7 +1669,7 @@ static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool f
>         /* The running task is never eligible for pushing */
>         dequeue_pushable_task(rq, p);
>
> -       if (!first)
> +       if (type != SNT_PICK)
>                 return;
>
>         /*
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index 6c3ad70e58b8..944366e2d142 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -2630,6 +2630,12 @@ struct affinity_context {
>
>  extern s64 update_curr_common(struct rq *rq);
>
> +enum snt_e {
> +       SNT_NORMAL,
> +       SNT_PICK,
> +       SNT_REPICK,
> +};
> +
>  struct sched_class {
>
>  #ifdef CONFIG_UCLAMP_TASK
> @@ -2687,7 +2693,7 @@ struct sched_class {
>          * __schedule: rq->lock
>          */
>         void (*put_prev_task)(struct rq *rq, struct task_struct *p, struct task_struct *next);
> -       void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);
> +       void (*set_next_task)(struct rq *rq, struct task_struct *p, enum snt_e type);
>
>         /*
>          * select_task_rq: p->pi_lock
> @@ -2790,7 +2796,7 @@ static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
>
>  static inline void set_next_task(struct rq *rq, struct task_struct *next)
>  {
> -       next->sched_class->set_next_task(rq, next, false);
> +       next->sched_class->set_next_task(rq, next, SNT_NORMAL);
>  }
>
>  static inline void
> @@ -2811,11 +2817,13 @@ static inline void put_prev_set_next_task(struct rq *rq,
>
>         __put_prev_set_next_dl_server(rq, prev, next);
>
> -       if (next == prev)
> +       if (next == prev) {
> +               next->sched_class->set_next_task(rq, next, SNT_REPICK);
>                 return;
> +       }
>
>         prev->sched_class->put_prev_task(rq, prev, next);
> -       next->sched_class->set_next_task(rq, next, true);
> +       next->sched_class->set_next_task(rq, next, SNT_PICK);
>  }
>
>  /*
> diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c
> index c909ca0d8c87..1e0109ec36b3 100644
> --- a/kernel/sched/stop_task.c
> +++ b/kernel/sched/stop_task.c
> @@ -27,8 +27,11 @@ wakeup_preempt_stop(struct rq *rq, struct task_struct *p, int flags)
>         /* we're never preempted */
>  }
>
> -static void set_next_task_stop(struct rq *rq, struct task_struct *stop, bool first)
> +static void set_next_task_stop(struct rq *rq, struct task_struct *stop, enum snt_e type)
>  {
> +       if (type == SNT_REPICK)
> +               return;
> +
>         stop->se.exec_start = rq_clock_task(rq);
>  }
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-09-11 12:36   ` Vincent Guittot
@ 2026-09-11 13:59     ` Peter Zijlstra
  2026-09-11 14:09       ` Vincent Guittot
  0 siblings, 1 reply; 9+ messages in thread
From: Peter Zijlstra @ 2026-09-11 13:59 UTC (permalink / raw)
  To: Vincent Guittot
  Cc: Shubhang Kaushik (Ampere),
	Ingo Molnar, Juri Lelli, Dietmar Eggemann, Steven Rostedt,
	Ben Segall, Mel Gorman, Valentin Schneider, K Prateek Nayak,
	Shubhang Kaushik, Christoph Lameter, linux-kernel

On Fri, Sep 11, 2026 at 02:36:41PM +0200, Vincent Guittot wrote:

> > @@ -15293,11 +15297,12 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
> >
> >         WARN_ON_ONCE(se->sched_delayed);
> >
> > -       if (hrtick_enabled_fair(rq))
> > -               hrtick_start_fair(rq, p);
> > -
> >         update_misfit_status(p, rq);
> >         sched_fair_update_stop_tick(rq, p);
> > +
> > +repick:
> > +       if (hrtick_enabled_fair(rq))
> > +               hrtick_start_fair(rq, p);
> 
> While at it, you might want to replace:
> vdelta = se->deadline - se->vruntime;
> by
> vdelta = se->vprot - se->vruntime;
> in hrtick_start_fair()

That should be a separate patch.

> 
> >  }
> >
> >  void init_cfs_rq(struct cfs_rq *cfs_rq)

But that made me thing; do we want something like so folded in here?

Since we got picked again, we should set vprot again, no?

---
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -15279,11 +15279,8 @@ static void set_next_task_fair(struct rq
 	se = &p->se;
 	cfs_rq->curr = se;
 
-	if (on_rq) {
+	if (on_rq)
 		reweight_eevdf(cfs_rq, se, weight, se->on_rq);
-		if (first)
-			set_protect_slice(cfs_rq, se);
-	}
 
 	if (task_on_rq_queued(p)) {
 		/*
@@ -15301,6 +15298,9 @@ static void set_next_task_fair(struct rq
 	sched_fair_update_stop_tick(rq, p);
 
 repick:
+	if (on_rq)
+		set_protect_slice(cfs_rq, se);
+
 	if (hrtick_enabled_fair(rq))
 		hrtick_start_fair(rq, p);
 }

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-09-11 13:59     ` Peter Zijlstra
@ 2026-09-11 14:09       ` Vincent Guittot
  0 siblings, 0 replies; 9+ messages in thread
From: Vincent Guittot @ 2026-09-11 14:09 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Shubhang Kaushik (Ampere),
	Ingo Molnar, Juri Lelli, Dietmar Eggemann, Steven Rostedt,
	Ben Segall, Mel Gorman, Valentin Schneider, K Prateek Nayak,
	Shubhang Kaushik, Christoph Lameter, linux-kernel

On Fri, 11 Sept 2026 at 15:59, Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Fri, Sep 11, 2026 at 02:36:41PM +0200, Vincent Guittot wrote:
>
> > > @@ -15293,11 +15297,12 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
> > >
> > >         WARN_ON_ONCE(se->sched_delayed);
> > >
> > > -       if (hrtick_enabled_fair(rq))
> > > -               hrtick_start_fair(rq, p);
> > > -
> > >         update_misfit_status(p, rq);
> > >         sched_fair_update_stop_tick(rq, p);
> > > +
> > > +repick:
> > > +       if (hrtick_enabled_fair(rq))
> > > +               hrtick_start_fair(rq, p);
> >
> > While at it, you might want to replace:
> > vdelta = se->deadline - se->vruntime;
> > by
> > vdelta = se->vprot - se->vruntime;
> > in hrtick_start_fair()
>
> That should be a separate patch.

ok

>
> >
> > >  }
> > >
> > >  void init_cfs_rq(struct cfs_rq *cfs_rq)
>
> But that made me thing; do we want something like so folded in here?
>
> Since we got picked again, we should set vprot again, no?

No, because we want to allow picking another task as soon as the
current task has run at least its "min" slice and a new eligible task
is enqueued instead of waiting the end of the next period of slice

This also means that we can't simply replace deadline by vprot as i
proposed above because once we are after vprot we need deadline

>
> ---
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -15279,11 +15279,8 @@ static void set_next_task_fair(struct rq
>         se = &p->se;
>         cfs_rq->curr = se;
>
> -       if (on_rq) {
> +       if (on_rq)
>                 reweight_eevdf(cfs_rq, se, weight, se->on_rq);
> -               if (first)
> -                       set_protect_slice(cfs_rq, se);
> -       }
>
>         if (task_on_rq_queued(p)) {
>                 /*
> @@ -15301,6 +15298,9 @@ static void set_next_task_fair(struct rq
>         sched_fair_update_stop_tick(rq, p);
>
>  repick:
> +       if (on_rq)
> +               set_protect_slice(cfs_rq, se);
> +
>         if (hrtick_enabled_fair(rq))
>                 hrtick_start_fair(rq, p);
>  }

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] sched/fair: Restart hrtick after same-task repicks
  2026-09-11 11:20 ` Peter Zijlstra
  2026-09-11 12:36   ` Vincent Guittot
@ 2026-09-11 18:56   ` Shubhang
  1 sibling, 0 replies; 9+ messages in thread
From: Shubhang @ 2026-09-11 18:56 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Juri Lelli, Vincent Guittot, Dietmar Eggemann,
	Steven Rostedt, Ben Segall, Mel Gorman, Valentin Schneider,
	K Prateek Nayak, Shubhang Kaushik, Christoph Lameter,
	linux-kernel

Hi Peter,

On Fri, 11 Sep 2026, Peter Zijlstra wrote:

> On Thu, Aug 13, 2026 at 02:23:48PM -0700, Shubhang Kaushik (Ampere) wrote:
>> Fair hrtick is implemented with a one-shot timer, so each precise
>> preemption point has to be programmed explicitly. The usual fair path
>> does this from set_next_task_fair(), which calls hrtick_start_fair().
>>
>> The missed path is:
>>
>>   hrtick
>>     -> task_tick_fair(..., queued=1)
>>        -> entity_tick()
>> 	  -> resched_curr()
>>     -> schedule()
>>        -> pick_task_fair() picks current again
>>        -> put_prev_set_next_task()
>> 	  -> next == prev
>> 	  -> return
>>
>> Since set_next_task_fair() is skipped, hrtick_start_fair() is not called
>> and no new fair hrtick is started.
>
> Indeed. However, you missed this is also true for DL.
>
> Does something like the below work for you?
>

Yes, this works for me.

When schedule() selects the current task again, next == prev 
case returns from put_prev_set_next_task() without calling the selected
task's set_next_task() function. For a fair task, that means 
set_next_task_fair() is skipped, meaning hrtick_start_fair() is skipped.
For a deadline task, set_next_task_dl() and start_hrtick_dl() are skipped 
for the same reason.

Using SNT_REPICK makes this case explicit:

         next == prev
           -> next->sched_class->set_next_task(rq, next, SNT_REPICK)

set_next_task_fair(..., SNT_REPICK) can then bypass the normal
fair task selection work and restart only the fair hrtick. Likewise,
set_next_task_dl(..., SNT_REPICK) can restart only the DL hrtick.
This seems cleaner than the fair specific rq flag and runnable count 
checks in my patch. And it also fixes the DL case that I missed.

It also retains the reason I moved the restart to the pick side. This
call happens during schedule(), when rq->hrtick_sched is in its 
deferred state. Therefore hrtick_start() records the new delay and
hrtick_schedule_exit() rearms the hrtimer after scheduling completes,
rather than reprogramming it directly from the hrtick callback.

I will test this approach with the delayed dequeue workload and a DL
hrtick case, then send a v2 based on it.

On the vprot point, I agree with Vincent's follow-up i.e. SNT_REPICK
must not call set_protect_slice(). As doing so would extend the protected
minimum slice on every repick. Once vprot has passed, a newly eligible
task should be able to preempt before the current task reaches deadline. 
Will keep that as a separate fix.

Thanks,
Shubhang Kaushik

> ---
> kernel/sched/core.c      |  2 +-
> kernel/sched/deadline.c  |  8 ++++++--
> kernel/sched/ext/ext.c   |  5 ++++-
> kernel/sched/fair.c      | 15 ++++++++++-----
> kernel/sched/idle.c      |  5 ++++-
> kernel/sched/rt.c        |  7 +++++--
> kernel/sched/sched.h     | 16 ++++++++++++----
> kernel/sched/stop_task.c |  5 ++++-
> 8 files changed, 46 insertions(+), 17 deletions(-)
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 91f059a55695..a39d12d38070 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -7241,7 +7241,7 @@ static void __sched notrace __schedule(int sched_mode)
> 			 * on_cpu.
> 			 */
> 			donor->sched_class->put_prev_task(rq, donor, donor);
> -			donor->sched_class->set_next_task(rq, donor, true);
> +			donor->sched_class->set_next_task(rq, donor, SNT_PICK);
> 		}
> 	} else {
> 		rq_set_donor(rq, next);
> diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
> index de6a361a87c7..21d904d92c64 100644
> --- a/kernel/sched/deadline.c
> +++ b/kernel/sched/deadline.c
> @@ -2773,11 +2773,14 @@ static void start_hrtick_dl(struct rq *rq, struct sched_dl_entity *dl_se)
>  * DL keeps current in tree, because ->deadline is not typically changed while
>  * a task is runnable.
>  */
> -static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
> +static void set_next_task_dl(struct rq *rq, struct task_struct *p, enum snt_e type)
> {
> 	struct sched_dl_entity *dl_se = &p->dl;
> 	struct dl_rq *dl_rq = &rq->dl;
>
> +	if (type == SNT_REPICK)
> +		goto repick;
> +
> 	p->se.exec_start = rq_clock_task(rq);
> 	if (on_dl_rq(&p->dl))
> 		update_stats_wait_end_dl(dl_rq, dl_se);
> @@ -2788,7 +2791,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
> 	WARN_ON_ONCE(dl_rq->curr);
> 	dl_rq->curr = dl_se;
>
> -	if (!first)
> +	if (type != SNT_PICK)
> 		return;
>
> 	if (rq->donor->sched_class != &dl_sched_class)
> @@ -2796,6 +2799,7 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
>
> 	deadline_queue_push_tasks(rq);
>
> +repick:
> 	if (hrtick_enabled_dl(rq))
> 		start_hrtick_dl(rq, &p->dl);
> }
> diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
> index 51de1d8b72a1..31a300f2d3b2 100644
> --- a/kernel/sched/ext/ext.c
> +++ b/kernel/sched/ext/ext.c
> @@ -3003,10 +3003,13 @@ static enum scx_dsp_verdict dispatch_one(struct rq *rq, struct task_struct *prev
> 	return verdict;
> }
>
> -static void set_next_task_scx(struct rq *rq, struct task_struct *p, bool first)
> +static void set_next_task_scx(struct rq *rq, struct task_struct *p, enum snt_e type)
> {
> 	struct scx_sched *sch = scx_task_sched(p);
>
> +	if (type == SNT_REPICK)
> +		return;
> +
> 	if (p->scx.flags & SCX_TASK_QUEUED) {
> 		/*
> 		 * Core-sched might decide to execute @p before it is
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 4d0b94465d19..f469e469b402 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -15242,14 +15242,18 @@ static void switched_to_fair(struct rq *rq, struct task_struct *p)
> 	}
> }
>
> -static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
> +static void set_next_task_fair(struct rq *rq, struct task_struct *p, enum snt_e type)
> {
> 	struct sched_entity *se = &p->se;
> -	bool throttled = false;
> 	struct cfs_rq *cfs_rq = &rq->cfs;
> 	unsigned long weight = NICE_0_LOAD;
> +	bool first = type == SNT_PICK;
> +	bool throttled = false;
> 	bool on_rq = se->on_rq;
>
> +	if (type == SNT_REPICK)
> +		goto repick;
> +
> 	clear_buddies(cfs_rq, se);
>
> 	if (on_rq)
> @@ -15293,11 +15297,12 @@ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool first)
>
> 	WARN_ON_ONCE(se->sched_delayed);
>
> -	if (hrtick_enabled_fair(rq))
> -		hrtick_start_fair(rq, p);
> -
> 	update_misfit_status(p, rq);
> 	sched_fair_update_stop_tick(rq, p);
> +
> +repick:
> +	if (hrtick_enabled_fair(rq))
> +		hrtick_start_fair(rq, p);
> }
>
> void init_cfs_rq(struct cfs_rq *cfs_rq)
> diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
> index eb73b65ce6c4..76f3c84ca684 100644
> --- a/kernel/sched/idle.c
> +++ b/kernel/sched/idle.c
> @@ -487,8 +487,11 @@ static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, struct t
> 	update_rq_avg_idle(rq);
> }
>
> -static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
> +static void set_next_task_idle(struct rq *rq, struct task_struct *next, enum snt_e type)
> {
> +	if (type == SNT_REPICK)
> +		return;
> +
> 	update_idle_core(rq);
> 	scx_update_idle(rq, true, true);
> 	schedstat_inc(rq->sched_goidle);
> diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
> index 85303add726d..1535046a23ff 100644
> --- a/kernel/sched/rt.c
> +++ b/kernel/sched/rt.c
> @@ -1654,11 +1654,14 @@ static void wakeup_preempt_rt(struct rq *rq, struct task_struct *p, int flags)
> 		check_preempt_equal_prio(rq, p);
> }
>
> -static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool first)
> +static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, enum snt_e type)
> {
> 	struct sched_rt_entity *rt_se = &p->rt;
> 	struct rt_rq *rt_rq = &rq->rt;
>
> +	if (type == SNT_REPICK)
> +		return;
> +
> 	p->se.exec_start = rq_clock_task(rq);
> 	if (on_rt_rq(&p->rt))
> 		update_stats_wait_end_rt(rt_rq, rt_se);
> @@ -1666,7 +1669,7 @@ static inline void set_next_task_rt(struct rq *rq, struct task_struct *p, bool f
> 	/* The running task is never eligible for pushing */
> 	dequeue_pushable_task(rq, p);
>
> -	if (!first)
> +	if (type != SNT_PICK)
> 		return;
>
> 	/*
> diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
> index 6c3ad70e58b8..944366e2d142 100644
> --- a/kernel/sched/sched.h
> +++ b/kernel/sched/sched.h
> @@ -2630,6 +2630,12 @@ struct affinity_context {
>
> extern s64 update_curr_common(struct rq *rq);
>
> +enum snt_e {
> +	SNT_NORMAL,
> +	SNT_PICK,
> +	SNT_REPICK,
> +};
> +
> struct sched_class {
>
> #ifdef CONFIG_UCLAMP_TASK
> @@ -2687,7 +2693,7 @@ struct sched_class {
> 	 * __schedule: rq->lock
> 	 */
> 	void (*put_prev_task)(struct rq *rq, struct task_struct *p, struct task_struct *next);
> -	void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);
> +	void (*set_next_task)(struct rq *rq, struct task_struct *p, enum snt_e type);
>
> 	/*
> 	 * select_task_rq: p->pi_lock
> @@ -2790,7 +2796,7 @@ static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
>
> static inline void set_next_task(struct rq *rq, struct task_struct *next)
> {
> -	next->sched_class->set_next_task(rq, next, false);
> +	next->sched_class->set_next_task(rq, next, SNT_NORMAL);
> }
>
> static inline void
> @@ -2811,11 +2817,13 @@ static inline void put_prev_set_next_task(struct rq *rq,
>
> 	__put_prev_set_next_dl_server(rq, prev, next);
>
> -	if (next == prev)
> +	if (next == prev) {
> +		next->sched_class->set_next_task(rq, next, SNT_REPICK);
> 		return;
> +	}
>
> 	prev->sched_class->put_prev_task(rq, prev, next);
> -	next->sched_class->set_next_task(rq, next, true);
> +	next->sched_class->set_next_task(rq, next, SNT_PICK);
> }
>
> /*
> diff --git a/kernel/sched/stop_task.c b/kernel/sched/stop_task.c
> index c909ca0d8c87..1e0109ec36b3 100644
> --- a/kernel/sched/stop_task.c
> +++ b/kernel/sched/stop_task.c
> @@ -27,8 +27,11 @@ wakeup_preempt_stop(struct rq *rq, struct task_struct *p, int flags)
> 	/* we're never preempted */
> }
>
> -static void set_next_task_stop(struct rq *rq, struct task_struct *stop, bool first)
> +static void set_next_task_stop(struct rq *rq, struct task_struct *stop, enum snt_e type)
> {
> +	if (type == SNT_REPICK)
> +		return;
> +
> 	stop->se.exec_start = rq_clock_task(rq);
> }
>
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-09-11 19:06 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-13 21:23 [PATCH] sched/fair: Restart hrtick after same-task repicks Shubhang Kaushik (Ampere)
2026-08-26  1:13 ` Shubhang
2026-08-26  4:00 ` Zhan Xusheng
2026-09-10 21:14   ` Shubhang
2026-09-11 11:20 ` Peter Zijlstra
2026-09-11 12:36   ` Vincent Guittot
2026-09-11 13:59     ` Peter Zijlstra
2026-09-11 14:09       ` Vincent Guittot
2026-09-11 18:56   ` Shubhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®