diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 88903098bf7c11a713eccd99efcd64cc08b2a021..960031c9052c9b793a7641bb4813c536623d58c5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5481,6 +5481,58 @@ next: return target; } +static inline int find_best_target(struct task_struct *p) +{ + int i; + int target_cpu = -1; + int target_capacity; + int idle_cpu = -1; + int backup_cpu = -1; + + /* + * Favor 1) busy cpu with most capacity at current OPP + * 2) busy cpu with capacity at higher OPP + * 3) idle_cpu with capacity at current OPP + */ + for_each_cpu(i, tsk_cpus_allowed(p)) { + + int cur_capacity = capacity_curr_of(i); + + /* + * p's blocked utilization is still accounted for on prev_cpu + * so prev_cpu will receive a negative bias due to the double + * accounting. However, the blocked utilization may be zero. + */ + int new_util = get_cpu_usage(i) + boosted_task_utilization(p); + + if (new_util > capacity_orig_of(i)) + continue; + + if (new_util < cur_capacity) { + + if (cpu_rq(i)->nr_running) { + if (target_capacity < cur_capacity) { + /* busy CPU with most capacity at current OPP */ + target_cpu = i; + target_capacity = cur_capacity; + } + } else if (idle_cpu < 0) { + /* first idle CPU with capacity at current OPP */ + idle_cpu = i; + } + } else if (backup_cpu < 0 && cpu_rq(i)->nr_running) { + /* first busy CPU with capacity at higher OPP */ + backup_cpu = i; + } + } + + if (target_cpu < 0) { + target_cpu = backup_cpu >= 0 ? backup_cpu : idle_cpu; + } + + return target_cpu; +} + static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync) { struct sched_domain *sd; @@ -5504,55 +5556,62 @@ static int energy_aware_wake_cpu(struct task_struct *p, int target, int sync) sg = sd->groups; sg_target = sg; - - /* - * Find group with sufficient capacity. We only get here if no cpu is - * overutilized. We may end up overutilizing a cpu by adding the task, - * but that should not be any worse than select_idle_sibling(). - * load_balance() should sort it out later as we get above the tipping - * point. - */ - do { - /* Assuming all cpus are the same in group */ - int max_cap_cpu = group_first_cpu(sg); - + if (sysctl_sched_is_big_little) { /* - * Assume smaller max capacity means more energy-efficient. - * Ideally we should query the energy model for the right - * answer but it easily ends up in an exhaustive search. + * Find group with sufficient capacity. We only get here if no cpu is + * overutilized. We may end up overutilizing a cpu by adding the task, + * but that should not be any worse than select_idle_sibling(). + * load_balance() should sort it out later as we get above the tipping + * point. */ - if (capacity_of(max_cap_cpu) < target_max_cap && - task_fits_capacity(p, max_cap_cpu)) { - sg_target = sg; - target_max_cap = capacity_of(max_cap_cpu); - } + do { + /* Assuming all cpus are the same in group */ + int max_cap_cpu = group_first_cpu(sg); - } while (sg = sg->next, sg != sd->groups); + /* + * Assume smaller max capacity means more energy-efficient. + * Ideally we should query the energy model for the right + * answer but it easily ends up in an exhaustive search. + */ + if (capacity_of(max_cap_cpu) < target_max_cap && + task_fits_capacity(p, max_cap_cpu)) { + sg_target = sg; + target_max_cap = capacity_of(max_cap_cpu); + } - /* Find cpu with sufficient capacity */ - for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg_target)) { - /* - * 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. - */ - int new_usage = get_cpu_usage(i) + boosted_task_utilization(p); + } while (sg = sg->next, sg != sd->groups); - if (new_usage > capacity_orig_of(i)) - continue; + /* Find cpu with sufficient capacity */ + for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg_target)) { + /* + * 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. + */ + int new_usage = get_cpu_usage(i) + boosted_task_utilization(p); - if (new_usage < capacity_curr_of(i)) { - target_cpu = i; - if (cpu_rq(i)->nr_running) - break; - } + if (new_usage > capacity_orig_of(i)) + continue; - /* cpu has capacity at higher OPP, keep it as fallback */ - if (target_cpu < 0) - target_cpu = i; - } + if (new_usage < capacity_curr_of(i)) { + target_cpu = i; + if (cpu_rq(i)->nr_running) + break; + } + + /* cpu has capacity at higher OPP, keep it as fallback */ + if (target_cpu < 0) + target_cpu = i; + } + } else { + /* + * Find a cpu with sufficient capacity + */ + int tmp_target = find_best_target(p); + if (tmp_target >= 0) target_cpu = tmp_target; + } - if (target_cpu < 0) + if (target_cpu < 0) target_cpu = task_cpu(p); else if (target_cpu != task_cpu(p)) { struct energy_env eenv = {