In the previous code, if there have imbalance the scheduler will randomly to select task for migration. E.g, it's possible to migrate only one big task or alternately to migrate two small tasks which have similar total utilization with the big task. This works well for SMP platform by eventually spreading tasks as possible, but this will introduce potential performance and power issues for asymmetric architecture (like ARM big.LITTLE). In the example, the sub optimal result is to migrate two small tasks but leave the big task on LITTLE core; so the big task cannot utilize big core's high performance and two small tasks consume more power on big core but actually the LITTLE cores can meet their capacity requirement.
This patch is to use rq's rb tree for task utilization track and easily to select the highest utilization task and give it the chance to migrate to higher capacity CPU; after the highest utilization task has been detached, it also will be removed from the rb tree; so the code still can give more chance to other lower utilization tasks to migrate to higher capacity CPU if still has rest imbalance value.
Signed-off-by: Leo Yan leo.yan@linaro.org --- kernel/sched/fair.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7183000..ec43670 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6745,16 +6745,32 @@ static int can_migrate_task(struct task_struct *p, struct lb_env *env) { int tsk_cache_hot; + struct sched_entity *se;
lockdep_assert_held(&env->src_rq->lock);
/* * We do not migrate tasks that are: - * 1) throttled_lb_pair, or - * 2) cannot be migrated to this CPU due to cpus_allowed, or - * 3) running (obviously), or - * 4) are cache-hot on their current CPU. + * 1) energy_aware is enabled and highest utilization task is + * migrated to higher capacity CPU, + * 2) throttled_lb_pair, or + * 3) cannot be migrated to this CPU due to cpus_allowed, or + * 4) running (obviously), or + * 5) are cache-hot on their current CPU. */ + + if (energy_aware() && + (capacity_orig_of(env->dst_cpu) > capacity_orig_of(env->src_cpu))) { + + se = __pick_first_queue_util(env->src_rq); + if (&p->se != se) + return 0; + + if (cpu_overutilized(env->dst_cpu) && + !idle_cpu(env->dst_cpu)) + return 0; + } + if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu)) return 0;
-- 1.9.1