Lines Matching +full:wakeup +full:- +full:latency
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2018 - 2021 Intel Corporation
10 * DOC: teo-description
14 * other interrupt types, so they are likely to dominate CPU wakeup patterns.
20 * Of course, non-timer wakeup sources are more important in some use cases,
27 * checks if it can select a shallow idle state using wakeup pattern information
29 * at all. For this purpose, it counts CPU wakeup events and looks for an idle
31 * after wakeup) in the majority of relevant recent cases. If the target
51 * sleep length and the idle duration measured after CPU wakeup fall into the
54 * non-timer wakeup events for which the measured idle duration falls into a bin
64 * steps (modulo the possible latency constraint that must be taken into account
70 * - The sum of the "hits" metric for all of the idle states shallower than
74 * - The sum of the "intercepts" metric for all of the idle states shallower
76 * likely woken up by a non-timer wakeup source).
82 * - Traverse the enabled idle states shallower than the candidate one in the
85 * - For each of them compute the sum of the "intercepts" metrics over all
89 * - If this sum is greater than a half of the second sum computed in step 1,
109 * Idle state exit latency threshold used for deciding whether or not to check
122 * struct teo_bin - Metrics used by the TEO cpuidle governor.
132 * struct teo_cpu - CPU data used by the TEO cpuidle governor.
138 * @artificial_wakeup: Set if the wakeup has been triggered by a safety net.
152 * teo_update - Update CPU metrics after wakeup.
158 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_update()
163 cpu_data->short_idles -= cpu_data->short_idles >> DECAY_SHIFT; in teo_update()
165 if (cpu_data->artificial_wakeup) { in teo_update()
172 u64 lat_ns = drv->states[dev->last_state_idx].exit_latency_ns; in teo_update()
174 measured_ns = dev->last_residency_ns; in teo_update()
176 * The delay between the wakeup and the first instruction in teo_update()
177 * executed by the CPU is not likely to be worst-case every in teo_update()
178 * time, so take 1/2 of the exit latency as a very rough in teo_update()
182 measured_ns -= lat_ns / 2; in teo_update()
184 cpu_data->short_idles += PULSE; in teo_update()
187 cpu_data->short_idles += PULSE; in teo_update()
196 for (i = 0; i < drv->state_count; i++) { in teo_update()
197 struct teo_bin *bin = &cpu_data->state_bins[i]; in teo_update()
199 bin->hits -= bin->hits >> DECAY_SHIFT; in teo_update()
200 bin->intercepts -= bin->intercepts >> DECAY_SHIFT; in teo_update()
202 target_residency_ns = drv->states[i].target_residency_ns; in teo_update()
204 if (target_residency_ns <= cpu_data->sleep_length_ns) { in teo_update()
211 cpu_data->tick_intercepts -= cpu_data->tick_intercepts >> DECAY_SHIFT; in teo_update()
219 cpu_data->state_bins[idx_timer].hits += PULSE; in teo_update()
221 cpu_data->state_bins[idx_duration].intercepts += PULSE; in teo_update()
223 cpu_data->tick_intercepts += PULSE; in teo_update()
226 cpu_data->total -= cpu_data->total >> DECAY_SHIFT; in teo_update()
227 cpu_data->total += PULSE; in teo_update()
233 drv->states[i].target_residency_ns >= TICK_NSEC; in teo_state_ok()
237 * teo_find_shallower_state - Find shallower idle state matching given duration.
250 for (i = state_idx - 1; i >= 0; i--) { in teo_find_shallower_state()
251 if (dev->states_usage[i].disable || in teo_find_shallower_state()
252 (no_poll && drv->states[i].flags & CPUIDLE_FLAG_POLLING)) in teo_find_shallower_state()
256 if (drv->states[i].target_residency_ns <= duration_ns) in teo_find_shallower_state()
263 * teo_select - Selects the next idle state to enter.
271 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_select()
272 s64 latency_req = cpuidle_governor_latency_req(dev->cpu); in teo_select()
279 int idx0 = 0, idx = -1; in teo_select()
283 if (dev->last_state_idx >= 0) { in teo_select()
285 dev->last_state_idx = -1; in teo_select()
291 * be known whether or not the subsequent wakeup is caused by a timer. in teo_select()
292 * It is generally fine to count the wakeup as an intercept then, except in teo_select()
297 cpu_data->sleep_length_ns = KTIME_MAX; in teo_select()
300 if (drv->state_count < 2) { in teo_select()
305 if (!dev->states_usage[0].disable) in teo_select()
308 /* Compute the sums of metrics for early wakeup pattern detection. */ in teo_select()
309 for (i = 1; i < drv->state_count; i++) { in teo_select()
310 struct teo_bin *prev_bin = &cpu_data->state_bins[i-1]; in teo_select()
311 struct cpuidle_state *s = &drv->states[i]; in teo_select()
317 intercept_sum += prev_bin->intercepts; in teo_select()
318 hit_sum += prev_bin->hits; in teo_select()
320 if (dev->states_usage[i].disable) in teo_select()
328 if (s->exit_latency_ns <= latency_req) in teo_select()
347 duration_ns = drv->states[idx].target_residency_ns; in teo_select()
358 if (2 * idx_intercept_sum > cpu_data->total - idx_hit_sum) { in teo_select()
371 for (i = idx - 1; i >= 0; i--) { in teo_select()
372 struct teo_bin *bin = &cpu_data->state_bins[i]; in teo_select()
374 intercept_sum += bin->intercepts; in teo_select()
383 !dev->states_usage[i].disable) { in teo_select()
391 if (dev->states_usage[i].disable) in teo_select()
417 * If there is a latency constraint, it may be necessary to select an in teo_select()
426 * length is not updated, the subsequent wakeup will be counted as an in teo_select()
437 * questionable anyway for latency reasons. Thus if the measured idle in teo_select()
439 * non-timer wakeups to be dominant and skip updating the sleep length in teo_select()
440 * to reduce latency. in teo_select()
442 * Also, if the latency constraint is sufficiently low, it will force in teo_select()
443 * shallow idle states regardless of the wakeup type, so the sleep in teo_select()
446 if ((!idx || drv->states[idx].target_residency_ns < RESIDENCY_THRESHOLD_NS) && in teo_select()
447 (2 * cpu_data->short_idles >= cpu_data->total || in teo_select()
452 cpu_data->sleep_length_ns = duration_ns; in teo_select()
461 if (drv->states[idx].target_residency_ns > duration_ns) { in teo_select()
470 * total wakeup events, do not stop the tick. in teo_select()
472 if (drv->states[idx].target_residency_ns < TICK_NSEC && in teo_select()
473 cpu_data->tick_intercepts > cpu_data->total / 2 + cpu_data->total / 8) in teo_select()
482 if ((!(drv->states[idx].flags & CPUIDLE_FLAG_POLLING) && in teo_select()
492 drv->states[idx].target_residency_ns > delta_tick) in teo_select()
501 * teo_reflect - Note that governor data for the CPU need to be updated.
507 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_reflect()
509 dev->last_state_idx = state; in teo_reflect()
510 if (dev->poll_time_limit || in teo_reflect()
511 (tick_nohz_idle_got_tick() && cpu_data->sleep_length_ns > TICK_NSEC)) { in teo_reflect()
513 * The wakeup was not "genuine", but triggered by one of the in teo_reflect()
516 dev->poll_time_limit = false; in teo_reflect()
517 cpu_data->artificial_wakeup = true; in teo_reflect()
519 cpu_data->artificial_wakeup = false; in teo_reflect()
524 * teo_enable_device - Initialize the governor's data for the target CPU.
531 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_enable_device()