Skip to content

Commit e43dcf2

Browse files
committed
cpuidle: teo: Consider hits and misses metrics of disabled states
The TEO governor uses idle duration "bins" defined in accordance with the CPU idle states table provided by the driver, so that each "bin" covers the idle duration range between the target residency of the idle state corresponding to it and the target residency of the closest deeper idle state. The governor collects statistics for each bin regardless of whether or not the idle state corresponding to it is currently enabled. In particular, the "hits" and "misses" metrics measure the likelihood of a situation in which both the time till the next timer (sleep length) and the idle duration measured after wakeup fall into the given bin. Namely, if the "hits" value is greater than the "misses" one, that situation is more likely than the one in which the sleep length falls into the given bin, but the idle duration measured after wakeup falls into a bin corresponding to one of the shallower idle states. If the idle state corresponding to the given bin is disabled, it cannot be selected and if it turns out to be the one that should be selected, a shallower idle state needs to be used instead of it. Nevertheless, the metrics collected for the bin corresponding to it are still valid and need to be taken into account as though that state had not been disabled. For this reason, make teo_select() always use the "hits" and "misses" values of the idle duration range that the sleep length falls into even if the specific idle state corresponding to it is disabled and if the "hits" values is greater than the "misses" one, select the closest enabled shallower idle state in that case. Fixes: b26bf6a ("cpuidle: New timer events oriented governor for tickless systems") Signed-off-by: Rafael J. Wysocki <[email protected]> Cc: 5.1+ <[email protected]> # 5.1+
1 parent 4f690bb commit e43dcf2

File tree

1 file changed

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

1 file changed

+21
-4
lines changed

drivers/cpuidle/governors/teo.c

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
233233
{
234234
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
235235
int latency_req = cpuidle_governor_latency_req(dev->cpu);
236-
unsigned int duration_us, early_hits;
236+
unsigned int duration_us, hits, misses, early_hits;
237237
int max_early_idx, constraint_idx, idx, i;
238238
ktime_t delta_tick;
239239

@@ -247,6 +247,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
247247
cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick);
248248
duration_us = ktime_to_us(cpu_data->sleep_length_ns);
249249

250+
hits = 0;
251+
misses = 0;
250252
early_hits = 0;
251253
max_early_idx = -1;
252254
constraint_idx = drv->state_count;
@@ -264,6 +266,17 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
264266
if (s->target_residency > duration_us)
265267
continue;
266268

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+
267280
/*
268281
* If the "early hits" metric of a disabled state is
269282
* greater than the current maximum, it should be taken
@@ -280,8 +293,11 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
280293
continue;
281294
}
282295

283-
if (idx < 0)
296+
if (idx < 0) {
284297
idx = i; /* first enabled state */
298+
hits = cpu_data->states[i].hits;
299+
misses = cpu_data->states[i].misses;
300+
}
285301

286302
if (s->target_residency > duration_us)
287303
break;
@@ -290,6 +306,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
290306
constraint_idx = i;
291307

292308
idx = i;
309+
hits = cpu_data->states[i].hits;
310+
misses = cpu_data->states[i].misses;
293311

294312
if (early_hits < cpu_data->states[i].early_hits &&
295313
!(tick_nohz_tick_stopped() &&
@@ -307,8 +325,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
307325
* "early hits" metric, but if that cannot be determined, just use the
308326
* state selected so far.
309327
*/
310-
if (cpu_data->states[idx].hits <= cpu_data->states[idx].misses &&
311-
max_early_idx >= 0) {
328+
if (hits <= misses && max_early_idx >= 0) {
312329
idx = max_early_idx;
313330
duration_us = drv->states[idx].target_residency;
314331
}

0 commit comments

Comments
 (0)