Skip to content

Commit 63f202e

Browse files
committed
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: 159e485 ("cpuidle: teo: Fix "early hits" handling for disabled idle states") Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent b6495b7 commit 63f202e

File tree

1 file changed

+17
-4
lines changed
  • drivers/cpuidle/governors

1 file changed

+17
-4
lines changed

drivers/cpuidle/governors/teo.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
239239
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
240240
u64 duration_ns;
241241
unsigned int hits, misses, early_hits;
242-
int max_early_idx, constraint_idx, idx, i;
242+
int max_early_idx, prev_max_early_idx, constraint_idx, idx, i;
243243
ktime_t delta_tick;
244244

245245
if (dev->last_state_idx >= 0) {
@@ -256,6 +256,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
256256
misses = 0;
257257
early_hits = 0;
258258
max_early_idx = -1;
259+
prev_max_early_idx = -1;
259260
constraint_idx = drv->state_count;
260261
idx = -1;
261262

@@ -307,6 +308,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
307308
*/
308309
if (!(tick_nohz_tick_stopped() &&
309310
drv->states[idx].target_residency_ns < TICK_NSEC)) {
311+
prev_max_early_idx = max_early_idx;
310312
early_hits = cpu_data->states[i].early_hits;
311313
max_early_idx = idx;
312314
}
@@ -333,6 +335,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
333335
if (early_hits < cpu_data->states[i].early_hits &&
334336
!(tick_nohz_tick_stopped() &&
335337
drv->states[i].target_residency_ns < TICK_NSEC)) {
338+
prev_max_early_idx = max_early_idx;
336339
early_hits = cpu_data->states[i].early_hits;
337340
max_early_idx = i;
338341
}
@@ -346,9 +349,19 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
346349
* "early hits" metric, but if that cannot be determined, just use the
347350
* state selected so far.
348351
*/
349-
if (hits <= misses && max_early_idx >= 0) {
350-
idx = max_early_idx;
351-
duration_ns = drv->states[idx].target_residency_ns;
352+
if (hits <= misses) {
353+
/*
354+
* The current candidate state is not suitable, so take the one
355+
* whose "early hits" metric is the maximum for the range of
356+
* shallower states.
357+
*/
358+
if (idx == max_early_idx)
359+
max_early_idx = prev_max_early_idx;
360+
361+
if (max_early_idx >= 0) {
362+
idx = max_early_idx;
363+
duration_ns = drv->states[idx].target_residency_ns;
364+
}
352365
}
353366

354367
/*

0 commit comments

Comments
 (0)