On 10/11/15 09:58, Leo Yan wrote:
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.
If you do this, IMHO you're just changing from one scenario in which you base your calculation on erroneous data to another. In your case, if the system underneath EAS has changed, you're operating on stale data for before _and_ after now.
The result which we base task placement decision on, is a difference of energy and it is impossible to calculate this atomically. So what difference does it make to have the error in the resulting energy number comparing to the case where you calculate the energy number purely on stale data but the system you put the task on has changed in the meantime? Worst case scenario is a wrong task placement. The whole cfs code is designed in such a way that you have to be able to work with stale data for the sched domain/sched group statistic data. Don't see an advantage right now.
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))) {
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.