Re: [RFC PATCH] sched/fair: Address avruntime drift caused by entity_lag()

From: Vincent Guittot

Date: Mon Jul 06 2026 - 14:11:25 EST


On Fri, 3 Jul 2026 at 11:50, Chen Jinghuang <chenjinghuang2@xxxxxxxxxx> wrote:
>
> While running EEVDF-related test cases, we observed an anomalous
> phenomenon where the vruntime of a continuously running scheduling
> entity (se) exhibits an overall downward trend.
>
> The test topology and observed behavior are as follows:
>
> CPU 0 CPU 1 / Other CPUs
> +----------------------------+ +----------------------------+
> | cgroup A cgroup B | | cgroup A cgroup B |
> | |- A1 (Run) |- B1 | | |- A2, A3... |- B2, B3...|
> | (50us S)| | (Frequent sleep/wake) |
> | (10us W)| | |
> +----------------------------+ +----------------------------+
> |
> v
> A2/A3 frequent sleep/wake -> Frequent reweight of gse(A) on CPU 0
> -> Triggers vlag clamping -> Unidirectional avruntime drift
> -> gse->vruntime drops abnormally (while gse weight remains stable)
>
> According to function_graph traces, frequent sleep/wake cycles of
> sibling tasks within the same cgroup cause the running task to repeatedly
> trigger update_cfs_cgroup() -> reweight_entity().
>
> The root cause appears to point to the entity_lag() boundary limit
> introduced in `reweight_entity()` to prevent overflows. During repeated
> weight scaling, this limit introduces an asymmetric cumulative error.
> Connsider an example here where se->vruntime > avruntime:
>
> 1. Downscale:
> se->vlag = entity_lag(cfs_rq, se, avruntime);

The clamp applied in entity_lag() should "in theory never" happen.

Do you have more details to share about your setup?

Which kernel version do you use ? A number of changes have been queued
recently that should ensure that the vlag never goes above the
theoretical limit.

How many CPUs are in the system ?
Is there other tasks running in the cgroups ?

Could you try to run without RUN_TO_PARITY ?
echo NO_RUN_TO_PARITY > /sys/kernel/debug/sched/features

Do you set the share of task groups to particular values?
Do you change the slice of the tasks ?

Note that even without clamping, part of the vlag is lost in div64_long

> se->vlag = div64_long(se->vlag * old_weight, weight);
> se->vruntime = avruntime - se->vlag;
>
> If the calculated vlag exceeds the limit boundary, it is clamped.
> This causes the scaled vlag to be bigger than its theoretical value,
> making the resulting se->vruntime smaller than it should be (forced
> closer to avruntime).
>
> 2. Upscale:
> Because se->vruntime already carries the clamping error from the
> previous step, it implicitly shifts the subsequent global avruntime
> computation trajectory. When the weight is restored, se->vruntime
> deviates from its original true value, preventing the true vlag from
> being reconstructed and leading to a unidirectional avruntime drift.
>
> Under frequent cgroup reweighting, this asymmetric truncation error
> accumulates, causing a unidirectional downward drift of vruntime.
>
> Regarding this vlag limit mechanism in reweight_entity(), we would like
> to raise a few questions for discussion:
>
> Question 1: Is this deviation of se->vruntime expected?
> For a currently running entity (curr se), due to RUN_TO_PARITY, it
> typically operates in a state where se->vruntime > avruntime. During
> reweighting, the limit forces its vruntime downward (closer to avruntime),
> while attributes like deadline remain unaffected by the limit.
>
> Question 2: Is the unidirectional drift of avruntime reasonable?
> Since avruntime = avg_vruntime(), the deviation of se->vruntime
> before and after reweighting (while its weight remains unchanged) shifts
> the global avruntime downward. According to EEVDF core principles,
> avruntime should remain invariant across weight changes.
> (https://lore.kernel.org/lkml/20260415211149.2658910-1-jstultz@xxxxxxxxxx/),
>
> Question 3: Is the reduction of avruntime fair to other entities?
> A non-functional reduction in global avruntime passively decreases the
> se->vlag of other queued entities on the runqueue, which practically
> worsens the starvation of those tasks.
>
> Question 4: Does this lead to complete preemption suppression?
> In entity_tick -> update_deadline, because curr->vruntime is abnormally
> pulled down by the clamping error while its deadline is unchanged, the
> condition vruntime < deadline can be continuously satisfied at every
> tick. This skips resched_curr(), suppressing preemption until the
> frequent reweighting stops or curr's vlag falls back within the limit.
>
> While entity_lag() was originally introduced to prevent overflow-induced
> NULL pointer dereferences, given its significant impact on EEVDF fairness,
> should the necessity and implementation of this limit be reconsidered?
>
> Analyzed-by: Hui Tang <tanghui20@xxxxxxxxxx>
> Analyzed-by: Zhang Qiao <zhangqiao22@xxxxxxxxxx>
> Analyzed-by: Zicheng Qu <quzicheng@xxxxxxxxxx>
> Analyzed-by: Chen Jinghuang <chenjinghuang2@xxxxxxxxxx>