[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20201029182429.GA1844482@google.com>
Date: Thu, 29 Oct 2020 14:24:29 -0400
From: Joel Fernandes <joel@...lfernandes.org>
To: Peter Zijlstra <peterz@...radead.org>
Cc: Nishanth Aravamudan <naravamudan@...italocean.com>,
Julien Desfossez <jdesfossez@...italocean.com>,
Tim Chen <tim.c.chen@...ux.intel.com>,
Vineeth Pillai <viremana@...ux.microsoft.com>,
Aaron Lu <aaron.lwe@...il.com>,
Aubrey Li <aubrey.intel@...il.com>, tglx@...utronix.de,
linux-kernel@...r.kernel.org, mingo@...nel.org,
keescook@...omium.org, kerrnel@...gle.com,
Phil Auld <pauld@...hat.com>,
Valentin Schneider <valentin.schneider@....com>,
Mel Gorman <mgorman@...hsingularity.net>,
Pawan Gupta <pawan.kumar.gupta@...ux.intel.com>,
Paolo Bonzini <pbonzini@...hat.com>, vineeth@...byteword.org,
Chen Yu <yu.c.chen@...el.com>,
Christian Brauner <christian.brauner@...ntu.com>,
Agata Gruza <agata.gruza@...el.com>,
Antonio Gomez Iglesias <antonio.gomez.iglesias@...el.com>,
graf@...zon.com, konrad.wilk@...cle.com, dfaggioli@...e.com,
pjt@...gle.com, rostedt@...dmis.org, derkling@...gle.com,
benbjiang@...cent.com,
Alexandre Chartre <alexandre.chartre@...cle.com>,
James.Bottomley@...senpartnership.com, OWeisse@...ch.edu,
Dhaval Giani <dhaval.giani@...cle.com>,
Junaid Shahid <junaids@...gle.com>, jsbarnes@...gle.com,
chris.hyser@...cle.com, Aubrey Li <aubrey.li@...ux.intel.com>,
Tim Chen <tim.c.chen@...el.com>
Subject: Re: [PATCH v8 -tip 08/26] sched/fair: Snapshot the min_vruntime of
CPUs on force idle
On Mon, Oct 26, 2020 at 01:47:24PM +0100, Peter Zijlstra wrote:
[..]
> How's something like this?
>
> - after each pick, such that the pick itself sees the divergence (see
> above); either:
>
> - pull the vruntime_fi forward, when !fi
> - freeze the vruntime_fi, when newly fi (A)
>
> - either way, update vruntime_fi for each cfs_rq in the active
> hierachy.
>
> - when comparing, and fi, update the vruntime_fi hierachy until we
> encounter a mark from (A), per doing it during the pick, but before
> runtime, this guaranteees it hasn't moved since (A).
>
> XXX, still buggered on SMT>2, imagine having {ta, tb, fi, i} on an SMT4,
> then when comparing any two tasks that do not involve the fi, we should
> (probably) have pulled them fwd -- but we can't actually pull them,
> because then the fi thing would break, mooo.
>
v>
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -115,19 +115,8 @@ static inline bool prio_less(struct task
> if (pa == -1) /* dl_prio() doesn't work because of stop_class above */
> return !dl_time_before(a->dl.deadline, b->dl.deadline);
>
> - if (pa == MAX_RT_PRIO + MAX_NICE) { /* fair */
> - u64 vruntime = b->se.vruntime;
> -
> - /*
> - * Normalize the vruntime if tasks are in different cpus.
> - */
> - if (task_cpu(a) != task_cpu(b)) {
> - vruntime -= task_cfs_rq(b)->min_vruntime;
> - vruntime += task_cfs_rq(a)->min_vruntime;
> - }
> -
> - return !((s64)(a->se.vruntime - vruntime) <= 0);
> - }
> + if (pa == MAX_RT_PRIO + MAX_NICE) /* fair */
> + return cfs_prio_less(a, b);
>
> return false;
> }
> @@ -4642,12 +4631,15 @@ pick_task(struct rq *rq, const struct sc
> return cookie_pick;
> }
>
> +extern void task_vruntime_update(struct rq *rq, struct task_struct *p);
> +
> static struct task_struct *
> pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
> {
> struct task_struct *next, *max = NULL;
> const struct sched_class *class;
> const struct cpumask *smt_mask;
> + bool fi_before = false;
> bool need_sync;
> int i, j, cpu;
>
> @@ -4707,6 +4699,7 @@ pick_next_task(struct rq *rq, struct tas
> need_sync = !!rq->core->core_cookie;
> if (rq->core->core_forceidle) {
> need_sync = true;
> + fi_before = true;
> rq->core->core_forceidle = false;
> }
>
> @@ -4757,6 +4750,11 @@ pick_next_task(struct rq *rq, struct tas
> continue;
>
> rq_i->core_pick = p;
> + if (rq_i->idle == p && rq_i->nr_running) {
> + rq->core->core_forceidle = true;
> + if (!fi_before)
> + rq->core->core_forceidle_seq++;
> + }
>
> /*
> * If this new candidate is of higher priority than the
> @@ -4775,6 +4773,7 @@ pick_next_task(struct rq *rq, struct tas
> max = p;
>
> if (old_max) {
> + rq->core->core_forceidle = false;
> for_each_cpu(j, smt_mask) {
> if (j == i)
> continue;
> @@ -4823,10 +4822,8 @@ pick_next_task(struct rq *rq, struct tas
> if (!rq_i->core_pick)
> continue;
>
> - if (is_task_rq_idle(rq_i->core_pick) && rq_i->nr_running &&
> - !rq_i->core->core_forceidle) {
> - rq_i->core->core_forceidle = true;
> - }
> + if (!(fi_before && rq->core->core_forceidle))
> + task_vruntime_update(rq_i, rq_i->core_pick);
Shouldn't this be:
if (!fi_before && rq->core->core_forceidle)
task_vruntime_update(rq_i, rq_i->core_pick);
?
>
> if (i == cpu) {
> rq_i->core_pick = NULL;
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -10686,6 +10686,67 @@ static inline void task_tick_core(struct
> __entity_slice_used(&curr->se, MIN_NR_TASKS_DURING_FORCEIDLE))
> resched_curr(rq);
> }
> +
> +static void se_fi_update(struct sched_entity *se, unsigned int fi_seq, bool forceidle)
> +{
> + for_each_sched_entity(se) {
> + struct cfs_rq *cfs_rq = cfs_rq_of(se);
> +
> + if (forceidle) {
> + if (cfs_rq->forceidle_seq == fi_seq)
> + break;
> + cfs_rq->forceidle_seq = fi_seq;
> + }
> +
> + cfs_rq->min_vruntime_fi = cfs_rq->min_vruntime;
> + }
> +}
> +
> +void task_vruntime_update(struct rq *rq, struct task_struct *p)
> +{
> + struct sched_entity *se = &p->se;
> +
> + if (p->sched_class != &fair_sched_class)
> + return;
> +
> + se_fi_update(se, rq->core->core_forceidle_seq, rq->core->core_forceidle);
> +}
> +
> +bool cfs_prio_less(struct task_struct *a, struct task_struct *b)
> +{
> + struct rq *rq = task_rq(a);
> + struct sched_entity *sea = &a->se;
> + struct sched_entity *seb = &b->se;
> + struct cfs_rq *cfs_rqa;
> + struct cfs_rq *cfs_rqb;
> + s64 delta;
> +
> + SCHED_WARN_ON(task_rq(b)->core != rq->core);
> +
> + while (sea->cfs_rq->tg != seb->cfs_rq->tg) {
> + int sea_depth = sea->depth;
> + int seb_depth = seb->depth;
> +
> + if (sea_depth >= seb_depth)
> + sea = parent_entity(sea);
> + if (sea_depth <= seb_depth)
> + seb = parent_entity(seb);
> + }
> +
> + if (rq->core->core_forceidle) {
> + se_fi_update(sea, rq->core->core_forceidle_seq, true);
> + se_fi_update(seb, rq->core->core_forceidle_seq, true);
> + }
As we chatted on IRC you mentioned the reason for the sync here is:
say we have 2 cgroups (a,b) under root, and we go force-idle in a, then we
update a and root. Then we pick and end up in b, but b hasn't been updated
yet.
One thing I was wondering about that was, if the pick of 'b' happens much
later than 'a', then the snapshot might be happening too late right?
Maybe the snapshot should happen on all cfs_rqs on all siblings in
pick_next_task() itself? That way everything gets updated at the instant the
force-idle started. Thought that may be a bit more slow.
thanks,
- Joel
Powered by blists - more mailing lists