From: Shubhang Kaushik <shubhang@os.amperecomputing.com>
To: Vincent Guittot <vincent.guittot@linaro.org>,
mingo@redhat.com, peterz@infradead.org, juri.lelli@redhat.com,
dietmar.eggemann@arm.com, rostedt@goodmis.org,
bsegall@google.com, mgorman@suse.de, vschneid@redhat.com,
kprateek.nayak@amd.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2] sched: fair: Prevent negative lag increase during delayed dequeue
Date: Thu, 2 Apr 2026 12:27:16 -0700 (PDT) [thread overview]
Message-ID: <2668574e-fefd-2d13-4fcf-39205ca9efb8@os.amperecomputing.com> (raw)
In-Reply-To: <20260331162352.551501-1-vincent.guittot@linaro.org>
Hi Vincent,
I have been testing your v2 patch on my 80 core Ampere Altra (ARMv8
Neoverse-N1) 1P system using an idle tickless kernel on the latest
tip/sched/core branch.
On Tue, 31 Mar 2026, Vincent Guittot wrote:
> Delayed dequeue feature aims to reduce the negative lag of a dequeued task
> while sleeping but it can happens that newly enqueued tasks will move
> backward the avg vruntime and increase its negative lag.
> When the delayed dequeued task wakes up, it has more neg lag compared to
> being dequeued immediately or to other tasks that have been dequeued just
> before theses new enqueues.
>
> Ensure that the negative lag of a delayed dequeued task doesn't increase
> during its delayed dequeued phase while waiting for its neg lag to
> diseappear. Similarly, we remove any positive lag that the delayed
> dequeued task could have gain during thsi period.
>
> Short slice tasks are particularly impacted in overloaded system.
>
> Test on snapdragon rb5:
>
> hackbench -T -p -l 16000000 -g 2 1> /dev/null &
> cyclictest -t 1 -i 2777 -D 333 --policy=fair --mlock -h 20000 -q
>
> The scheduling latency of cyclictest is:
>
> tip/sched/core tip/sched/core +this patch
> cyclictest slice (ms) (default)2.8 8 8
> hackbench slice (ms) (default)2.8 20 20
> Total Samples | 115632 119733 119806
> Average (us) | 364 64(-82%) 61(- 5%)
> Median (P50) (us) | 60 56(- 7%) 56( 0%)
> 90th Percentile (us) | 1166 62(-95%) 62( 0%)
> 99th Percentile (us) | 4192 73(-98%) 72(- 1%)
> 99.9th Percentile (us) | 8528 2707(-68%) 1300(-52%)
> Maximum (us) | 17735 14273(-20%) 13525(- 5%)
>
> Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org>
> ---
>
I replicated this cyclictest environment scaled for 80 cores using a
background hackbench load (-g 20). On Ampere Altra, I did not see the
tail latency reduction that you observed on the 8-core Snapdragon. In
fact, both average and max latencies increased slightly.
Metric | Baseline | Patched | Delta (%)
-------------|----------|----------|-----------
Max Latency | 9141us | 9426us | +3.11%
Avg Latency | 206us | 217us | +5.33%
Min Latency | 14us | 13us | -7.14%
More concerning is the impact on throughput. At 8-16 threads, hackbench
execution times increased by ~30%. I attempted to isolate this by
disabling the DELAY_DEQUEUE sched_feature. But the regression persists
even with NO_DELAY_DEQUEUE, pointing to overhead in the modified
update_entity_lag() path itself.
Test Case | Baseline | Patched | Delta (%) | Patched(NO_DELAYDQ)
-------------|----------|----------|-----------|--------------------
4 Threads | 13.77s | 17.53s | +27.3% | 17.16s
8 Threads | 24.39s | 31.90s | +30.8% | 30.67s
16 Threads | 47.92s | 60.46s | +26.2% | 62.53s
32 Processes | 118.08s | 103.16s | -12.6% | 101.87s
> Since v1:
> - Embedded the check of lag evolution of delayed dequeue entities in
> update_entity_lag() to include all cases.
>
While the patch shows a ~12.6% improvement at high saturation (32
processes), the throughput cost at mid-range scales appears to outweigh
the fairness benefits on our high core system, as even the worst-case
wake-up latencies did not improve.
> kernel/sched/fair.c | 53 ++++++++++++++++++++++++++-------------------
> 1 file changed, 31 insertions(+), 22 deletions(-)
>
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 226509231e67..c1ffe86bf78d 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -840,11 +840,30 @@ static s64 entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se, u64 avrunt
> return clamp(vlag, -limit, limit);
> }
>
> -static void update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
> +/*
> + * Delayed dequeue aims to reduce the negative lag of a dequeued task.
> + * While updating the lag of an entity, check that negative lag didn't increase
> + * during the delayed dequeue period which would be unfair.
> + * Similarly, check that the entity didn't gain positive lag when DELAY_ZERO is
> + * set.
> + *
> + * Return true if the lag has been adjusted.
> + */
> +static bool update_entity_lag(struct cfs_rq *cfs_rq, struct sched_entity *se)
> {
> + s64 vlag;
> +
> WARN_ON_ONCE(!se->on_rq);
>
> - se->vlag = entity_lag(cfs_rq, se, avg_vruntime(cfs_rq));
> + vlag = entity_lag(cfs_rq, se, avg_vruntime(cfs_rq));
> +
> + if (se->sched_delayed)
> + /* previous vlag < 0 otherwise se would not be delayed */
> + se->vlag = clamp(vlag, se->vlag, sched_feat(DELAY_ZERO) ? 0 : S64_MAX);
> + else
> + se->vlag = vlag;
> +
> + return (vlag != se->vlag);
> }
>
> /*
> @@ -5563,13 +5582,6 @@ static void clear_delayed(struct sched_entity *se)
> }
> }
>
> -static inline void finish_delayed_dequeue_entity(struct sched_entity *se)
> -{
> - clear_delayed(se);
> - if (sched_feat(DELAY_ZERO) && se->vlag > 0)
> - se->vlag = 0;
> -}
> -
> static bool
> dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
> {
> @@ -5595,6 +5607,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
> if (sched_feat(DELAY_DEQUEUE) && delay &&
> !entity_eligible(cfs_rq, se)) {
> update_load_avg(cfs_rq, se, 0);
> + update_entity_lag(cfs_rq, se);
The regression persists even with NO_DELAY_DEQUEUE, likely because
update_entity_lag() is now called unconditionally in dequeue_entity()
thereby adding avg_vruntime() overhead and cacheline contention for every
dequeue.
Do consider guarding the update_entity_lag() call in dequeue_entity()
with sched_feat(DELAY_DEQUEUE) check to avoid this tax when the feature
is disabled.
> set_delayed(se);
> return false;
> }
> @@ -5634,7 +5647,7 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
> update_cfs_group(se);
>
> if (flags & DEQUEUE_DELAYED)
> - finish_delayed_dequeue_entity(se);
> + clear_delayed(se);
>
> if (cfs_rq->nr_queued == 0) {
> update_idle_cfs_rq_clock_pelt(cfs_rq);
> @@ -7088,18 +7101,14 @@ requeue_delayed_entity(struct sched_entity *se)
> WARN_ON_ONCE(!se->sched_delayed);
> WARN_ON_ONCE(!se->on_rq);
>
> - if (sched_feat(DELAY_ZERO)) {
> - update_entity_lag(cfs_rq, se);
> - if (se->vlag > 0) {
> - cfs_rq->nr_queued--;
> - if (se != cfs_rq->curr)
> - __dequeue_entity(cfs_rq, se);
> - se->vlag = 0;
> - place_entity(cfs_rq, se, 0);
> - if (se != cfs_rq->curr)
> - __enqueue_entity(cfs_rq, se);
> - cfs_rq->nr_queued++;
> - }
> + if (update_entity_lag(cfs_rq, se)) {
> + cfs_rq->nr_queued--;
> + if (se != cfs_rq->curr)
> + __dequeue_entity(cfs_rq, se);
> + place_entity(cfs_rq, se, 0);
> + if (se != cfs_rq->curr)
> + __enqueue_entity(cfs_rq, se);
> + cfs_rq->nr_queued++;
Triggering a full dequeue/enqueue cycle for every vlag adjustment appears
to be a major bottleneck. Frequent RB-tree rebalancing here creates
significant contention.
Could we preserve fairness while recovering throughput by only re-queuing
when the lag sign changes or a significant eligibility threshold is
crossed?
> }
>
> update_load_avg(cfs_rq, se, 0);
> --
> 2.43.0
>
>
Regards,
Shubhang Kaushik
next prev parent reply other threads:[~2026-04-02 19:27 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-31 16:23 Vincent Guittot
2026-04-02 13:13 ` Peter Zijlstra
2026-04-02 13:17 ` Vincent Guittot
2026-04-17 17:18 ` Vincent Guittot
2026-04-22 13:39 ` Peter Zijlstra
2026-04-22 14:06 ` Vincent Guittot
2026-04-22 14:24 ` Peter Zijlstra
2026-04-22 14:28 ` Peter Zijlstra
2026-04-22 14:46 ` Vincent Guittot
2026-04-22 22:20 ` Peter Zijlstra
2026-04-23 7:28 ` Vincent Guittot
2026-04-23 9:41 ` Peter Zijlstra
2026-04-23 10:27 ` Vincent Guittot
2026-04-23 12:12 ` Vincent Guittot
2026-04-02 13:42 ` Peter Zijlstra
2026-04-02 19:27 ` Shubhang Kaushik [this message]
2026-04-03 8:37 ` Vincent Guittot
2026-04-04 8:08 ` Shubhang Kaushik
2026-04-03 8:46 ` Vincent Guittot
2026-04-03 12:30 ` [tip: sched/core] sched/fair: " tip-bot2 for Vincent Guittot
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=2668574e-fefd-2d13-4fcf-39205ca9efb8@os.amperecomputing.com \
--to=shubhang@os.amperecomputing.com \
--cc=bsegall@google.com \
--cc=dietmar.eggemann@arm.com \
--cc=juri.lelli@redhat.com \
--cc=kprateek.nayak@amd.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mgorman@suse.de \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=vincent.guittot@linaro.org \
--cc=vschneid@redhat.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome