aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaravana Kannan <skannan@codeaurora.org>2014-10-15 12:44:18 -0700
committerRuchi Kandoi <kandoiruchi@google.com>2015-05-19 12:45:31 -0700
commitb4ca5bc05c4daf08366379812099e74c757096db (patch)
tree933ee171b7bbdf3fadcfd42dbe6c7501c5132e90
parente456f1e59d6aade6801c053babf375cc95d98264 (diff)
cpufreq: interactive: Exercise hispeed settings at a policy level
If a heavy task migrates between otherwise idle CPUs in a policy during every sample window, the above hispeed delay window for the CPUs would get restarted for every sample window. Due to the continuous restart of above hispeed delay window, none of the CPUs would ever pick a target frequency higher than hispeed frequency. This causes the policy's frequency to be stuck at hispeed freq even if the load justifies a higher frequency. To fix this, the above high speed delay window is restarted only when the policy frequency changes. This ensures that tasks migrating between CPUs in a policy are handled correctly. Also, the hispeed load/frequency heuristic is only necessary when the information is insufficient to determine if the load on the CPU needs at least hispeed frequency. When the policy frequency is already at or above hispeed frequency, if the CPU load% based on policy frequency is not above hispeed load, then the information is clearly sufficient to determine that the load on the CPU does not need hispeed frequency. Therefore, compute CPU load% (which is used only to compare against hispeed load) based on policy frequency instead of CPU target frequency. Change-Id: I8b5dfe6c50bee567a6719f0980e3f7757876ce4b Signed-off-by: Saravana Kannan <skannan@codeaurora.org> Signed-off-by: Junjie Wu <junjiew@codeaurora.org>
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c40
1 files changed, 26 insertions, 14 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 508815511b89..b4e1df18518b 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -49,7 +49,8 @@ struct cpufreq_interactive_cpuinfo {
unsigned int floor_freq;
unsigned int max_freq;
u64 floor_validate_time;
- u64 hispeed_validate_time;
+ u64 pol_hispeed_val_time; /* policy hispeed_validate_time */
+ u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
struct rw_semaphore enable_sem;
int governor_enabled;
};
@@ -367,7 +368,7 @@ static void cpufreq_interactive_timer(unsigned long data)
tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime;
if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) {
- if (pcpu->target_freq < tunables->hispeed_freq) {
+ if (pcpu->policy->cur < tunables->hispeed_freq) {
new_freq = tunables->hispeed_freq;
} else {
new_freq = choose_freq(pcpu, loadadjfreq);
@@ -378,14 +379,14 @@ static void cpufreq_interactive_timer(unsigned long data)
} else {
new_freq = choose_freq(pcpu, loadadjfreq);
if (new_freq > tunables->hispeed_freq &&
- pcpu->target_freq < tunables->hispeed_freq)
+ pcpu->policy->cur < tunables->hispeed_freq)
new_freq = tunables->hispeed_freq;
}
- if (pcpu->target_freq >= tunables->hispeed_freq &&
- new_freq > pcpu->target_freq &&
- now - pcpu->hispeed_validate_time <
- freq_to_above_hispeed_delay(tunables, pcpu->target_freq)) {
+ if (pcpu->policy->cur >= tunables->hispeed_freq &&
+ new_freq > pcpu->policy->cur &&
+ now - pcpu->pol_hispeed_val_time <
+ freq_to_above_hispeed_delay(tunables, pcpu->policy->cur)) {
trace_cpufreq_interactive_notyet(
data, cpu_load, pcpu->target_freq,
pcpu->policy->cur, new_freq);
@@ -393,7 +394,7 @@ static void cpufreq_interactive_timer(unsigned long data)
goto rearm;
}
- pcpu->hispeed_validate_time = now;
+ pcpu->loc_hispeed_val_time = now;
if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
new_freq, CPUFREQ_RELATION_L,
@@ -553,6 +554,8 @@ static int cpufreq_interactive_speedchange_task(void *data)
for_each_cpu(cpu, &tmp_mask) {
unsigned int j;
unsigned int max_freq = 0;
+ struct cpufreq_interactive_cpuinfo *pjcpu;
+ u64 hvt = ~0ULL;
pcpu = &per_cpu(cpuinfo, cpu);
if (!down_read_trylock(&pcpu->enable_sem))
@@ -563,17 +566,25 @@ static int cpufreq_interactive_speedchange_task(void *data)
}
for_each_cpu(j, pcpu->policy->cpus) {
- struct cpufreq_interactive_cpuinfo *pjcpu =
- &per_cpu(cpuinfo, j);
+ pjcpu = &per_cpu(cpuinfo, j);
- if (pjcpu->target_freq > max_freq)
+ if (pjcpu->target_freq > max_freq) {
max_freq = pjcpu->target_freq;
+ hvt = pjcpu->loc_hispeed_val_time;
+ } else if (pjcpu->target_freq == max_freq) {
+ hvt = min(hvt, pjcpu->loc_hispeed_val_time);
+ }
}
- if (max_freq != pcpu->policy->cur)
+ if (max_freq != pcpu->policy->cur) {
__cpufreq_driver_target(pcpu->policy,
max_freq,
CPUFREQ_RELATION_H);
+ for_each_cpu(j, pcpu->policy->cpus) {
+ pjcpu = &per_cpu(cpuinfo, j);
+ pjcpu->pol_hispeed_val_time = hvt;
+ }
+ }
trace_cpufreq_interactive_setspeed(cpu,
pcpu->target_freq,
pcpu->policy->cur);
@@ -605,7 +616,7 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab
if (pcpu->target_freq < tunables->hispeed_freq) {
pcpu->target_freq = tunables->hispeed_freq;
cpumask_set_cpu(i, &speedchange_cpumask);
- pcpu->hispeed_validate_time =
+ pcpu->pol_hispeed_val_time =
ktime_to_us(ktime_get());
anyboost = 1;
}
@@ -1234,8 +1245,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
pcpu->floor_freq = pcpu->target_freq;
pcpu->floor_validate_time =
ktime_to_us(ktime_get());
- pcpu->hispeed_validate_time =
+ pcpu->pol_hispeed_val_time =
pcpu->floor_validate_time;
+ pcpu->loc_hispeed_val_time = pcpu->floor_validate_time;
pcpu->max_freq = policy->max;
down_write(&pcpu->enable_sem);
del_timer_sync(&pcpu->cpu_timer);