All of lore.kernel.org
 help / color / mirror / Atom feed
From: Morten Rasmussen <morten.rasmussen@arm.com>
To: Vincent Guittot <vincent.guittot@linaro.org>
Cc: "Peter Zijlstra" <peterz@infradead.org>,
	"mingo@redhat.com" <mingo@redhat.com>,
	"Dietmar Eggemann" <dietmar.eggemann@arm.com>,
	"Yuyang Du" <yuyang.du@intel.com>,
	mgalbraith@suse.de,
	"Sai Charan Gurrappadi" <sgurrappadi@nvidia.com>,
	"Koan-Sin Tan" <freedom.tan@mediatek.com>,
	小林敬太 <keita.kobayashi.ym@renesas.com>,
	linux-kernel <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v3 11/13] sched/fair: Consider spare capacity in find_idlest_group()
Date: Thu, 18 Aug 2016 12:16:33 +0100	[thread overview]
Message-ID: <20160818111632.GB27873@e105550-lin.cambridge.arm.com> (raw)
In-Reply-To: <CAKfTPtAR4F4iAF-Jhwsz_8SiD+CPX2wHVODEdbo+OjLvS+F33g@mail.gmail.com>

On Tue, Aug 16, 2016 at 03:57:06PM +0200, Vincent Guittot wrote:
> On 25 July 2016 at 15:34, Morten Rasmussen <morten.rasmussen@arm.com> wrote:
> > In low-utilization scenarios comparing relative loads in
> > find_idlest_group() doesn't always lead to the most optimum choice.
> > Systems with groups containing different numbers of cpus and/or cpus of
> > different compute capacity are significantly better off when considering
> > spare capacity rather than relative load in those scenarios.
> >
> > In addition to existing load based search an alternative spare capacity
> > based candidate sched_group is found and selected instead if sufficient
> > spare capacity exists. If not, existing behaviour is preserved.
> >
> > cc: Ingo Molnar <mingo@redhat.com>
> > cc: Peter Zijlstra <peterz@infradead.org>
> >
> > Signed-off-by: Morten Rasmussen <morten.rasmussen@arm.com>
> > ---
> >  kernel/sched/fair.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
> >  1 file changed, 41 insertions(+), 5 deletions(-)
> >
> > diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> > index 9c6ec3bf75ce..e3654409d099 100644
> > --- a/kernel/sched/fair.c
> > +++ b/kernel/sched/fair.c
> > @@ -5164,6 +5164,14 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p,
> >         return 1;
> >  }
> >
> > +static inline int task_util(struct task_struct *p);
> > +static int cpu_util_wake(int cpu, struct task_struct *p);
> > +
> > +static unsigned long capacity_spare_wake(int cpu, struct task_struct *p)
> > +{
> > +       return capacity_orig_of(cpu) - cpu_util_wake(cpu, p);
> > +}
> > +
> >  /*
> >   * find_idlest_group finds and returns the least busy CPU group within the
> >   * domain.
> > @@ -5173,7 +5181,9 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p,
> >                   int this_cpu, int sd_flag)
> >  {
> >         struct sched_group *idlest = NULL, *group = sd->groups;
> > +       struct sched_group *most_spare_sg = NULL;
> >         unsigned long min_load = ULONG_MAX, this_load = 0;
> > +       unsigned long most_spare = 0, this_spare = 0;
> >         int load_idx = sd->forkexec_idx;
> >         int imbalance = 100 + (sd->imbalance_pct-100)/2;
> >
> > @@ -5181,7 +5191,7 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p,
> >                 load_idx = sd->wake_idx;
> >
> >         do {
> > -               unsigned long load, avg_load;
> > +               unsigned long load, avg_load, spare_cap, max_spare_cap;
> >                 int local_group;
> >                 int i;
> >
> > @@ -5193,8 +5203,12 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p,
> >                 local_group = cpumask_test_cpu(this_cpu,
> >                                                sched_group_cpus(group));
> >
> > -               /* Tally up the load of all CPUs in the group */
> > +               /*
> > +                * Tally up the load of all CPUs in the group and find
> > +                * the group containing the cpu with most spare capacity.
> > +                */
> >                 avg_load = 0;
> > +               max_spare_cap = 0;
> >
> >                 for_each_cpu(i, sched_group_cpus(group)) {
> >                         /* Bias balancing toward cpus of our domain */
> > @@ -5204,6 +5218,13 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p,
> >                                 load = target_load(i, load_idx);
> >
> >                         avg_load += load;
> > +
> > +                       spare_cap = capacity_spare_wake(i, p);
> > +
> > +                       if (spare_cap > max_spare_cap &&
> > +                           spare_cap > capacity_of(i) >> 3) {
> 
> This condition probably needs some descriptions. You're not only
> looking for max spare capacity but also a significant spare capacity
> (more than 12.5% of cpu_capacity_orig). Can't this additional test
> lead to some strange situation where a CPU with more spare capacity
> will not be selected because of this 12.5% condition whereas another
> with less spare capacity will be selected because its capacity_orig is
> lower ?

Right, the reason why I added the 12.5% check is that I thought we
wouldn't want to pack cpus too aggressively. You are right that we could
reject a 1024 capacity with a spare capacity of 100 and pick a 512
capacity cpu with a spare capacity of 65.

Using an absolute margin instead, e.g. 128 instead of 12.5%, would fix
this particular issue but create another one as we would reject low
capacity cpus at very low utilization. For example, if we have cpus with
a capacity of 256. I thought that the relative threshold was more
generic and would cause less trouble, but I'm happy to discuss
alternatives.

>From a latency perspective it might not be a bad idea staying away from
cpus with a utilization even if they have more capacity available as the
task is more likely to end up waiting on the rq. For throughput tasks
you would of course want it the other way around.

> 
> > +                               max_spare_cap = spare_cap;
> > +                       }
> >                 }
> >
> >                 /* Adjust by relative CPU capacity of the group */
> > @@ -5211,12 +5232,27 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p,
> >
> >                 if (local_group) {
> >                         this_load = avg_load;
> > -               } else if (avg_load < min_load) {
> > -                       min_load = avg_load;
> > -                       idlest = group;
> > +                       this_spare = max_spare_cap;
> > +               } else {
> > +                       if (avg_load < min_load) {
> > +                               min_load = avg_load;
> > +                               idlest = group;
> > +                       }
> > +
> > +                       if (most_spare < max_spare_cap) {
> > +                               most_spare = max_spare_cap;
> > +                               most_spare_sg = group;
> > +                       }
> >                 }
> >         } while (group = group->next, group != sd->groups);
> >
> > +       /* Found a significant amount of spare capacity. */
> 
> It may worth explaining the threshold when it becomes better to choose
> the most spare group instead of the least loaded group.

Yes. I admit that the threshold is somewhat randomly chosen. Based on a
few experiments I found that requiring enough spare capacity to fit the
task completely was too conservative. We would bail out and go with the
least loaded groups very often, especially for new tasks, despite the
spare capacity only being slightly too small. Allowing a small degree of
stuffing of the task seemed better. Choosing the least loaded group
instead doesn't give any better throughput for the waking task unless it
has high priority. For overall throughput, the most spare capacity cpus
should be the better choice.

Should I just add a comment saying that we want to allow a little bit of
task stuffing to accommodate better for new tasks and have better overall
throughput, or should we investigate the threshold further?


> 
> > +       if (this_spare > task_util(p) / 2 &&
> > +           imbalance*this_spare > 100*most_spare)
> > +               return NULL;
> > +       else if (most_spare > task_util(p) / 2)
> > +               return most_spare_sg;
> > +
> >         if (!idlest || 100*this_load < imbalance*min_load)
> >                 return NULL;
> >         return idlest;
> > --
> > 1.9.1
> >

  reply	other threads:[~2016-08-18 11:18 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-25 13:34 [PATCH v3 00/13] sched: Clean-ups and asymmetric cpu capacity support Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 01/13] sched: Fix power to capacity renaming in comment Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 02/13] sched/fair: Consistent use of prev_cpu in wakeup path Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 03/13] sched/fair: Optimize find_idlest_cpu() when there is no choice Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 04/13] sched/core: Remove unnecessary null-pointer check Morten Rasmussen
2016-08-18 10:56   ` [tip:sched/core] sched/core: Remove unnecessary NULL-pointer check tip-bot for Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 05/13] sched: Introduce SD_ASYM_CPUCAPACITY sched_domain topology flag Morten Rasmussen
2016-08-15 10:54   ` Peter Zijlstra
2016-08-15 11:43     ` Morten Rasmussen
2016-08-18 10:56     ` [tip:sched/core] sched/core: Clarify SD_flags comment tip-bot for Peter Zijlstra
2016-08-17  8:42   ` [PATCH v3 05/13] sched: Introduce SD_ASYM_CPUCAPACITY sched_domain topology flag Wanpeng Li
2016-08-17  9:23     ` Morten Rasmussen
2016-08-17  9:26       ` Wanpeng Li
2016-08-18 10:56   ` [tip:sched/core] sched/core: " tip-bot for Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 06/13] sched/core: Pass child domain into sd_init Morten Rasmussen
2016-08-18 10:57   ` [tip:sched/core] sched/core: Pass child domain into sd_init() tip-bot for Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 07/13] sched: Enable SD_BALANCE_WAKE for asymmetric capacity systems Morten Rasmussen
2016-08-18 10:57   ` [tip:sched/core] sched/core: " tip-bot for Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 08/13] sched: Store maximum per-cpu capacity in root domain Morten Rasmussen
2016-08-01 18:53   ` Dietmar Eggemann
2016-08-16 12:24     ` Vincent Guittot
2016-08-18 10:58     ` [tip:sched/core] sched/core: Store maximum per-CPU " tip-bot for Dietmar Eggemann
2016-07-25 13:34 ` [PATCH v3 09/13] sched/fair: Let asymmetric cpu configurations balance at wake-up Morten Rasmussen
2016-08-15 13:39   ` Peter Zijlstra
2016-08-15 15:01     ` Morten Rasmussen
2016-08-15 15:10       ` Peter Zijlstra
2016-08-15 15:30         ` Morten Rasmussen
2016-08-18 10:58   ` [tip:sched/core] sched/fair: Let asymmetric CPU " tip-bot for Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 10/13] sched/fair: Compute task/cpu utilization at wake-up more correctly Morten Rasmussen
2016-08-15 14:23   ` Peter Zijlstra
2016-08-15 15:42     ` Morten Rasmussen
2016-08-18  8:40       ` Morten Rasmussen
2016-08-18 10:24         ` Morten Rasmussen
2016-08-18 11:46           ` Wanpeng Li
2016-08-18 13:45             ` Morten Rasmussen
2016-08-19  1:43               ` Wanpeng Li
2016-08-19 14:03                 ` Morten Rasmussen
2016-08-22  1:48                   ` Wanpeng Li
2016-08-22 11:29                     ` Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 11/13] sched/fair: Consider spare capacity in find_idlest_group() Morten Rasmussen
2016-08-16 13:57   ` Vincent Guittot
2016-08-18 11:16     ` Morten Rasmussen [this message]
2016-08-18 12:28       ` Peter Zijlstra
2016-07-25 13:34 ` [PATCH v3 12/13] sched: Add per-cpu min capacity to sched_group_capacity Morten Rasmussen
2016-07-25 13:34 ` [PATCH v3 13/13] sched/fair: Avoid pulling tasks from non-overloaded higher capacity groups Morten Rasmussen

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=20160818111632.GB27873@e105550-lin.cambridge.arm.com \
    --to=morten.rasmussen@arm.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=freedom.tan@mediatek.com \
    --cc=keita.kobayashi.ym@renesas.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mgalbraith@suse.de \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=sgurrappadi@nvidia.com \
    --cc=vincent.guittot@linaro.org \
    --cc=yuyang.du@intel.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.