compute_energy() traverses scheduling groups and calc_sg_energy() iterates every candidate for scheduling group energy computation. This implementation is good from the point of view of performance, due all candidates energy calculation can be finished by calling these two functions only one time. Because every function has program looping, one is to iterate scheduling group and another is to iterate candidate CPUs, the code is not readable with complex logic, furthermore, it's difficult to do any optimization due this two functions are very coupled with each other.
This patch lifts CPU iteration out of calc_sg_energy(), and move candidates iteration into select_energy_cpu_idx(). With this change, functions can have simple semantics, compute_energy()/calc_sg_energy() is used to calculate energy for only single one CPU, though compute_energy() will be called 3 times compared against 1 time calling before this patch, but calc_sg_energy() should have same overload between with and without this patch, and this function is main contribution for computation.
Change-Id: Ic6d1843a3502baf6939eec1d36067cbfc11af817 Signed-off-by: Leo Yan leo.yan@linaro.org --- kernel/sched/fair.c | 68 ++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 35 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index f4206c1..618c80d 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5678,7 +5678,7 @@ static int group_idle_state(struct energy_env *eenv, int cpu_id) * The required scaling will be performed just one time, by the calling * functions, once we accumulated the contributons for all the SGs. */ -static void calc_sg_energy(struct energy_env *eenv) +static void calc_sg_energy(struct energy_env *eenv, int cpu) { struct sched_group *sg = eenv->sg; int busy_energy, idle_energy; @@ -5687,31 +5687,27 @@ static void calc_sg_energy(struct energy_env *eenv) unsigned long sg_util; int cap_idx, idle_idx; int total_energy = 0; - int cpu; - - for_each_cpu(cpu, &eenv->cpus_mask) {
- /* Compute ACTIVE energy */ - cap_idx = find_new_capacity(eenv, cpu); - busy_power = sg->sge->cap_states[cap_idx].power; - /* - * in order to calculate cpu_norm_util, we need to know which - * capacity level the group will be at, so calculate that first - */ - sg_util = group_norm_util(eenv, cpu); + /* Compute ACTIVE energy */ + cap_idx = find_new_capacity(eenv, cpu); + busy_power = sg->sge->cap_states[cap_idx].power; + /* + * in order to calculate cpu_norm_util, we need to know which + * capacity level the group will be at, so calculate that first + */ + sg_util = group_norm_util(eenv, cpu);
- busy_energy = sg_util * busy_power; + busy_energy = sg_util * busy_power;
- /* Compute IDLE energy */ - idle_idx = group_idle_state(eenv, cpu); - idle_power = sg->sge->idle_states[idle_idx].power; + /* Compute IDLE energy */ + idle_idx = group_idle_state(eenv, cpu); + idle_power = sg->sge->idle_states[idle_idx].power;
- idle_energy = SCHED_CAPACITY_SCALE - sg_util; - idle_energy *= idle_power; + idle_energy = SCHED_CAPACITY_SCALE - sg_util; + idle_energy *= idle_power;
- total_energy = busy_energy + idle_energy; - eenv->cpu[cpu].energy += total_energy; - } + total_energy = busy_energy + idle_energy; + eenv->cpu[cpu].energy += total_energy; }
/* @@ -5721,7 +5717,7 @@ static void calc_sg_energy(struct energy_env *eenv) * NOTE: compute_energy() may fail when racing with sched_domain updates, in * which case we abort by returning -EINVAL. */ -static int compute_energy(struct energy_env *eenv) +static int compute_energy(struct energy_env *eenv, int candidate) { struct cpumask visit_cpus; int cpu_count; @@ -5773,7 +5769,7 @@ static int compute_energy(struct energy_env *eenv) * CPUs in the current visited SG. */ eenv->sg = sg; - calc_sg_energy(eenv); + calc_sg_energy(eenv, candidate);
if (!sd->child) { /* @@ -5847,20 +5843,22 @@ static inline int select_energy_cpu_idx(struct energy_env *eenv) return -1; }
- sg = sd->groups; - do { - /* Skip SGs which do not contains a candidate CPU */ - if (!cpumask_intersects(&eenv->cpus_mask, sched_group_cpus(sg))) - continue; + for_each_cpu(cpu, &eenv->cpus_mask) { + sg = sd->groups; + do { + /* Skip SGs which do not contains a candidate CPU */ + if (!cpumask_intersects(&eenv->cpus_mask, sched_group_cpus(sg))) + continue;
- eenv->sg_top = sg; - /* energy is unscaled to reduce rounding errors */ - if (compute_energy(eenv) == -EINVAL) { - eenv->next_cpu = eenv->prev_cpu; - return -EINVAL; - } + eenv->sg_top = sg; + /* energy is unscaled to reduce rounding errors */ + if (compute_energy(eenv, cpu) == -EINVAL) { + eenv->next_cpu = eenv->prev_cpu; + return -EINVAL; + }
- } while (sg = sg->next, sg != sd->groups); + } while (sg = sg->next, sg != sd->groups); + }
/* Scale energy before comparisons */ for_each_cpu(cpu, &eenv->cpus_mask) -- 1.9.1