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
22 * Of course, non-timer wakeup sources are more important in some use cases
49 * sleep length and the idle duration measured after CPU wakeup fall into the
62 * steps (modulo the possible latency constraint that must be taken into account
69 * - The sum of the "hits" and "intercepts" metrics for the candidate state
74 * - The sum of the "intercepts" metrics for all of the idle states shallower
79 * - The sum of the numbers of recent intercepts for all of the idle states
86 * - Traverse the idle states shallower than the candidate one in the
89 * - For each of them compute the sum of the "intercepts" metrics and the sum
94 * - If each of these sums that needs to be taken into account (because the
119 * the detection of recent early wakeup patterns.
124 * struct teo_bin - Metrics used by the TEO cpuidle governor.
136 * struct teo_cpu - CPU data used by the TEO cpuidle governor.
137 * @time_span_ns: Time between idle state selection and post-wakeup update.
156 * teo_update - Update CPU metrics after wakeup.
162 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_update()
166 if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { in teo_update()
168 * One of the safety nets has triggered or the wakeup was close in teo_update()
174 u64 lat_ns = drv->states[dev->last_state_idx].exit_latency_ns; in teo_update()
183 measured_ns = dev->last_residency_ns; in teo_update()
185 * The delay between the wakeup and the first instruction in teo_update()
186 * executed by the CPU is not likely to be worst-case every in teo_update()
187 * time, so take 1/2 of the exit latency as a very rough in teo_update()
191 measured_ns -= lat_ns / 2; in teo_update()
196 cpu_data->total = 0; in teo_update()
203 for (i = 0; i < drv->state_count; i++) { in teo_update()
204 s64 target_residency_ns = drv->states[i].target_residency_ns; in teo_update()
205 struct teo_bin *bin = &cpu_data->state_bins[i]; in teo_update()
207 bin->hits -= bin->hits >> DECAY_SHIFT; in teo_update()
208 bin->intercepts -= bin->intercepts >> DECAY_SHIFT; in teo_update()
210 cpu_data->total += bin->hits + bin->intercepts; in teo_update()
212 if (target_residency_ns <= cpu_data->sleep_length_ns) { in teo_update()
219 i = cpu_data->next_recent_idx++; in teo_update()
220 if (cpu_data->next_recent_idx >= NR_RECENT) in teo_update()
221 cpu_data->next_recent_idx = 0; in teo_update()
223 if (cpu_data->recent_idx[i] >= 0) in teo_update()
224 cpu_data->state_bins[cpu_data->recent_idx[i]].recent--; in teo_update()
233 cpu_data->state_bins[idx_timer].hits += PULSE; in teo_update()
234 cpu_data->recent_idx[i] = -1; in teo_update()
236 cpu_data->state_bins[idx_duration].intercepts += PULSE; in teo_update()
237 cpu_data->state_bins[idx_duration].recent++; in teo_update()
238 cpu_data->recent_idx[i] = idx_duration; in teo_update()
241 cpu_data->total += PULSE; in teo_update()
251 return (drv->states[idx].target_residency_ns + in teo_middle_of_bin()
252 drv->states[idx+1].target_residency_ns) / 2; in teo_middle_of_bin()
256 * teo_find_shallower_state - Find shallower idle state matching given duration.
268 for (i = state_idx - 1; i >= 0; i--) { in teo_find_shallower_state()
269 if (dev->states_usage[i].disable) in teo_find_shallower_state()
273 if (drv->states[i].target_residency_ns <= duration_ns) in teo_find_shallower_state()
280 * teo_select - Selects the next idle state to enter.
288 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_select()
289 s64 latency_req = cpuidle_governor_latency_req(dev->cpu); in teo_select()
297 int idx0 = 0, idx = -1; in teo_select()
303 if (dev->last_state_idx >= 0) { in teo_select()
305 dev->last_state_idx = -1; in teo_select()
308 cpu_data->time_span_ns = local_clock(); in teo_select()
311 cpu_data->sleep_length_ns = duration_ns; in teo_select()
314 if (drv->state_count < 2) { in teo_select()
318 if (!dev->states_usage[0].disable) { in teo_select()
320 if (drv->states[1].target_residency_ns > duration_ns) in teo_select()
327 * the former whose exit latency does not exceed the current latency in teo_select()
328 * constraint. Compute the sums of metrics for early wakeup pattern in teo_select()
331 for (i = 1; i < drv->state_count; i++) { in teo_select()
332 struct teo_bin *prev_bin = &cpu_data->state_bins[i-1]; in teo_select()
333 struct cpuidle_state *s = &drv->states[i]; in teo_select()
339 intercept_sum += prev_bin->intercepts; in teo_select()
340 hit_sum += prev_bin->hits; in teo_select()
341 recent_sum += prev_bin->recent; in teo_select()
343 if (dev->states_usage[i].disable) in teo_select()
351 if (s->target_residency_ns > duration_ns) in teo_select()
356 if (s->exit_latency_ns <= latency_req) in teo_select()
382 alt_intercepts = 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum; in teo_select()
394 * Take the possible latency constraint and duration limitation in teo_select()
400 for (i = idx - 1; i >= 0; i--) { in teo_select()
401 struct teo_bin *bin = &cpu_data->state_bins[i]; in teo_select()
404 intercept_sum += bin->intercepts; in teo_select()
405 recent_sum += bin->recent; in teo_select()
413 !dev->states_usage[i].disable) { in teo_select()
428 if (dev->states_usage[i].disable) in teo_select()
449 * If there is a latency constraint, it may be necessary to select an in teo_select()
460 if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) || in teo_select()
471 drv->states[idx].target_residency_ns > delta_tick) in teo_select()
479 * teo_reflect - Note that governor data for the CPU need to be updated.
485 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_reflect()
487 dev->last_state_idx = state; in teo_reflect()
489 * If the wakeup was not "natural", but triggered by one of the safety in teo_reflect()
493 if (dev->poll_time_limit || in teo_reflect()
494 (tick_nohz_idle_got_tick() && cpu_data->sleep_length_ns > TICK_NSEC)) { in teo_reflect()
495 dev->poll_time_limit = false; in teo_reflect()
496 cpu_data->time_span_ns = cpu_data->sleep_length_ns; in teo_reflect()
498 cpu_data->time_span_ns = local_clock() - cpu_data->time_span_ns; in teo_reflect()
503 * teo_enable_device - Initialize the governor's data for the target CPU.
510 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_enable_device()
516 cpu_data->recent_idx[i] = -1; in teo_enable_device()