From: sashiko-bot@kernel.org
To: "Vincent Guittot" <vincent.guittot@linaro.org>,
sched-ext@lists.linux.dev
Subject: Re: [PATCH 01/20 v3] sched/eevdf: Decay positive lag of sleeping entities
Date: Fri, 06 Nov 2026 15:43:31 +0000 [thread overview]
Message-ID: <sashiko-outbox-201722@kernel.org> (raw)
In-Reply-To: <20261106151947.3991524-2-vincent.guittot@linaro.org>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] sched/eevdf: decay_entity_lag() uses stale PELT loads and
h_load
- [Medium] sched/eevdf: decay_entity_lag() uses zero or cross-CPU
exec_start
--
commit af61170f82add576c62982c6213d87ccfac0159f
Author: Vincent Guittot <vincent.guittot@linaro.org>
sched/eevdf: Decay positive lag of sleeping entities
This commit introduces decay_entity_lag() and calls it from
enqueue_task_fair() on wakeup to decay the positive virtual lag of sleeping
tasks based on their sleep duration and weight share on the previous
runqueue.
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 0feec172fd37e..5cd171f830d86 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -897,6 +897,91 @@ bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
> return avruntime - vlag != se->vruntime;
> }
>
> +/*
> + * Signed add and clamp on underflow.
> + *
> + * Explicitly do a load-store to ensure the intermediate value never hits
> + * memory. This allows lockless observations without ever seeing the negative
> + * values.
> + */
> +#define add_positive(_ptr, _val) do { \
> + typeof(_ptr) ptr = (_ptr); \
> + __signed_scalar_typeof(*ptr) val = (_val); \
> + typeof(*ptr) res, var = READ_ONCE(*ptr); \
> + \
> + res = var + val; \
> + \
> + if (val < 0 && res > var) \
> + res = 0; \
> + \
> + WRITE_ONCE(*ptr, res); \
> +} while (0)
> +
> +/*
> + * Remove and clamp on negative, from a local variable.
> + *
> + * A variant of sub_positive(), which does not use explicit load-store
> + * and is thus optimized for local variable updates.
> + */
> +#define lsub_positive(_ptr, _val) do { \
> + typeof(_ptr) ptr = (_ptr); \
> + *ptr -= min_t(typeof(*ptr), *ptr, _val); \
> +} while (0)
> +
> +static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq);
> +static unsigned long task_h_load(struct task_struct *p);
> +
> +static __always_inline
> +void decay_entity_lag(struct cfs_rq *cfs_rq, struct task_struct *p, int flags)
> +{
> + struct sched_entity *se = &p->se;
> + s64 delta_exec, vlag = se->vlag;
> + unsigned long cfs_load;
> + struct rq *rq;
> +
> + WARN_ON_ONCE(se->on_rq);
> +
> + /* Negative lag is managed by delayed dequeue path */
> + if (vlag <= 0)
> + return;
> +
> + rq = rq_of(cfs_rq);
> +
> + /* No fast access to prev rq task clock */
> + if (flags & ENQUEUE_MIGRATED)
> + return;
> +
> + /* Compute sleep time */
> + delta_exec = rq_clock_task(rq) - se->exec_start;
[Severity: Medium]
Can se->exec_start be zero or hold another CPU's task clock here even when
ENQUEUE_MIGRATED is not set?
When a task is migrated (for instance via proxy_migrate_task() or as a
sched_delayed task), enqueue_entity() clears se->exec_start to 0. If that
task is then dequeued before being picked to run (such as by
proxy_needs_return() in ttwu_runnable(), or when pick_next_entity() finishes
the delayed dequeue) and wakes on the same CPU, ENQUEUE_MIGRATED is not set,
so rq_clock_task(rq) - se->exec_start equals the full CPU task clock since
boot and zeroes se->vlag.
Similarly, under CONFIG_CFS_BANDWIDTH, if a throttled task is migrated onto a
destination cfs_rq that is also throttled, enqueue_task_fair() returns early
via enqueue_throttled_task(p) before enqueue_entity() can clear
se->exec_start, and tg_unthrottle_up() later calls enqueue_task_fair(rq, p,
ENQUEUE_WAKEUP) without ENQUEUE_MIGRATED. decay_entity_lag() then subtracts
the previous CPU's se->exec_start from the new CPU's rq_clock_task(rq) and
subtracts an unattached task_h_load(p) from cfs_load.
> + if (unlikely(delta_exec <= 0))
> + return;
> +
> + /* For anything above ~4 seconds, save computation and clear the lag */
> + if (unlikely(delta_exec >> 32)) {
> + se->vlag = 0;
> + return;
> + }
> +
> + /*
> + * Use cfs' load and p's weight to estimate what would have been the
> + * share for p. task's load contribution to cfs' load is replaced by
> + * its weight.
> + */
> + cfs_load = cfs_rq_load_avg(cfs_rq);
> + lsub_positive(&cfs_load, task_h_load(p));
> + if (cfs_load) {
> + unsigned long weight = scale_load_down(se->h_load.weight);
> +
> + delta_exec *= weight;
> + delta_exec = div64_long(delta_exec, cfs_load + weight);
> + }
> +
> + vlag -= calc_delta_fair(delta_exec, se);
> +
> + /* vlag can't become neg while sleeping */
> + se->vlag = max(0, vlag);
> +}
[ ... ]
> @@ -8185,6 +8238,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
> if (p->in_iowait)
> cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT);
>
> + if (task_wake)
> + decay_entity_lag(cfs_rq, p, flags);
[Severity: Medium]
Does calling decay_entity_lag() before enqueue_hierarchy() and
reweight_eevdf() use stale PELT load averages and a stale se->h_load.weight?
When p wakes on its previous CPU without sync_entity_load_avg() having run
(for example via the select_idle_sibling() fast path), p->se.avg.load_avg is
still at its pre-sleep value because update_load_avg() is only called inside
enqueue_hierarchy() -> enqueue_entity(). Meanwhile, if other tasks ran on rq
while p slept, p's blocked load contribution inside cfs_rq->avg.load_avg has
already decayed; subtracting the undecayed task_h_load(p) from the decayed
cfs_rq_load_avg(cfs_rq) eats into the active load of the other tasks (often
clamping cfs_load to 0) and over-decays p->se.vlag as if the CPU had been
idle.
Under CONFIG_FAIR_GROUP_SCHED, calling task_h_load(p) before
enqueue_hierarchy() also invokes update_cfs_rq_h_load() on unsynchronized
group PELT averages and caches that stale cfs_rq->h_load for the rest of the
current jiffy. In addition, if p was reniced or had its group shares changed
while sleeping, reweight_task_fair() returned early while !se->on_rq, so
se->h_load.weight is not updated until enqueue_hierarchy() and
reweight_eevdf() run below.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261106151947.3991524-2-vincent.guittot@linaro.org?part=1
next prev parent reply other threads:[~2026-11-06 15:43 UTC|newest]
Thread overview: 67+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 15:19 [PATCH 00/18 v3] Improving latency of short slice tasks Vincent Guittot
2026-11-06 15:19 ` [PATCH 01/20 v3] sched/eevdf: Decay positive lag of sleeping entities Vincent Guittot
2026-11-06 15:43 ` sashiko-bot [this message]
2026-11-06 15:19 ` [PATCH 02/20 v3] sched/eevdf: Reset lag at wakeup when prev CPU has been idle Vincent Guittot
2026-11-06 16:22 ` Kayra Cizmeci
2026-11-09 15:27 ` Vincent Guittot
2026-11-09 15:45 ` Peter Zijlstra
2026-11-09 16:27 ` Vincent Guittot
2026-11-11 9:03 ` Peter Zijlstra
2026-11-12 7:02 ` Vincent Guittot
2026-11-11 10:04 ` K Prateek Nayak
2026-11-12 7:33 ` Vincent Guittot
2026-11-06 15:19 ` [PATCH 03/20 v3] sched/eevdf: Reset lag at wakeup when migrating and prev " Vincent Guittot
2026-11-06 18:05 ` Kayra Cizmeci
2026-11-06 15:19 ` [PATCH 04/20 v3] sched/eevdf: Reset lag when waking up on idle cpu Vincent Guittot
2026-11-06 18:39 ` Kayra Cizmeci
2026-11-06 15:19 ` [PATCH 05/20 v3] sched/eevdf: Add per cpu cached min_slice Vincent Guittot
2026-11-07 6:53 ` Kayra Cizmeci
2026-11-09 15:27 ` Vincent Guittot
2026-11-06 15:19 ` [PATCH 06/20 v3] sched/eevdf: Add min slice check when selecting CPU Vincent Guittot
2026-11-06 15:40 ` sashiko-bot
2026-11-07 8:57 ` Kayra Cizmeci
2026-11-09 13:55 ` Peter Zijlstra
2026-11-09 14:15 ` Kayra Cizmeci
2026-11-09 15:37 ` Vincent Guittot
2026-11-09 15:34 ` Vincent Guittot
2026-11-09 15:55 ` Vincent Guittot
2026-11-09 19:56 ` Kayra Cizmeci
2026-11-10 13:32 ` Vincent Guittot
2026-11-06 15:19 ` [PATCH 07/20 v3] sched/fair: Prepare select_task_rq_fair() to be called for new cases Vincent Guittot
2026-11-06 15:39 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 08/20 v3] sched/fair: Add push task mechanism for fair Vincent Guittot
2026-11-06 16:15 ` sashiko-bot
2026-11-09 14:43 ` Peter Zijlstra
2026-11-09 16:07 ` Vincent Guittot
2026-11-11 8:59 ` Peter Zijlstra
2026-11-12 7:01 ` Vincent Guittot
2026-11-09 15:54 ` Peter Zijlstra
2026-11-09 16:14 ` Vincent Guittot
2026-11-11 9:01 ` Peter Zijlstra
2026-11-12 7:01 ` Vincent Guittot
2026-11-12 7:36 ` Vincent Guittot
2026-11-12 9:49 ` Peter Zijlstra
2026-11-12 11:29 ` Vincent Guittot
2026-11-12 12:19 ` Peter Zijlstra
2026-11-06 15:19 ` [PATCH 09/20 v3] sched/fair: Optimize " Vincent Guittot
2026-11-06 16:00 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 10/20 v3] sched/core: Add rq flag to tick parameters Vincent Guittot
2026-11-06 15:19 ` [PATCH 11/20 v3] sched/fair: Add force push task mechanism for fair Vincent Guittot
2026-11-06 16:16 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 12/20 v3] sched/fair: Support not wakeup case in select_idle_sibling Vincent Guittot
2026-11-06 15:51 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 13/20] sched/eevdf: Try to push short slice task on a better CPU Vincent Guittot
2026-11-06 16:12 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 14/20 v3] sched/eevdf: Push short slice task that are not picked Vincent Guittot
2026-11-06 16:14 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 15/20 v3] sched/fair: Enable push task for preempt short Vincent Guittot
2026-11-06 16:27 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 16/20 v3] energy model: Add a get previous state function Vincent Guittot
2026-11-10 19:55 ` Rafael J. Wysocki (Intel)
2026-11-06 15:19 ` [PATCH 17/20 v3] sched/fair: Rework feec() to use cost instead of spare capacity Vincent Guittot
2026-11-06 16:30 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 18/20 v3] energy model: Remove unused em_cpu_energy() Vincent Guittot
2026-11-06 15:19 ` [PATCH 19/20 v3] sched/fair: Take into account slice in EAS Vincent Guittot
2026-11-06 16:26 ` sashiko-bot
2026-11-06 15:19 ` [PATCH 20/20 v3] sched/fair: Fix tasks stacking on same idle CPU Vincent Guittot
2026-11-06 16:53 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-201722@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=sched-ext@lists.linux.dev \
--cc=vincent.guittot@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.