From 512bf8141094a1c46949a4e3211c1acbe3cc6277 Mon Sep 17 00:00:00 2001 From: Junjie Wu Date: Wed, 26 Aug 2015 17:47:21 -0700 Subject: [PATCH] cpufreq: interactive: Allow frequency drop during max_freq_hysteresis max_freq_hysteresis keeps CPU at policy->max even after load goes away. This is necessary for some workloads where heavy task start and stop often. However, in case heavy task indeed stops, it's not very power friendly to stay at policy->max for extended period. Instead of keeping CPU at policy->max, drop frequency optimistically. If a heavy load starts back up again and hit go_hispeed_load within max_freq_hysteresis period, directly ramp back up to policy->max. Change-Id: I5edf6d765a3599a5b26e13e584bd237e932593f0 Signed-off-by: Junjie Wu --- drivers/cpufreq/cpufreq_interactive.c | 46 +++++++++++++++++---------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 1516d6ea9011..e73b5d7a62ed 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -470,6 +470,8 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif) unsigned long max_cpu; int i, fcpu; struct cpufreq_govinfo govinfo; + bool skip_hispeed_logic, skip_min_sample_time; + bool policy_max_fast_restore = false; if (!down_read_trylock(&ppol->enable_sem)) return; @@ -532,7 +534,20 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif) cpu_load = loadadjfreq / ppol->target_freq; tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime; - if (tunables->ignore_hispeed_on_notif && is_notif) { + skip_hispeed_logic = tunables->ignore_hispeed_on_notif && is_notif; + skip_min_sample_time = tunables->fast_ramp_down && is_notif; + if (now - ppol->max_freq_hyst_start_time < + tunables->max_freq_hysteresis && + cpu_load >= tunables->go_hispeed_load && + ppol->target_freq < ppol->policy->max) { + skip_hispeed_logic = true; + skip_min_sample_time = true; + policy_max_fast_restore = true; + } + + if (policy_max_fast_restore) { + new_freq = ppol->policy->max; + } else if (skip_hispeed_logic) { new_freq = choose_freq(ppol, loadadjfreq); } else if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) { if (ppol->target_freq < tunables->hispeed_freq) { @@ -550,7 +565,11 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif) new_freq = tunables->hispeed_freq; } - if ((!tunables->ignore_hispeed_on_notif || !is_notif) && + if (now - ppol->max_freq_hyst_start_time < + tunables->max_freq_hysteresis) + new_freq = max(tunables->hispeed_freq, new_freq); + + if (!skip_hispeed_logic && ppol->target_freq >= tunables->hispeed_freq && new_freq > ppol->target_freq && now - ppol->hispeed_validate_time < @@ -573,22 +592,11 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif) new_freq = ppol->freq_table[index].frequency; - if ((!tunables->fast_ramp_down || !is_notif) && - new_freq < ppol->target_freq && - now - ppol->max_freq_hyst_start_time < - tunables->max_freq_hysteresis) { - trace_cpufreq_interactive_notyet(max_cpu, cpu_load, - ppol->target_freq, ppol->policy->cur, new_freq); - spin_unlock_irqrestore(&ppol->target_freq_lock, flags); - goto rearm; - } - /* * Do not scale below floor_freq unless we have been at or above the * floor frequency for the minimum sample time since last validated. */ - if ((!tunables->fast_ramp_down || !is_notif) && - new_freq < ppol->floor_freq) { + if (!skip_min_sample_time && new_freq < ppol->floor_freq) { if (now - ppol->floor_validate_time < tunables->min_sample_time) { trace_cpufreq_interactive_notyet( @@ -604,15 +612,19 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif) * or above the selected frequency for a minimum of min_sample_time, * if not boosted to hispeed_freq. If boosted to hispeed_freq then we * allow the speed to drop as soon as the boostpulse duration expires - * (or the indefinite boost is turned off). + * (or the indefinite boost is turned off). If policy->max is restored + * for max_freq_hysteresis, don't extend the timestamp. Otherwise, it + * could incorrectly extended the duration of max_freq_hysteresis by + * min_sample_time. */ - if (!tunables->boosted || new_freq > tunables->hispeed_freq) { + if ((!tunables->boosted || new_freq > tunables->hispeed_freq) + && !policy_max_fast_restore) { ppol->floor_freq = new_freq; ppol->floor_validate_time = now; } - if (new_freq == ppol->policy->max) + if (new_freq == ppol->policy->max && !policy_max_fast_restore) ppol->max_freq_hyst_start_time = now; if (ppol->target_freq == new_freq &&