When calculate energy difference, EAS need calculate twice. The first time is to calculate energy before task's migration and second time is to calculate energy if task is migrated to the selected CPU. But there have high chance for these two times have no exactly same context, such like the CPU frequency has been changed by CPUFreq governor. Then the calculation for energy difference will introduce unexpected result and cannot be trusted anymore.
So this patch try to create a snapshot for CPU's utilization, so later's two times' calculation will base on this snapshot; This will be helpful for the calculations with same context.
Signed-off-by: Leo Yan leo.yan@linaro.org --- kernel/sched/fair.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 63aef51..01bb3f0 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4890,6 +4890,11 @@ static inline bool energy_aware(void) return sched_feat(ENERGY_AWARE); }
+struct energy_env_snapshot { + int util[8]; + int block[8]; +}; + struct energy_env { struct sched_group *sg_top; struct cpumask sg_cap; @@ -4900,6 +4905,8 @@ struct energy_env { int energy; int energy_payoff; struct task_struct *task; + struct energy_env_snapshot snapshot; + struct { int before; int after; @@ -4913,6 +4920,24 @@ struct energy_env { } cap; };
+static unsigned long __eas_get_cpu_usage(struct energy_env *eenv, int cpu, int delta) +{ + int sum; + unsigned long usage = eenv->snapshot.util[cpu]; + unsigned long blocked = eenv->snapshot.block[cpu]; + unsigned long capacity_orig = capacity_orig_of(cpu); + + sum = usage + blocked + delta; + + if (sum < 0) + return 0; + + if (sum >= capacity_orig) + return capacity_orig; + + return sum; +} + /* * __cpu_norm_usage() returns the cpu usage relative to a specific capacity, * i.e. it's busy ratio, in the range [0..SCHED_LOAD_SCALE] which is useful for @@ -4927,9 +4952,10 @@ struct energy_env { * * norm_usage = running_time/time ~ usage/capacity */ -static unsigned long __cpu_norm_usage(int cpu, unsigned long capacity, int delta) +static unsigned long __cpu_norm_usage(struct energy_env *eenv, int cpu, + unsigned long capacity, int delta) { - int usage = __get_cpu_usage(cpu, delta); + int usage = __eas_get_cpu_usage(eenv, cpu, delta);
if (usage >= capacity) return SCHED_CAPACITY_SCALE; @@ -4954,7 +4980,7 @@ unsigned long group_max_usage(struct energy_env *eenv)
for_each_cpu(i, &eenv->sg_cap) { delta = calc_usage_delta(eenv, i); - max_usage = max(max_usage, __get_cpu_usage(i, delta)); + max_usage = max(max_usage, __eas_get_cpu_usage(eenv, i, delta)); }
return max_usage; @@ -4978,7 +5004,7 @@ long group_norm_usage(struct energy_env *eenv, struct sched_group *sg)
for_each_cpu(i, sched_group_cpus(sg)) { delta = calc_usage_delta(eenv, i); - usage_sum += __cpu_norm_usage(i, capacity, delta); + usage_sum += __cpu_norm_usage(eenv, i, capacity, delta); }
if (usage_sum > SCHED_CAPACITY_SCALE) @@ -5135,6 +5161,7 @@ static int energy_diff(struct energy_env *eenv) struct sched_domain *sd; struct sched_group *sg; int sd_cpu = -1, energy_before = 0, energy_after = 0; + int i;
struct energy_env eenv_before = { .usage_delta = 0, @@ -5154,6 +5181,17 @@ static int energy_diff(struct energy_env *eenv) return 0; /* Error */
sg = sd->groups; + + for_each_cpu(i, sched_domain_span(sd)) { + eenv_before.snapshot.util[i] = + cpu_rq(i)->cfs.utilization_load_avg; + eenv_before.snapshot.block[i] = + cpu_rq(i)->cfs.utilization_blocked_avg; + + eenv->snapshot.util[i] = eenv_before.snapshot.util[i]; + eenv->snapshot.block[i] = eenv_before.snapshot.block[i]; + } + do { if (eenv->src_cpu != -1 && cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg))) { -- 1.9.1