Hi Steve,
Sorry for some late.
On Wed, Nov 25, 2015 at 10:41:32AM -0800, Steve Muckle wrote:
On 11/24/2015 07:55 PM, Leo Yan wrote:
[...]
Let's say we are placing a small task on a big.Little system, and that small task could fit on both the big and Little cluster.
Does the above statement imply that we would not evaluate the best CPU in the big cluster? I'd think we should, in addition to the best CPU in the little cluster, and decide between those two options. This is because we can have cases where the big cluster is actually the most efficient place to run a task due to current task loads and the OPP of the little cluster.
- Select CPUs with lowest OPP to meet capacity requirement;
- Select CPUs with highest utilization (as your said, here need to try to use least one, and I think it's more suitable for rt-app cases, even rt-app-6 also will take 35% CPU's utilization when CPU run at lowest OPP);
- Select CPUs with least CPU ID;
If you think here have no obvious logic error, I will try it in next 1~2 weeks and post result after finish related testing.
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.
---<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)) cpumask_set_cpu(task_cpu(p), &target_cpus);
target_cpu = find_power_efficient_cpu(&target_cpus, p);
return target_cpu; }
--->8---
Thanks, Leo Yan