From: Kayra Cizmeci <kayracizmeci@gmail.com>
To: K Prateek Nayak <kprateek.nayak@amd.com>
Cc: albin_yang@163.com, albinwyang@tencent.com, bsegall@google.com,
chen.yu@linux.dev, dietmar.eggemann@arm.com,
juri.lelli@redhat.com, linux-kernel@vger.kernel.org,
mgorman@suse.de, mingo@redhat.com, peterz@infradead.org,
rostedt@goodmis.org, vincent.guittot@linaro.org,
vschneid@redhat.com
Subject: Re: [PATCH] sched/stats: Fix run_delay over-count for proxy-migrated blocked donors
Date: Tue, 27 Oct 2026 09:52:33 +0300 [thread overview]
Message-ID: <auBEeDRRFKZOGlZA@scheduler.schedules> (raw)
In-Reply-To: <4ac4564e-08fb-4639-a89e-a2ad54cee3f7@amd.com>
On Tue, Oct 27, 2026 at 11:54:35AM +0530, K Prateek Nayak wrote:
> Hello Kayra,
>
> On 10/27/2026 11:41 AM, Kayra Cizmeci wrote:
> >> So all things considered, I think the following should work unless I'm
> >> terribly mistaken yet again :-) I've left my reasoning as comments:
> >>
> >> diff --git a/kernel/sched/stats.h b/kernel/sched/stats.h
> >> index ebe0a7765f98..c4c624deb25b 100644
> >> --- a/kernel/sched/stats.h
> >> +++ b/kernel/sched/stats.h
> >> @@ -239,6 +239,15 @@ static inline void psi_account_irqtime(struct rq *rq, struct task_struct *curr,
> >> static inline void sched_info_dequeue(struct rq *rq, struct task_struct *t)
> >> {
> >> unsigned long long delta = 0;
> >> + /*
> >> + * If a task is blocked (blocked donor, delayed dequeue task),
> >> + * do not account the queued time as runnable. A task that is
> >> + * blocking would have already cleared the "last_queued"
> >> + * indicator from sched_info_arrive() when it got a chance to
> >> + * run on the CPU.
> >> + */
> >> + if (t->is_blocked)
> >> + t->sched_info.last_queued = 0;
> >>
> >> if (!t->sched_info.last_queued)
> >> return;
> >> @@ -290,7 +299,23 @@ static void sched_info_arrive(struct rq *rq, struct task_struct *t)
> >> */
> >> static inline void sched_info_enqueue(struct rq *rq, struct task_struct *t)
> >> {
> >> - if (!t->sched_info.last_queued)
> >> + /*
> >> + * "t->is_blocked" is only cleared after the enqueue is done and
> >> + * the task is woken up. If the task is blocked, update the
> >> + * "last_queued" timestamp to that of last enqueue - if the task
> >> + * is still blocked while it leaves the runqueue, this timestamp
> >> + * is ignored and is cleared at sched_info_dequeue().
> >> + *
> >> + * To transition a task back to blocked after wakeup, it has to
> >> + * run on the CPU and naturally reach a safe preemption point.
> >> + * sched_info_arrive() will do the correct wait time accounting
> >> + * based on the last "last_queued".
> >> + *
> >> + * Any movement of task after being marked not blocked will be
> >> + * correctly captured as queued time at enqueue + dequeue
> >> + * boundaries when "t->is_blocked" cleared.
> >> + */
> >> + if (!t->sched_info.last_queued || t->is_blocked)
> >> t->sched_info.last_queued = rq_clock(rq);
> >> }
> >>
> >> ---
> >>
> >> That "t->is_blocked" check in sched_info_enqueue() may not be
> >> necessary either but I've left it in there for now since I did my
> >> quick testing with it.
> >
> >
> > Hi Prateek,
> >
> > IMO too doing this with is_blocked would be cleaner.
> >
> > But I think this not works on a case where a donor is in a different CPU
> > from its owner, like:
> >
> > A holds the mutex M in CPU0, B is the waiter and its on CPU1.
> >
> > proxy_migrate_task() gets B to CPU0.
> >> After that, A suddenly wants to goto CPU1. And it goes.
> > Now B goes back to its home CPU next to A.
> >
> > Now in here, timer starts.
> >
> > And suddenly A drops the mutex. Now B is not is_blocked.
> >
> > Because B is back to its home CPU, there is no dequeue.
> > Even if there was B is not is_blocked so timer wouldn't be reset.
> >
> > Normally we need to add the time that task waited for itself.
> > But in this case we add the time task waited for its mutex + for itself.
> >
> > Or am I missssssing something?
>
> Indeed. That is possible and can probably be fixed by doing a
> sched_info_enqueue() in proxy_needs_return() for
> task_cpu(p) == p->wake_cpu case like:
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 04b62c16fa8c..3d261a4e5b0b 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -3838,8 +3838,11 @@ static inline bool proxy_needs_return(struct rq *rq, struct task_struct *p)
> * will not apply. But if it did, this check is the safe way around
> * and would migrate.
> */
> - if (task_cpu(p) == p->wake_cpu)
> + if (task_cpu(p) == p->wake_cpu) {
> + /* Begin wait time accounting before marking !is_blocked. */
> + sched_info_enqueue(rq, p);
> return false;
> + }
>
> scoped_guard(raw_spinlock, &p->blocked_lock) {
> /* Task is waking up; clear any blocked_on relationship */
> ---
>
> Not sure if this solution is ugly or not for calling
> sched_info_enqueue() out of the enqueue path :-)
I think this fixes the issue. BTW I think this should skip curr, no?
On a case like this:
C holds M1 in CPU0, D waits that mutex in CPU1. A holds mutex M2 in
CPU2. B is the working task on CPU1 but it wants mutex M2 and we enter
__schedule(). B gets is_blocked. D gets chosen. We open the rq lock to
get D to CPU0. While this happens A drops the mutex and wakes up B.
we enter ttwu_runnable() and B is still curr. And we start the timer.
Or am I MISSSING something?
>
> --
> Thanks and Regards,
> Prateek
>
Thanks,
Kayra
next prev parent reply other threads:[~2026-10-27 6:52 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-25 13:07 [PATCH] sched/stats: Fix run_delay over-count for proxy-migrated blocked donors albin_yang
2026-10-25 19:28 ` Kayra Cizmeci
2026-10-26 13:53 ` albin_yang
2026-10-26 14:48 ` Kayra Cizmeci
2026-10-26 5:46 ` K Prateek Nayak
2026-10-26 13:38 ` albin_yang
2026-10-27 4:11 ` K Prateek Nayak
2026-10-27 6:11 ` Kayra Cizmeci
2026-10-27 6:24 ` K Prateek Nayak
2026-10-27 6:52 ` Kayra Cizmeci [this message]
2026-10-27 9:45 ` K Prateek Nayak
2026-10-27 9:53 ` Kayra Cizmeci
2026-10-27 9:58 ` K Prateek Nayak
2026-10-27 12:09 ` Peter Zijlstra
2026-10-27 12:13 ` Kayra Cizmeci
2026-10-28 3:40 ` K Prateek Nayak
2026-10-28 9:22 ` Peter Zijlstra
2026-11-01 14:31 ` albin_yang
2026-11-01 15:19 ` Kayra Cizmeci
2026-11-02 13:15 ` albin_yang
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=auBEeDRRFKZOGlZA@scheduler.schedules \
--to=kayracizmeci@gmail.com \
--cc=albin_yang@163.com \
--cc=albinwyang@tencent.com \
--cc=bsegall@google.com \
--cc=chen.yu@linux.dev \
--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 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.