diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 4012266f4f64..9b43520dc248 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6340,8 +6340,13 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy { unsigned long prev_delta = ULONG_MAX, best_delta = ULONG_MAX; struct root_domain *rd = cpu_rq(smp_processor_id())->rd; + int max_spare_cap_cpu_ls = prev_cpu, best_idle_cpu = -1; + unsigned long max_spare_cap_ls = 0, target_cap; unsigned long cpu_cap, util, base_energy = 0; + bool boosted, latency_sensitive = false; + unsigned int min_exit_lat = UINT_MAX; int cpu, best_energy_cpu = prev_cpu; + struct cpuidle_state *idle; struct sched_domain *sd; struct perf_domain *pd; @@ -6370,6 +6375,10 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy if (!task_util_est(p)) goto unlock; + latency_sensitive = uclamp_latency_sensitive(p); + boosted = uclamp_boosted(p); + target_cap = boosted ? 0 : ULONG_MAX; + for (; pd; pd = pd->next) { unsigned long cur_delta, spare_cap, max_spare_cap = 0; unsigned long base_energy_pd; @@ -6394,7 +6403,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy continue; /* Always use prev_cpu as a candidate. */ - if (cpu == prev_cpu) { + if (!latency_sensitive && cpu == prev_cpu) { prev_delta = compute_energy(p, prev_cpu, pd); prev_delta -= base_energy_pd; best_delta = min(best_delta, prev_delta); @@ -6409,10 +6418,34 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy max_spare_cap = spare_cap; max_spare_cap_cpu = cpu; } + + if (!latency_sensitive) + continue; + + if (idle_cpu(cpu)) { + cpu_cap = capacity_orig_of(cpu); + if (boosted && cpu_cap < target_cap) + continue; + if (!boosted && cpu_cap > target_cap) + continue; + idle = idle_get_state(cpu_rq(cpu)); + if (idle && idle->exit_latency > min_exit_lat && + cpu_cap == target_cap) + continue; + + if (idle) + min_exit_lat = idle->exit_latency; + target_cap = cpu_cap; + best_idle_cpu = cpu; + } else if (spare_cap > max_spare_cap_ls) { + max_spare_cap_ls = spare_cap; + max_spare_cap_cpu_ls = cpu; + } } /* Evaluate the energy impact of using this CPU. */ - if (max_spare_cap_cpu >= 0 && max_spare_cap_cpu != prev_cpu) { + if (!latency_sensitive && max_spare_cap_cpu >= 0 && + max_spare_cap_cpu != prev_cpu) { cur_delta = compute_energy(p, max_spare_cap_cpu, pd); cur_delta -= base_energy_pd; if (cur_delta < best_delta) { @@ -6424,6 +6457,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy unlock: rcu_read_unlock(); + if (latency_sensitive) + return best_idle_cpu >= 0 ? best_idle_cpu : max_spare_cap_cpu_ls; + /* * Pick the best CPU if prev_cpu cannot be used, or if it saves at * least 6% of the energy used by prev_cpu.