Skip to content

Commit 23a8818

Browse files
vireshkrafaeljw
authored andcommitted
cpufreq: schedutil: Don't skip freq update if need_freq_update is set
The cpufreq policy's frequency limits (min/max) can get changed at any point of time, while schedutil is trying to update the next frequency. Though the schedutil governor has necessary locking and support in place to make sure we don't miss any of those updates, there is a corner case where the governor will find that the CPU is already running at the desired frequency and so may skip an update. For example, consider that the CPU can run at 1 GHz, 1.2 GHz and 1.4 GHz and is running at 1 GHz currently. Schedutil tries to update the frequency to 1.2 GHz, during this time the policy limits get changed as policy->min = 1.4 GHz. As schedutil (and cpufreq core) does clamp the frequency at various instances, we will eventually set the frequency to 1.4 GHz, while we will save 1.2 GHz in sg_policy->next_freq. Now lets say the policy limits get changed back at this time with policy->min as 1 GHz. The next time schedutil is invoked by the scheduler, we will reevaluate the next frequency (because need_freq_update will get set due to limits change event) and lets say we want to set the frequency to 1.2 GHz again. At this point sugov_update_next_freq() will find the next_freq == current_freq and will abort the update, while the CPU actually runs at 1.4 GHz. Until now need_freq_update was used as a flag to indicate that the policy's frequency limits have changed, and that we should consider the new limits while reevaluating the next frequency. This patch fixes the above mentioned issue by extending the purpose of the need_freq_update flag. If this flag is set now, the schedutil governor will not try to abort a frequency change even if next_freq == current_freq. As similar behavior is required in the case of CPUFREQ_NEED_UPDATE_LIMITS flag as well, need_freq_update will never be set to false if that flag is set for the driver. We also don't need to consider the need_freq_update flag in sugov_update_single() anymore to handle the special case of busy CPU, as we won't abort a frequency update anymore. Reported-by: zhuguangqing <zhuguangqing@xiaomi.com> Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> [ rjw: Rearrange code to avoid a branch ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 3cea11c commit 23a8818

1 file changed

Lines changed: 10 additions & 12 deletions

File tree

kernel/sched/cpufreq_schedutil.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,12 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
102102
static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time,
103103
unsigned int next_freq)
104104
{
105-
if (sg_policy->next_freq == next_freq &&
106-
!cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS))
107-
return false;
105+
if (!sg_policy->need_freq_update) {
106+
if (sg_policy->next_freq == next_freq)
107+
return false;
108+
} else {
109+
sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS);
110+
}
108111

109112
sg_policy->next_freq = next_freq;
110113
sg_policy->last_freq_update_time = time;
@@ -162,11 +165,9 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
162165

163166
freq = map_util_freq(util, freq, max);
164167

165-
if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update &&
166-
!cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS))
168+
if (freq == sg_policy->cached_raw_freq && !sg_policy->need_freq_update)
167169
return sg_policy->next_freq;
168170

169-
sg_policy->need_freq_update = false;
170171
sg_policy->cached_raw_freq = freq;
171172
return cpufreq_driver_resolve_freq(policy, freq);
172173
}
@@ -442,7 +443,6 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
442443
struct sugov_policy *sg_policy = sg_cpu->sg_policy;
443444
unsigned long util, max;
444445
unsigned int next_f;
445-
bool busy;
446446
unsigned int cached_freq = sg_policy->cached_raw_freq;
447447

448448
sugov_iowait_boost(sg_cpu, time, flags);
@@ -453,9 +453,6 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
453453
if (!sugov_should_update_freq(sg_policy, time))
454454
return;
455455

456-
/* Limits may have changed, don't skip frequency update */
457-
busy = !sg_policy->need_freq_update && sugov_cpu_is_busy(sg_cpu);
458-
459456
util = sugov_get_util(sg_cpu);
460457
max = sg_cpu->max;
461458
util = sugov_iowait_apply(sg_cpu, time, util, max);
@@ -464,7 +461,7 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
464461
* Do not reduce the frequency if the CPU has not been idle
465462
* recently, as the reduction is likely to be premature then.
466463
*/
467-
if (busy && next_f < sg_policy->next_freq) {
464+
if (sugov_cpu_is_busy(sg_cpu) && next_f < sg_policy->next_freq) {
468465
next_f = sg_policy->next_freq;
469466

470467
/* Restore cached freq as next_freq has changed */
@@ -829,9 +826,10 @@ static int sugov_start(struct cpufreq_policy *policy)
829826
sg_policy->next_freq = 0;
830827
sg_policy->work_in_progress = false;
831828
sg_policy->limits_changed = false;
832-
sg_policy->need_freq_update = false;
833829
sg_policy->cached_raw_freq = 0;
834830

831+
sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS);
832+
835833
for_each_cpu(cpu, policy->cpus) {
836834
struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
837835

0 commit comments

Comments
 (0)