blob: d0ad86ec5f6102e573df4ab5e21252986f034848 [file] [log] [blame]
From a7fc7fb22cc8632cea0d24c26bdde9881aed1a82 Mon Sep 17 00:00:00 2001
From: Quentin Perret <quentin.perret@arm.com>
Date: Wed, 27 Feb 2019 11:21:24 +0000
Subject: [PATCH] NOUPSTREAM: ANDROID: sched/fair: Bias EAS placement for
latency
Add to find_energy_efficient_cpu() a latency sensitive case which mimics
what was done for prefer-idle in android-4.19 and before (see [1] for
reference).
This isn't strictly equivalent to the legacy algorithm but comes real
close, and isn't very invasive. Overall, the idea is to select the
biggest idle CPU we can find for latency-sensitive boosted tasks, and
the smallest CPU where the can fit for latency-sensitive non-boosted
tasks.
The main differences with the legacy behaviour are the following:
1. the policy for 'prefer idle' when there isn't a single idle CPU in
the system is simpler now. We just pick the CPU with the highest
spare capacity;
2. the cstate awareness is implemented by minimizing the exit latency
rather than the idle state index. This is how it is done in the slow
path (find_idlest_group_cpu()), it doesn't require us to keep hooks
into CPUIdle, and should actually be better because what we want is
a CPU that can wake up quickly;
3. non-latency-sensitive tasks just use the standard mainline
energy-aware wake-up path, which decides the placement using the
Energy Model;
4. the 'boosted' and 'latency_sensitive' attributes of a task come from
util_clamp (which now replaces schedtune).
[1] https://android.googlesource.com/kernel/common.git/+/c27c56105dcaaae54ecc39ef33fbfac87a1486fc
[CPNOTE: 30/06/21] Lee: Hoping for an upstream alternative (conversation died)
Bug: 120440300
Change-Id: Ia58516906e9cb5abe08385a8cd088097043d8703
Signed-off-by: Quentin Perret <quentin.perret@arm.com>
---
kernel/sched/fair.c | 38 ++++++++++++++++++++++++++++++++++++--
1 file changed, 36 insertions(+), 2 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index d517efe9e85f33c151aae3295378482c7c577a3d..89fa0526883cf3c2c5ec78f332bdc209f8186586 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7778,11 +7778,16 @@ 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;
unsigned long p_util_min = uclamp_is_used() ? uclamp_eff_value(p, UCLAMP_MIN) : 0;
unsigned long p_util_max = uclamp_is_used() ? uclamp_eff_value(p, UCLAMP_MAX) : 1024;
+ int max_spare_cap_cpu_ls = prev_cpu, best_idle_cpu = -1;
+ unsigned long max_spare_cap_ls = 0, target_cap;
struct root_domain *rd = this_rq()->rd;
int cpu, best_energy_cpu, target = -1;
int prev_fits = -1, best_fits = -1;
unsigned long best_thermal_cap = 0;
unsigned long prev_thermal_cap = 0;
+ bool boosted, latency_sensitive = false;
+ unsigned int min_exit_lat = UINT_MAX;
+ struct cpuidle_state *idle;
struct sched_domain *sd;
struct perf_domain *pd;
struct energy_env eenv;
@@ -7816,6 +7821,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
goto unlock;
eenv_task_busy_time(&eenv, p, prev_cpu);
+ latency_sensitive = uclamp_latency_sensitive(p);
+ boosted = uclamp_boosted(p);
+ target_cap = boosted ? 0 : ULONG_MAX;
for (; pd; pd = pd->next) {
unsigned long util_min = p_util_min, util_max = p_util_max;
@@ -7881,7 +7889,7 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
lsub_positive(&cpu_cap, util);
- if (cpu == prev_cpu) {
+ if (!latency_sensitive && cpu == prev_cpu) {
/* Always use prev_cpu as a candidate. */
prev_spare_cap = cpu_cap;
prev_fits = fits;
@@ -7896,9 +7904,32 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
max_spare_cap_cpu = cpu;
max_fits = fits;
}
+
+ if (!latency_sensitive)
+ continue;
+
+ if (idle_cpu(cpu)) {
+ cpu_cap = arch_scale_cpu_capacity(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 (cpu_cap > max_spare_cap_ls) {
+ max_spare_cap_ls = cpu_cap;
+ max_spare_cap_cpu_ls = cpu;
+ }
}
- if (max_spare_cap_cpu < 0 && prev_spare_cap < 0)
+ if (!latency_sensitive && max_spare_cap_cpu < 0 && prev_spare_cap == 0)
continue;
eenv_pd_busy_time(&eenv, cpus, p);
@@ -7954,6 +7985,9 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
}
rcu_read_unlock();
+ if (latency_sensitive)
+ return best_idle_cpu >= 0 ? best_idle_cpu : max_spare_cap_cpu_ls;
+
if ((best_fits > prev_fits) ||
((best_fits > 0) && (best_delta < prev_delta)) ||
((best_fits < 0) && (best_thermal_cap > prev_thermal_cap)))
--
2.43.0.rc2.451.g8631bc7472-goog