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

Commit 9e31218f authored by Morten Rasmussen's avatar Morten Rasmussen Committed by Andres Oportus
Browse files

ANDROID: sched/fair: Energy-aware wake-up task placement



When the systems is not overutilized, place waking tasks on the most
energy efficient cpu. Previous attempts reduced the search space by
matching task utilization to cpu capacity before consulting the energy
model as this is an expensive operation. The search heuristics didn't
work very well and lacking any better alternatives this patch takes the
brute-force route and tries all potential targets.

This approach doesn't scale, but it might be sufficient for many
embedded applications while work is continuing on a heuristic that can
minimize the necessary computations. The heuristic must be derrived from
the platform energy model rather than make additional assumptions, such
lower capacity implies better energy efficiency. PeterZ mentioned in the
past that we might be able to derrive some simpler deciding functions
using mathematical (modal?) analysis.

Change-Id: I772bacb4c8fd599f8006fa422f842e66377a9c6c
Signed-off-by: default avatarMorten Rasmussen <morten.rasmussen@arm.com>
[rebase: on top of msm-google/android-msm-marlin-3.18]
Signed-off-by: default avatarDietmar Eggemann <dietmar.eggemann@arm.com>
(cherry picked from commit a894422dbdb7b77ea2acfe7ff909ccb5ded23514)
Signed-off-by: default avatarChris Redpath <chris.redpath@arm.com>
Signed-off-by: default avatarQuentin Perret <quentin.perret@arm.com>
parent 53838923
Loading
Loading
Loading
Loading
+57 −0
Original line number Original line Diff line number Diff line
@@ -6411,6 +6411,60 @@ static int wake_cap(struct task_struct *p, int cpu, int prev_cpu)
	return min_cap * 1024 < task_util(p) * capacity_margin;
	return min_cap * 1024 < task_util(p) * capacity_margin;
}
}


static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu)
{
	int i;
	int min_diff = 0, energy_cpu = prev_cpu, spare_cpu = prev_cpu;
	unsigned long max_spare = 0;
	struct sched_domain *sd;

	rcu_read_lock();

	sd = rcu_dereference(per_cpu(sd_ea, prev_cpu));

	if (!sd)
		goto unlock;

	for_each_cpu_and(i, tsk_cpus_allowed(p), sched_domain_span(sd)) {
		int diff;
		unsigned long spare;

		struct energy_env eenv = {
			.util_delta	= task_util(p),
			.src_cpu	= prev_cpu,
			.dst_cpu	= i,
		};

		spare = capacity_spare_wake(i, p);

		if (i == prev_cpu)
			continue;

		if (spare > max_spare) {
			max_spare = spare;
			spare_cpu = i;
		}

		if (spare * 1024 < capacity_margin * task_util(p))
			continue;

		diff = energy_diff(&eenv);

		if (diff < min_diff) {
			min_diff = diff;
			energy_cpu = i;
		}
	}

unlock:
	rcu_read_unlock();

	if (energy_cpu == prev_cpu && !cpu_overutilized(prev_cpu))
		return prev_cpu;

	return energy_cpu != prev_cpu ? energy_cpu : spare_cpu;
}

/*
/*
 * select_task_rq_fair: Select target runqueue for the waking task in domains
 * select_task_rq_fair: Select target runqueue for the waking task in domains
 * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
 * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE,
@@ -6438,6 +6492,9 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
			cpumask_test_cpu(cpu, tsk_cpus_allowed(p)));
			cpumask_test_cpu(cpu, tsk_cpus_allowed(p)));
	}
	}


	if (energy_aware() && !(cpu_rq(prev_cpu)->rd->overutilized))
		return select_energy_cpu_brute(p, prev_cpu);

	rcu_read_lock();
	rcu_read_lock();
	for_each_domain(cpu, tmp) {
	for_each_domain(cpu, tmp) {
		if (!(tmp->flags & SD_LOAD_BALANCE))
		if (!(tmp->flags & SD_LOAD_BALANCE))