Commit 63f202e5 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

cpuidle: teo: Avoid using "early hits" incorrectly

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: 159e4856 ("cpuidle: teo: Fix "early hits" handling for disabled idle states")
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent b6495b7f
...@@ -239,7 +239,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -239,7 +239,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
s64 latency_req = cpuidle_governor_latency_req(dev->cpu); s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
u64 duration_ns; u64 duration_ns;
unsigned int hits, misses, early_hits; unsigned int 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; ktime_t delta_tick;
if (dev->last_state_idx >= 0) { if (dev->last_state_idx >= 0) {
...@@ -256,6 +256,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -256,6 +256,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
misses = 0; misses = 0;
early_hits = 0; early_hits = 0;
max_early_idx = -1; max_early_idx = -1;
prev_max_early_idx = -1;
constraint_idx = drv->state_count; constraint_idx = drv->state_count;
idx = -1; idx = -1;
...@@ -307,6 +308,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -307,6 +308,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
*/ */
if (!(tick_nohz_tick_stopped() && if (!(tick_nohz_tick_stopped() &&
drv->states[idx].target_residency_ns < TICK_NSEC)) { drv->states[idx].target_residency_ns < TICK_NSEC)) {
prev_max_early_idx = max_early_idx;
early_hits = cpu_data->states[i].early_hits; early_hits = cpu_data->states[i].early_hits;
max_early_idx = idx; max_early_idx = idx;
} }
...@@ -333,6 +335,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -333,6 +335,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (early_hits < cpu_data->states[i].early_hits && if (early_hits < cpu_data->states[i].early_hits &&
!(tick_nohz_tick_stopped() && !(tick_nohz_tick_stopped() &&
drv->states[i].target_residency_ns < TICK_NSEC)) { drv->states[i].target_residency_ns < TICK_NSEC)) {
prev_max_early_idx = max_early_idx;
early_hits = cpu_data->states[i].early_hits; early_hits = cpu_data->states[i].early_hits;
max_early_idx = i; max_early_idx = i;
} }
...@@ -346,10 +349,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -346,10 +349,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* "early hits" metric, but if that cannot be determined, just use the * "early hits" metric, but if that cannot be determined, just use the
* state selected so far. * state selected so far.
*/ */
if (hits <= misses && max_early_idx >= 0) { 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; idx = max_early_idx;
duration_ns = drv->states[idx].target_residency_ns; duration_ns = drv->states[idx].target_residency_ns;
} }
}
/* /*
* If there is a latency constraint, it may be necessary to use a * If there is a latency constraint, it may be necessary to use a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment