Re: [PATCH 5/8] sched/eevdf: Reset lag when waking up on idle cpu

From: Vincent Guittot

Date: Tue Sep 22 2026 - 10:24:50 EST


On Tue, 22 Sept 2026 at 12:19, Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:
>
> On Mon, Sep 21, 2026 at 05:22:35PM +0200, Vincent Guittot wrote:
> > When several tasks wake up simultaneously on an idle CPU, their final vlag
> > will depend of the ordering as the first one will lose its lag but not
> > the next ones.
> > Reset the lag when the enqueue happens while no fair task has already been
> > picked et set as the running task.
> >
> > As a typical example:
> > CPU0 is idle
> > TA with vlag 0ms and TB with vlag 5ms wake up on CPU0 simultaneously.
> > Depending which grab the lock 1st the behavior will be different:
> > If TA is enqueued 1st, TB will be enqueued with a positive lag and will
> > be picked 1st.
> > But if TB is enqueued 1st, it will loose its positive vlag and both TA and
> > TB will have 0 vlag when fair will pick a task.
> >
> > Signed-off-by: Vincent Guittot <vincent.guittot@xxxxxxxxxx>
> > ---
> > kernel/sched/fair.c | 27 +++++++++++++++++----------
> > 1 file changed, 17 insertions(+), 10 deletions(-)
> >
> > diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> > index 4230954d10d0..739a3af60520 100644
> > --- a/kernel/sched/fair.c
> > +++ b/kernel/sched/fair.c
> > @@ -900,7 +900,7 @@ static __always_inline
> > void decay_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
> > {
> > s64 vlag = se->vlag;
> > - s64 delta_exec;
> > + struct rq *rq;
> >
> > WARN_ON_ONCE(se->on_rq);
> >
> > @@ -908,18 +908,25 @@ void decay_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
> > if (vlag <= 0)
> > return;
> >
> > - if (flags & ENQUEUE_MIGRATED)
> > - return;
> > + rq = rq_of(cfs_rq);
> >
> > - /* Compute the sleep time */
> > - delta_exec = rq_clock_task(rq_of(cfs_rq)) - se->exec_start;
> > - if (unlikely(delta_exec <= 0))
> > - return;
> > + if (rq->curr == rq->idle) {
> > + /* You can't claim any lag when waking on idle CPU */
> > + vlag = 0;
>
> Right. As I mentioned during OSPM, one of the crazy ideas I had was to
> do something like the below. All of the lag stuff only makes sense while
> there is contention.
>
> Now, I've not actually tried this -- and at the very least the migation
> case is broken. But it should very much capture the rq->curr == rq->idle
> case and then some.

Yes, I remember the discussion. This one really care about severals
tasks wake up simultaneously on an idle CPU but what we do with their
lags depend on the enqueue order before trying to pick one

I'm going to try your suggestion below and see how I can get it
working with migration too

>
>
> diff --git a/include/linux/sched.h b/include/linux/sched.h
> index dac15ec36d1e..70fe8fadafac 100644
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -592,6 +592,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 2ad46fb2eafe..3e3dde5f2117 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -898,6 +898,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;
> }
> @@ -6397,6 +6398,9 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
> if (flags & ENQUEUE_QUEUED)
> nr_queued -= 1;
>
> + if (se->vlag_seq != cfs_rq->idle_seq)
> + se->vlag = 0;
> +
> /*
> * Due to how V is constructed as the weighted average of entities,
> * adding tasks with positive lag, or removing tasks with negative lag
> @@ -8374,6 +8378,9 @@ static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags)
>
> dequeue_hierarchy(p, flags);
>
> + if (!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 6c3ad70e58b8..0f0edb77e235 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;