Lines Matching +full:drv +full:- +full:2
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
39 * idle state 2, the third bin spans from the target residency of idle state 2
62 * the current sleep length (the candidate idle state) and compute 2 sums as
65 * - The sum of the "hits" and "intercepts" metrics for the candidate state
70 * - The sum of the "intercepts" metrics for all of the idle states shallower
75 * 2. If the second sum is greater than the first one the CPU is likely to wake
78 * - Traverse the idle states shallower than the candidate one in the
81 * - For each of them compute the sum of the "intercepts" metrics over all
85 * - If each of these sums that needs to be taken into account (because the
111 * struct teo_bin - Metrics used by the TEO cpuidle governor.
121 * struct teo_cpu - CPU data used by the TEO cpuidle governor.
122 * @time_span_ns: Time between idle state selection and post-wakeup update.
139 * teo_update - Update CPU metrics after wakeup.
140 * @drv: cpuidle driver containing state data.
143 static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) in teo_update() argument
145 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_update()
150 if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) { in teo_update()
158 u64 lat_ns = drv->states[dev->last_state_idx].exit_latency_ns; in teo_update()
167 measured_ns = dev->last_residency_ns; in teo_update()
170 * executed by the CPU is not likely to be worst-case every in teo_update()
171 * time, so take 1/2 of the exit latency as a very rough in teo_update()
175 measured_ns -= lat_ns / 2; in teo_update()
177 measured_ns /= 2; in teo_update()
180 cpu_data->total = 0; in teo_update()
187 for (i = 0; i < drv->state_count; i++) { in teo_update()
188 struct teo_bin *bin = &cpu_data->state_bins[i]; in teo_update()
190 bin->hits -= bin->hits >> DECAY_SHIFT; in teo_update()
191 bin->intercepts -= bin->intercepts >> DECAY_SHIFT; in teo_update()
193 cpu_data->total += bin->hits + bin->intercepts; in teo_update()
195 target_residency_ns = drv->states[i].target_residency_ns; in teo_update()
197 if (target_residency_ns <= cpu_data->sleep_length_ns) { in teo_update()
207 * to stop the tick. This effectively adds an extra hits-only bin in teo_update()
208 * beyond the last state-related one. in teo_update()
211 cpu_data->tick_hits -= cpu_data->tick_hits >> DECAY_SHIFT; in teo_update()
213 cpu_data->total += cpu_data->tick_hits; in teo_update()
215 if (TICK_NSEC <= cpu_data->sleep_length_ns) { in teo_update()
216 idx_timer = drv->state_count; in teo_update()
218 cpu_data->tick_hits += PULSE; in teo_update()
231 cpu_data->state_bins[idx_timer].hits += PULSE; in teo_update()
233 cpu_data->state_bins[idx_duration].intercepts += PULSE; in teo_update()
236 cpu_data->total += PULSE; in teo_update()
239 static bool teo_state_ok(int i, struct cpuidle_driver *drv) in teo_state_ok() argument
242 drv->states[i].target_residency_ns >= TICK_NSEC; in teo_state_ok()
246 * teo_find_shallower_state - Find shallower idle state matching given duration.
247 * @drv: cpuidle driver containing state data.
253 static int teo_find_shallower_state(struct cpuidle_driver *drv, in teo_find_shallower_state() argument
259 for (i = state_idx - 1; i >= 0; i--) { in teo_find_shallower_state()
260 if (dev->states_usage[i].disable || in teo_find_shallower_state()
261 (no_poll && drv->states[i].flags & CPUIDLE_FLAG_POLLING)) in teo_find_shallower_state()
265 if (drv->states[i].target_residency_ns <= duration_ns) in teo_find_shallower_state()
272 * teo_select - Selects the next idle state to enter.
273 * @drv: cpuidle driver containing state data.
277 static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, in teo_select() argument
280 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_select()
281 s64 latency_req = cpuidle_governor_latency_req(dev->cpu); in teo_select()
282 ktime_t delta_tick = TICK_NSEC / 2; in teo_select()
289 int idx0 = 0, idx = -1; in teo_select()
294 if (dev->last_state_idx >= 0) { in teo_select()
295 teo_update(drv, dev); in teo_select()
296 dev->last_state_idx = -1; in teo_select()
299 cpu_data->time_span_ns = local_clock(); in teo_select()
304 cpu_data->sleep_length_ns = KTIME_MAX; in teo_select()
307 if (drv->state_count < 2) { in teo_select()
312 if (!dev->states_usage[0].disable) in teo_select()
316 for (i = 1; i < drv->state_count; i++) { in teo_select()
317 struct teo_bin *prev_bin = &cpu_data->state_bins[i-1]; in teo_select()
318 struct cpuidle_state *s = &drv->states[i]; in teo_select()
324 intercept_sum += prev_bin->intercepts; in teo_select()
325 hit_sum += prev_bin->hits; in teo_select()
327 if (dev->states_usage[i].disable) in teo_select()
335 if (s->exit_latency_ns <= latency_req) in teo_select()
354 duration_ns = drv->states[idx].target_residency_ns; in teo_select()
359 cpu_data->state_bins[drv->state_count-1].intercepts; in teo_select()
369 if (2 * idx_intercept_sum > cpu_data->total - idx_hit_sum) { in teo_select()
382 for (i = idx - 1; i >= 0; i--) { in teo_select()
383 struct teo_bin *bin = &cpu_data->state_bins[i]; in teo_select()
385 intercept_sum += bin->intercepts; in teo_select()
387 if (2 * intercept_sum > idx_intercept_sum) { in teo_select()
393 if (teo_state_ok(i, drv) && in teo_select()
394 !dev->states_usage[i].disable) in teo_select()
402 if (dev->states_usage[i].disable) in teo_select()
405 if (!teo_state_ok(i, drv)) { in teo_select()
426 cpu_data->sleep_length_ns = duration_ns; in teo_select()
439 * because an immediate non-timer wakeup is expected in that case. in teo_select()
449 if ((drv->states[0].flags & CPUIDLE_FLAG_POLLING) && in teo_select()
450 drv->states[idx].target_residency_ns < RESIDENCY_THRESHOLD_NS) in teo_select()
454 cpu_data->sleep_length_ns = duration_ns; in teo_select()
460 if (drv->states[idx].target_residency_ns > duration_ns) { in teo_select()
461 i = teo_find_shallower_state(drv, dev, idx, duration_ns, false); in teo_select()
462 if (teo_state_ok(i, drv)) in teo_select()
471 if (drv->states[idx].target_residency_ns < TICK_NSEC && in teo_select()
472 tick_intercept_sum > cpu_data->total / 2 + cpu_data->total / 8) in teo_select()
473 duration_ns = TICK_NSEC / 2; in teo_select()
481 if ((!(drv->states[idx].flags & CPUIDLE_FLAG_POLLING) && in teo_select()
491 drv->states[idx].target_residency_ns > delta_tick) in teo_select()
492 idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false); in teo_select()
500 * teo_reflect - Note that governor data for the CPU need to be updated.
506 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_reflect()
508 dev->last_state_idx = state; in teo_reflect()
514 if (dev->poll_time_limit || in teo_reflect()
515 (tick_nohz_idle_got_tick() && cpu_data->sleep_length_ns > TICK_NSEC)) { in teo_reflect()
516 dev->poll_time_limit = false; in teo_reflect()
517 cpu_data->time_span_ns = cpu_data->sleep_length_ns; in teo_reflect()
519 cpu_data->time_span_ns = local_clock() - cpu_data->time_span_ns; in teo_reflect()
524 * teo_enable_device - Initialize the governor's data for the target CPU.
525 * @drv: cpuidle driver (not used).
528 static int teo_enable_device(struct cpuidle_driver *drv, in teo_enable_device() argument
531 struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); in teo_enable_device()