Commit bf475ce0 authored by Morten Rasmussen's avatar Morten Rasmussen Committed by Ingo Molnar

sched/fair: Add per-CPU min capacity to sched_group_capacity

struct sched_group_capacity currently represents the compute capacity
sum of all CPUs in the sched_group.

Unless it is divided by the group_weight to get the average capacity
per CPU, it hides differences in CPU capacity for mixed capacity systems
(e.g. high RT/IRQ utilization or ARM big.LITTLE).

But even the average may not be sufficient if the group covers CPUs of
different capacities.

Instead, by extending struct sched_group_capacity to indicate min per-CPU
capacity in the group a suitable group for a given task utilization can
more easily be found such that CPUs with reduced capacity can be avoided
for tasks with high utilization (not implemented by this patch).
Signed-off-by: default avatarMorten Rasmussen <morten.rasmussen@arm.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: dietmar.eggemann@arm.com
Cc: freedom.tan@mediatek.com
Cc: keita.kobayashi.ym@renesas.com
Cc: mgalbraith@suse.de
Cc: sgurrappadi@nvidia.com
Cc: vincent.guittot@linaro.org
Cc: yuyang.du@intel.com
Link: http://lkml.kernel.org/r/1476452472-24740-4-git-send-email-morten.rasmussen@arm.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 6a0b19c0
...@@ -5708,7 +5708,7 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, ...@@ -5708,7 +5708,7 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
printk(KERN_CONT " %*pbl", printk(KERN_CONT " %*pbl",
cpumask_pr_args(sched_group_cpus(group))); cpumask_pr_args(sched_group_cpus(group)));
if (group->sgc->capacity != SCHED_CAPACITY_SCALE) { if (group->sgc->capacity != SCHED_CAPACITY_SCALE) {
printk(KERN_CONT " (cpu_capacity = %d)", printk(KERN_CONT " (cpu_capacity = %lu)",
group->sgc->capacity); group->sgc->capacity);
} }
...@@ -6185,6 +6185,7 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) ...@@ -6185,6 +6185,7 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu)
* die on a /0 trap. * die on a /0 trap.
*/ */
sg->sgc->capacity = SCHED_CAPACITY_SCALE * cpumask_weight(sg_span); sg->sgc->capacity = SCHED_CAPACITY_SCALE * cpumask_weight(sg_span);
sg->sgc->min_capacity = SCHED_CAPACITY_SCALE;
/* /*
* Make sure the first group of this domain contains the * Make sure the first group of this domain contains the
......
...@@ -6909,13 +6909,14 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) ...@@ -6909,13 +6909,14 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu)
cpu_rq(cpu)->cpu_capacity = capacity; cpu_rq(cpu)->cpu_capacity = capacity;
sdg->sgc->capacity = capacity; sdg->sgc->capacity = capacity;
sdg->sgc->min_capacity = capacity;
} }
void update_group_capacity(struct sched_domain *sd, int cpu) void update_group_capacity(struct sched_domain *sd, int cpu)
{ {
struct sched_domain *child = sd->child; struct sched_domain *child = sd->child;
struct sched_group *group, *sdg = sd->groups; struct sched_group *group, *sdg = sd->groups;
unsigned long capacity; unsigned long capacity, min_capacity;
unsigned long interval; unsigned long interval;
interval = msecs_to_jiffies(sd->balance_interval); interval = msecs_to_jiffies(sd->balance_interval);
...@@ -6928,6 +6929,7 @@ void update_group_capacity(struct sched_domain *sd, int cpu) ...@@ -6928,6 +6929,7 @@ void update_group_capacity(struct sched_domain *sd, int cpu)
} }
capacity = 0; capacity = 0;
min_capacity = ULONG_MAX;
if (child->flags & SD_OVERLAP) { if (child->flags & SD_OVERLAP) {
/* /*
...@@ -6952,12 +6954,13 @@ void update_group_capacity(struct sched_domain *sd, int cpu) ...@@ -6952,12 +6954,13 @@ void update_group_capacity(struct sched_domain *sd, int cpu)
*/ */
if (unlikely(!rq->sd)) { if (unlikely(!rq->sd)) {
capacity += capacity_of(cpu); capacity += capacity_of(cpu);
continue; } else {
}
sgc = rq->sd->groups->sgc; sgc = rq->sd->groups->sgc;
capacity += sgc->capacity; capacity += sgc->capacity;
} }
min_capacity = min(capacity, min_capacity);
}
} else { } else {
/* /*
* !SD_OVERLAP domains can assume that child groups * !SD_OVERLAP domains can assume that child groups
...@@ -6966,12 +6969,16 @@ void update_group_capacity(struct sched_domain *sd, int cpu) ...@@ -6966,12 +6969,16 @@ void update_group_capacity(struct sched_domain *sd, int cpu)
group = child->groups; group = child->groups;
do { do {
capacity += group->sgc->capacity; struct sched_group_capacity *sgc = group->sgc;
capacity += sgc->capacity;
min_capacity = min(sgc->min_capacity, min_capacity);
group = group->next; group = group->next;
} while (group != child->groups); } while (group != child->groups);
} }
sdg->sgc->capacity = capacity; sdg->sgc->capacity = capacity;
sdg->sgc->min_capacity = min_capacity;
} }
/* /*
......
...@@ -892,7 +892,8 @@ struct sched_group_capacity { ...@@ -892,7 +892,8 @@ struct sched_group_capacity {
* CPU capacity of this group, SCHED_CAPACITY_SCALE being max capacity * CPU capacity of this group, SCHED_CAPACITY_SCALE being max capacity
* for a single CPU. * for a single CPU.
*/ */
unsigned int capacity; unsigned long capacity;
unsigned long min_capacity; /* Min per-CPU capacity in group */
unsigned long next_update; unsigned long next_update;
int imbalance; /* XXX unrelated to capacity but shared group state */ int imbalance; /* XXX unrelated to capacity but shared group state */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment