find_energy_efficient_cpu() (feec()) searches the best energy CPU to place a task on. To do so, compute_energy() estimates the energy impact of placing the task on a CPU, based on CPU and task utilization signals. Utilization signals can be concurrently updated while evaluating a performance domain (pd). In some cases, this leads to having a 'negative delta', i.e. placing the task in the pd is seen as an energy gain. Thus, any further energy comparison is biased. In case of a 'negative delta', return prev_cpu since: 1. a 'negative delta' happens in less than 0.5% of feec() calls, on a Juno with 6 CPUs (4 little, 2 big) 2. it is unlikely to have two consecutive 'negative delta' for a task, so if the first call fails, feec() will correctly place the task in the next feec() call 3. EAS current behavior tends to select prev_cpu if the task doesn't raise the OPP of its current pd. prev_cpu is EAS's generic decision 4. prev_cpu should be preferred to returning an error code. In the latter case, select_idle_sibling() would do the placement, selecting a big (and not energy efficient) CPU. As 3., the task would potentially reside on the big CPU for a long time
Unified · Split
| @@ -6661,15 +6661,15 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu) · 6660 unmodified lines | |||
| 6661 | { | 6661 | { |
| 6662 | unsigned long prev_delta = ULONG_MAX, best_delta = ULONG_MAX; | 6662 | unsigned long prev_delta = ULONG_MAX, best_delta = ULONG_MAX; |
| 6663 | struct root_domain *rd = cpu_rq(smp_processor_id())->rd; | 6663 | struct root_domain *rd = cpu_rq(smp_processor_id())->rd; |
| 6664 | int cpu, best_energy_cpu = prev_cpu, target = -1; | ||
| 6664 | unsigned long cpu_cap, util, base_energy = 0; | 6665 | unsigned long cpu_cap, util, base_energy = 0; |
| 6665 | int cpu, best_energy_cpu = prev_cpu; | ||
| 6666 | struct sched_domain *sd; | 6666 | struct sched_domain *sd; |
| 6667 | struct perf_domain *pd; | 6667 | struct perf_domain *pd; |
| 6668 | 6668 | ||
| 6669 | rcu_read_lock(); | 6669 | rcu_read_lock(); |
| 6670 | pd = rcu_dereference(rd->pd); | 6670 | pd = rcu_dereference(rd->pd); |
| 6671 | if (!pd || READ_ONCE(rd->overutilized)) | 6671 | if (!pd || READ_ONCE(rd->overutilized)) |
| 6672 | goto fail; | 6672 | goto unlock; |
| 6673 | 6673 | ||
| 6674 | /* | 6674 | /* |
| 6675 | * Energy-aware wake-up happens on the lowest sched_domain starting | 6675 | * Energy-aware wake-up happens on the lowest sched_domain starting |
| @@ -6679,7 +6679,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu) · 3 unmodified lines | |||
| 6679 | while (sd && !cpumask_test_cpu(prev_cpu, sched_domain_span(sd))) | 6679 | while (sd && !cpumask_test_cpu(prev_cpu, sched_domain_span(sd))) |
| 6680 | sd = sd->parent; | 6680 | sd = sd->parent; |
| 6681 | if (!sd) | 6681 | if (!sd) |
| 6682 | goto fail; | 6682 | goto unlock; |
| 6683 | |||
| 6684 | target = prev_cpu; | ||
| 6683 | 6685 | ||
| 6684 | sync_entity_load_avg(&p->se); | 6686 | sync_entity_load_avg(&p->se); |
| 6685 | if (!task_util_est(p)) | 6687 | if (!task_util_est(p)) |
| @@ -6734,6 +6736,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu) · 48 unmodified lines | |||
| 6734 | /* Evaluate the energy impact of using prev_cpu. */ | 6736 | /* Evaluate the energy impact of using prev_cpu. */ |
| 6735 | if (compute_prev_delta) { | 6737 | if (compute_prev_delta) { |
| 6736 | prev_delta = compute_energy(p, prev_cpu, pd); | 6738 | prev_delta = compute_energy(p, prev_cpu, pd); |
| 6739 | if (prev_delta < base_energy_pd) | ||
| 6740 | goto unlock; | ||
| 6737 | prev_delta -= base_energy_pd; | 6741 | prev_delta -= base_energy_pd; |
| 6738 | best_delta = min(best_delta, prev_delta); | 6742 | best_delta = min(best_delta, prev_delta); |
| 6739 | } | 6743 | } |
| @@ -6741,6 +6745,8 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu) · 1 unmodified line | |||
| 6741 | /* Evaluate the energy impact of using max_spare_cap_cpu. */ | 6745 | /* Evaluate the energy impact of using max_spare_cap_cpu. */ |
| 6742 | if (max_spare_cap_cpu >= 0) { | 6746 | if (max_spare_cap_cpu >= 0) { |
| 6743 | cur_delta = compute_energy(p, max_spare_cap_cpu, pd); | 6747 | cur_delta = compute_energy(p, max_spare_cap_cpu, pd); |
| 6748 | if (cur_delta < base_energy_pd) | ||
| 6749 | goto unlock; | ||
| 6744 | cur_delta -= base_energy_pd; | 6750 | cur_delta -= base_energy_pd; |
| 6745 | if (cur_delta < best_delta) { | 6751 | if (cur_delta < best_delta) { |
| 6746 | best_delta = cur_delta; | 6752 | best_delta = cur_delta; |
| @@ -6748,25 +6754,22 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu) · 1 unmodified line | |||
| 6748 | } | 6754 | } |
| 6749 | } | 6755 | } |
| 6750 | } | 6756 | } |
| 6751 | unlock: | ||
| 6752 | rcu_read_unlock(); | 6757 | rcu_read_unlock(); |
| 6753 | 6758 | ||
| 6754 | /* | 6759 | /* |
| 6755 | * Pick the best CPU if prev_cpu cannot be used, or if it saves at | 6760 | * Pick the best CPU if prev_cpu cannot be used, or if it saves at |
| 6756 | * least 6% of the energy used by prev_cpu. | 6761 | * least 6% of the energy used by prev_cpu. |
| 6757 | */ | 6762 | */ |
| 6758 | if (prev_delta == ULONG_MAX) | 6763 | if ((prev_delta == ULONG_MAX) || |
| 6759 | return best_energy_cpu; | 6764 | (prev_delta - best_delta) > ((prev_delta + base_energy) >> 4)) |
| 6765 | target = best_energy_cpu; | ||
| 6760 | 6766 | ||
| 6761 | if ((prev_delta - best_delta) > ((prev_delta + base_energy) >> 4)) | 6767 | return target; |
| 6762 | return best_energy_cpu; | ||
| 6763 | |||
| 6764 | return prev_cpu; | ||
| 6765 | 6768 | ||
| 6766 | fail: | 6769 | unlock: |
| 6767 | rcu_read_unlock(); | 6770 | rcu_read_unlock(); |
| 6768 | 6771 | ||
| 6769 | return -1; | 6772 | return target; |
| 6770 | } | 6773 | } |
| 6771 | 6774 | ||
| 6772 | /* | 6775 | /* |