Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cb866ac authored by Chris Redpath's avatar Chris Redpath
Browse files

ANDROID: sched/fair: Fall back to slow path wakeup placement if needed



Sometimes we can be in a scenario where we are unable to calculate an
energy-aware task placement. This can happen for a few reasons.
1. We might be racing with a hotplug and be unable to access the
   whole-system energy structures
2. The system might be in a condition (due to task size and load)
   whereby there is only one potential place to put a task (when
   we consider avoiding overutilization etc.).
3. There might actually be no non-overutilized sched domain in
   the system where the current task would fit.

We handle case 3 directly in select_task_rq_fair - there is no point
even checking what the energy situation might be since we can already
tell that it is not possible to do an energy-aware placement of this
task. When that is apparent, we null out the energy_sd and fallback to
the regular slow-path wakeup (which is also capacity-aware).

For the other cases, we can't tell we are in such a scenario until we do
at least a little further digging. Allow find_energy_efficient_cpu to
return -1 to indicate that we did not attempt an energy-aware wakeup as
either we couldn't or there was only one potential candidate.

When that happens, we will set new_cpu == -1 and drop again into
find_idlest_cpu to place the task (which is capacity aware).

Change-Id: I65454ea7bba6b85ee0467f28929650e80cba0cab
Signed-off-by: default avatarChris Redpath <chris.redpath@arm.com>
parent c8d50e06
Loading
Loading
Loading
Loading
+27 −11
Original line number Diff line number Diff line
@@ -5826,14 +5826,26 @@ static inline bool cpu_in_sg(struct sched_group *sg, int cpu)
 * select_energy_cpu_idx(): estimate the energy impact of changing the
 * utilization distribution.
 *
 * The eenv parameter specifies the changes: utilisation amount and a pair of
 * possible CPU candidates (the previous CPU and a different target CPU).
 * The eenv parameter specifies the changes: utilization amount and a
 * collection of possible CPU candidates. The number of candidates
 * depends upon the selection algorithm used.
 *
 * If find_best_target was used to select candidate CPUs, there will
 * be at most 3 including prev_cpu. If not, we used a brute force
 * selection which will provide the union of:
 *  * CPUs belonging to the highest sd which is not overutilized
 *  * CPUs the task is allowed to run on
 *  * online CPUs
 *
 * This function returns the index of a CPU candidate specified by the
 * energy_env which corresponds to the most energy_efficient CPU.
 * energy_env which corresponds to the most energy efficient CPU.
 * Thus, 0 (EAS_CPU_PRV) means that non of the CPU candidate is more energy
 * efficient than running on prev_cpu. This is also the value returned in case
 * of abort due to error conditions during the computations.
 * of abort due to error conditions during the computations. The only
 * exception to this if we fail to access the energy model via sd_ea, where
 * we return -1 with the intent of asking the system to use a different
 * wakeup placement algorithm.
 *
 * A value greater than zero means that the most energy efficient CPU is the
 * one represented by eenv->cpu[eenv->next_idx].cpu_id.
 */
@@ -5849,7 +5861,7 @@ static inline int select_energy_cpu_idx(struct energy_env *eenv)
	sd_cpu = eenv->cpu[EAS_CPU_PRV].cpu_id;
	sd = rcu_dereference(per_cpu(sd_ea, sd_cpu));
	if (!sd)
		return EAS_CPU_PRV;
		return -1;

	cpumask_clear(&eenv->cpus_mask);
	for (cpu_idx = EAS_CPU_PRV; cpu_idx < eenv->max_cpu_count; ++cpu_idx) {
@@ -7088,7 +7100,7 @@ static int find_energy_efficient_cpu(struct sched_domain *sd,
{
	int use_fbt = sched_feat(FIND_BEST_TARGET);
	int cpu_iter, eas_cpu_idx = EAS_CPU_NXT;
	int energy_cpu = prev_cpu;
	int energy_cpu = -1;
	struct energy_env *eenv;

	if (sysctl_sched_sync_hint_enable && sync) {
@@ -7097,7 +7109,7 @@ static int find_energy_efficient_cpu(struct sched_domain *sd,
		}
	}

	/* take ownership of our per-cpu data structure */
	/* prepopulate energy diff environment */
	eenv = get_eenv(p, prev_cpu);
	if (eenv->max_cpu_count < 2)
		return energy_cpu;
@@ -7168,8 +7180,8 @@ static int find_energy_efficient_cpu(struct sched_domain *sd,
	}

	/* find most energy-efficient CPU */
	eas_cpu_idx = select_energy_cpu_idx(eenv);
	energy_cpu = eenv->cpu[eas_cpu_idx].cpu_id;
	energy_cpu = select_energy_cpu_idx(eenv) < 0 ? -1 :
					eenv->cpu[eenv->next_idx].cpu_id;

	return energy_cpu;
}
@@ -7323,7 +7335,11 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
	} else {
		if (energy_sd)
			new_cpu = find_energy_efficient_cpu(energy_sd, p, cpu, prev_cpu, sync);
		else

		/* if we did an energy-aware placement and had no choices available
		 * then fall back to the default find_idlest_cpu choice
		 */
		if (!energy_sd || (energy_sd && new_cpu == -1))
			new_cpu = find_idlest_cpu(sd, p, cpu, prev_cpu, sd_flag);
	}