History

sched/fair: Fix negative energy delta in find_energy_efficient_cpu()

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

Pierre Gondois committed 5 years ago

Commit 619e0901 parent 8d4c97c1 file · +15 −12Browse files

Unified · Split

kernel/sched/fair.c+15−12
@@ -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 starting6675 * 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 }
6751unlock:
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 at6760 * 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
6766fail:6769unlock:
6767 rcu_read_unlock();6770 rcu_read_unlock();
6768 6771
6769 return -1;6772 return target;
6770}6773}
6771 6774
6772/*6775/*

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t