| From cbc11b6256c04f13c8b57006015fb69833141da6 Mon Sep 17 00:00:00 2001 |
| From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> |
| Date: Wed, 13 Nov 2019 01:03:24 +0100 |
| Subject: [PATCH] cpuidle: teo: Avoid using "early hits" incorrectly |
| |
| commit 63f202e5edf161c2ccffa286a9a701e995427b15 upstream. |
| |
| If the current state with the maximum "early hits" metric in |
| teo_select() is also the one "matching" the expected idle duration, |
| it will be used as the candidate one for selection even if its |
| "misses" metric is greater than its "hits" metric, which is not |
| correct. |
| |
| In that case, the candidate state should be shallower than the |
| current one and its "early hits" metric should be the maximum |
| among the idle states shallower than the current one. |
| |
| To make that happen, modify teo_select() to save the index of |
| the state whose "early hits" metric is the maximum for the |
| range of states below the current one and go back to that state |
| if it turns out that the current one should be rejected. |
| |
| Fixes: 159e48560f51 ("cpuidle: teo: Fix "early hits" handling for disabled idle states") |
| Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/teo.c |
| index 9722afd1179b..e5a30db5eef8 100644 |
| --- a/drivers/cpuidle/governors/teo.c |
| +++ b/drivers/cpuidle/governors/teo.c |
| @@ -242,7 +242,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, |
| struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); |
| int latency_req = cpuidle_governor_latency_req(dev->cpu); |
| unsigned int duration_us, hits, misses, early_hits; |
| - int max_early_idx, constraint_idx, idx, i; |
| + int max_early_idx, prev_max_early_idx, constraint_idx, idx, i; |
| ktime_t delta_tick; |
| |
| if (cpu_data->last_state >= 0) { |
| @@ -259,6 +259,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, |
| misses = 0; |
| early_hits = 0; |
| max_early_idx = -1; |
| + prev_max_early_idx = -1; |
| constraint_idx = drv->state_count; |
| idx = -1; |
| |
| @@ -311,6 +312,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, |
| */ |
| if (!(tick_nohz_tick_stopped() && |
| drv->states[idx].target_residency < TICK_USEC)) { |
| + prev_max_early_idx = max_early_idx; |
| early_hits = cpu_data->states[i].early_hits; |
| max_early_idx = idx; |
| } |
| @@ -337,6 +339,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, |
| if (early_hits < cpu_data->states[i].early_hits && |
| !(tick_nohz_tick_stopped() && |
| drv->states[i].target_residency < TICK_USEC)) { |
| + prev_max_early_idx = max_early_idx; |
| early_hits = cpu_data->states[i].early_hits; |
| max_early_idx = i; |
| } |
| @@ -350,9 +353,19 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, |
| * "early hits" metric, but if that cannot be determined, just use the |
| * state selected so far. |
| */ |
| - if (hits <= misses && max_early_idx >= 0) { |
| - idx = max_early_idx; |
| - duration_us = drv->states[idx].target_residency; |
| + if (hits <= misses) { |
| + /* |
| + * The current candidate state is not suitable, so take the one |
| + * whose "early hits" metric is the maximum for the range of |
| + * shallower states. |
| + */ |
| + if (idx == max_early_idx) |
| + max_early_idx = prev_max_early_idx; |
| + |
| + if (max_early_idx >= 0) { |
| + idx = max_early_idx; |
| + duration_us = drv->states[idx].target_residency; |
| + } |
| } |
| |
| /* |
| -- |
| 2.7.4 |
| |