@@ -233,7 +233,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
233
233
{
234
234
struct teo_cpu * cpu_data = per_cpu_ptr (& teo_cpus , dev -> cpu );
235
235
int latency_req = cpuidle_governor_latency_req (dev -> cpu );
236
- unsigned int duration_us , count ;
236
+ unsigned int duration_us , hits , misses , early_hits ;
237
237
int max_early_idx , constraint_idx , idx , i ;
238
238
ktime_t delta_tick ;
239
239
@@ -247,7 +247,9 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
247
247
cpu_data -> sleep_length_ns = tick_nohz_get_sleep_length (& delta_tick );
248
248
duration_us = ktime_to_us (cpu_data -> sleep_length_ns );
249
249
250
- count = 0 ;
250
+ hits = 0 ;
251
+ misses = 0 ;
252
+ early_hits = 0 ;
251
253
max_early_idx = -1 ;
252
254
constraint_idx = drv -> state_count ;
253
255
idx = -1 ;
@@ -258,23 +260,61 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
258
260
259
261
if (s -> disabled || su -> disable ) {
260
262
/*
261
- * If the "early hits" metric of a disabled state is
262
- * greater than the current maximum, it should be taken
263
- * into account, because it would be a mistake to select
264
- * a deeper state with lower "early hits" metric. The
265
- * index cannot be changed to point to it, however, so
266
- * just increase the max count alone and let the index
267
- * still point to a shallower idle state.
263
+ * Ignore disabled states with target residencies beyond
264
+ * the anticipated idle duration.
268
265
*/
269
- if (max_early_idx >= 0 &&
270
- count < cpu_data -> states [i ].early_hits )
271
- count = cpu_data -> states [i ].early_hits ;
266
+ if (s -> target_residency > duration_us )
267
+ continue ;
268
+
269
+ /*
270
+ * This state is disabled, so the range of idle duration
271
+ * values corresponding to it is covered by the current
272
+ * candidate state, but still the "hits" and "misses"
273
+ * metrics of the disabled state need to be used to
274
+ * decide whether or not the state covering the range in
275
+ * question is good enough.
276
+ */
277
+ hits = cpu_data -> states [i ].hits ;
278
+ misses = cpu_data -> states [i ].misses ;
279
+
280
+ if (early_hits >= cpu_data -> states [i ].early_hits ||
281
+ idx < 0 )
282
+ continue ;
283
+
284
+ /*
285
+ * If the current candidate state has been the one with
286
+ * the maximum "early hits" metric so far, the "early
287
+ * hits" metric of the disabled state replaces the
288
+ * current "early hits" count to avoid selecting a
289
+ * deeper state with lower "early hits" metric.
290
+ */
291
+ if (max_early_idx == idx ) {
292
+ early_hits = cpu_data -> states [i ].early_hits ;
293
+ continue ;
294
+ }
295
+
296
+ /*
297
+ * The current candidate state is closer to the disabled
298
+ * one than the current maximum "early hits" state, so
299
+ * replace the latter with it, but in case the maximum
300
+ * "early hits" state index has not been set so far,
301
+ * check if the current candidate state is not too
302
+ * shallow for that role.
303
+ */
304
+ if (!(tick_nohz_tick_stopped () &&
305
+ drv -> states [idx ].target_residency < TICK_USEC )) {
306
+ early_hits = cpu_data -> states [i ].early_hits ;
307
+ max_early_idx = idx ;
308
+ }
272
309
273
310
continue ;
274
311
}
275
312
276
- if (idx < 0 )
313
+ if (idx < 0 ) {
277
314
idx = i ; /* first enabled state */
315
+ hits = cpu_data -> states [i ].hits ;
316
+ misses = cpu_data -> states [i ].misses ;
317
+ }
278
318
279
319
if (s -> target_residency > duration_us )
280
320
break ;
@@ -283,11 +323,13 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
283
323
constraint_idx = i ;
284
324
285
325
idx = i ;
326
+ hits = cpu_data -> states [i ].hits ;
327
+ misses = cpu_data -> states [i ].misses ;
286
328
287
- if (count < cpu_data -> states [i ].early_hits &&
329
+ if (early_hits < cpu_data -> states [i ].early_hits &&
288
330
!(tick_nohz_tick_stopped () &&
289
331
drv -> states [i ].target_residency < TICK_USEC )) {
290
- count = cpu_data -> states [i ].early_hits ;
332
+ early_hits = cpu_data -> states [i ].early_hits ;
291
333
max_early_idx = i ;
292
334
}
293
335
}
@@ -300,8 +342,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
300
342
* "early hits" metric, but if that cannot be determined, just use the
301
343
* state selected so far.
302
344
*/
303
- if (cpu_data -> states [idx ].hits <= cpu_data -> states [idx ].misses &&
304
- max_early_idx >= 0 ) {
345
+ if (hits <= misses && max_early_idx >= 0 ) {
305
346
idx = max_early_idx ;
306
347
duration_us = drv -> states [idx ].target_residency ;
307
348
}
@@ -316,10 +357,9 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
316
357
if (idx < 0 ) {
317
358
idx = 0 ; /* No states enabled. Must use 0. */
318
359
} else if (idx > 0 ) {
360
+ unsigned int count = 0 ;
319
361
u64 sum = 0 ;
320
362
321
- count = 0 ;
322
-
323
363
/*
324
364
* Count and sum the most recent idle duration values less than
325
365
* the current expected idle duration value.
0 commit comments