Hi Leo,
On 12/09/2015 06:53 PM, Leo Yan wrote:
Could you post your draft changes here prior to testing? It'll help ensure I'm following your proposal correctly.
Below are the code with our discussion, please help review; I also enclosed the patch in case you want to check with diff format.
Looked over your changes, they look consistent to me with what was discussed earlier. One minor comment inline below.
---<8---
static int find_cpu_new_capacity(int cpu, unsigned long util) { struct sched_domain *sd; struct sched_group_energy *sge; int idx;
sd = rcu_dereference(per_cpu(sd_ea, cpu)); sge = sd->groups->sge;
for (idx = 0; idx < sge->nr_cap_states; idx++) if (sge->cap_states[idx].cap >= util) break;
if (idx == sge->nr_cap_states) idx = idx - 1;
return idx; }
static void find_best_cpu_in_sg(struct cpumask *mask, struct sched_group *sg, struct task_struct *p) { int min_opp = INT_MAX, max_usage = 0, new_usage; int target_cpu = -1, i;
for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg)) {
int opp; /* * p's blocked utilization is still accounted for on prev_cpu * so prev_cpu will receive a negative bias due the double * accouting. However, the blocked utilization may be zero. */ new_usage = get_cpu_usage(i) + task_utilization(p); opp = find_cpu_new_capacity(i, new_usage); /* If need higher OPP, then skip */ if (min_opp < opp) continue; /* If CPU with lowwer OPP, just use it */ if (min_opp > opp) { min_opp = opp; max_usage = new_usage; target_cpu = i; continue; } if (max_usage < new_usage) { max_usage = new_usage; target_cpu = i; continue; } if (i < target_cpu) { target_cpu = i; continue; }
}
BUG_ON(target_cpu == -1);
cpumask_set_cpu(target_cpu, mask); return; }
static int find_power_efficient_cpu(struct cpumask *mask, struct task_struct *p) { int i, target_cpu; int min_energy = 0, diff; struct energy_env eenv;
target_cpu = task_cpu(p);
for_each_cpu(i, mask) {
if (i == task_cpu(p)) continue; memset(&eenv, 0, sizeof(eenv)); eenv.usage_delta = task_utilization(p), eenv.src_cpu = task_cpu(p), eenv.dst_cpu = i, eenv.task = p, diff = energy_diff(&eenv); if (diff < min_energy) { target_cpu = i; min_energy = diff; }
}
return target_cpu; }
static int energy_aware_wake_cpu(struct task_struct *p, int target) { struct sched_domain *sd; struct sched_group *sg, *sg_target; int target_cpu; struct cpumask target_cpus;
sd = rcu_dereference(per_cpu(sd_ea, task_cpu(p)));
if (!sd) return target;
sg = sd->groups; sg_target = sg;
cpumask_clear(&target_cpus);
do { find_best_cpu_in_sg(&target_cpus, sg, p);
} while (sg = sg->next, sg != sd->groups);
if (cpumask_empty(&target_cpus))
I think you could just return task_cpu(p) here rather than setting the mask and continuing into find_power_efficient_cpu?
cpumask_set_cpu(task_cpu(p), &target_cpus);
target_cpu = find_power_efficient_cpu(&target_cpus, p);
return target_cpu; }
thanks, Steve