[PATCH 02/20 v3] sched/eevdf: Reset lag at wakeup when prev CPU has been idle
From: Vincent Guittot
Date: Fri Nov 06 2026 - 10:24:05 EST
When prev CPU entered idle while a task was sleeping, we assume that the
latter received enough running time and the lag can be cleared similarly to
what happens for a negative lag.
Track CPU's idle phase and save it when a task goes to sleep. Then check if
the local CPU entered idle while the task was sleeping when enqueuing the
waking task.
This only applies if the task didn't migrate at wakeup.
Suggested-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Signed-off-by: Vincent Guittot <vincent.guittot@xxxxxxxxxx>
---
include/linux/sched.h | 1 +
kernel/sched/fair.c | 14 ++++++++++++--
kernel/sched/sched.h | 1 +
3 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0cb03f9acfe3..3d31e9a698c3 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -593,6 +593,7 @@ struct sched_entity {
u64 vruntime;
/* Approximated virtual lag: */
s64 vlag;
+ u32 vlag_seq;
/* 'Protected' deadline, to give out minimum quantums: */
u64 vprot;
u64 slice;
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 5cd171f830d8..79f53811274e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -893,6 +893,7 @@ bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
vlag = min(vlag, 0);
}
se->vlag = vlag;
+ se->vlag_seq = cfs_rq->idle_seq;
return avruntime - vlag != se->vruntime;
}
@@ -945,12 +946,18 @@ void decay_entity_lag(struct cfs_rq *cfs_rq, struct task_struct *p, int flags)
if (vlag <= 0)
return;
- rq = rq_of(cfs_rq);
-
/* No fast access to prev rq task clock */
if (flags & ENQUEUE_MIGRATED)
return;
+ /* CPU has been idle in between so the lag has been removed */
+ if (se->vlag_seq != cfs_rq->idle_seq) {
+ se->vlag = 0;
+ return;
+ }
+
+ rq = rq_of(cfs_rq);
+
/* Compute sleep time */
delta_exec = rq_clock_task(rq) - se->exec_start;
if (unlikely(delta_exec <= 0))
@@ -8376,6 +8383,9 @@ static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags)
dequeue_hierarchy(p, flags);
+ if (!(flags & DEQUEUE_SAVE) && !cfs_rq->h_nr_queued)
+ cfs_rq->idle_seq++;
+
if (sched_feat(PLACE_REL_DEADLINE) && !task_sleep) {
se->deadline -= se->vruntime;
se->rel_deadline = 1;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 7d2ec527b8a2..24f9b7bd8f0f 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -689,6 +689,7 @@ struct cfs_rq {
u64 sum_weight;
u64 zero_vruntime;
unsigned int sum_shift;
+ u32 idle_seq;
#ifdef CONFIG_SCHED_CORE
unsigned int forceidle_seq;
--
2.53.0