* [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®