Skip to content

Commit 3f0b096

Browse files
committed
cpuidle: teo: Update idle duration estimate when choosing shallower state
The TEO governor takes CPU utilization into account by refining idle state selection when the utilization is above a certain threshold. This is done by choosing an idle state shallower than the previously selected one. However, when doing this, the idle duration estimate needs to be adjusted so as to prevent the scheduler tick from being stopped when the candidate idle state is shallow, which may lead to excessive energy usage if the CPU is not woken up quickly enough going forward. Moreover, if the scheduler tick has been stopped already and the new idle duration estimate is too small, the replacement candidate state cannot be used. Modify the relevant code to take the above observations into account. Fixes: 9ce0f7c ("cpuidle: teo: Introduce util-awareness") Link: https://lore.kernel.org/linux-pm/CAJZ5v0jJxHj65r2HXBTd3wfbZtsg=_StzwO1kA5STDnaPe_dWA@mail.gmail.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-and-tested-by: Kajetan Puchalski <kajetan.puchalski@arm.com>
1 parent 5d0c230 commit 3f0b096

File tree

1 file changed

+30
-10
lines changed
  • drivers/cpuidle/governors

1 file changed

+30
-10
lines changed

drivers/cpuidle/governors/teo.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -397,13 +397,23 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
397397
* the shallowest non-polling state and exit.
398398
*/
399399
if (drv->state_count < 3 && cpu_data->utilized) {
400-
for (i = 0; i < drv->state_count; ++i) {
401-
if (!dev->states_usage[i].disable &&
402-
!(drv->states[i].flags & CPUIDLE_FLAG_POLLING)) {
403-
idx = i;
404-
goto end;
405-
}
406-
}
400+
/* The CPU is utilized, so assume a short idle duration. */
401+
duration_ns = teo_middle_of_bin(0, drv);
402+
/*
403+
* If state 0 is enabled and it is not a polling one, select it
404+
* right away unless the scheduler tick has been stopped, in
405+
* which case care needs to be taken to leave the CPU in a deep
406+
* enough state in case it is not woken up any time soon after
407+
* all. If state 1 is disabled, though, state 0 must be used
408+
* anyway.
409+
*/
410+
if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
411+
teo_time_ok(duration_ns)) || dev->states_usage[1].disable)
412+
idx = 0;
413+
else /* Assume that state 1 is not a polling one and use it. */
414+
idx = 1;
415+
416+
goto end;
407417
}
408418

409419
/*
@@ -539,10 +549,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
539549

540550
/*
541551
* If the CPU is being utilized over the threshold, choose a shallower
542-
* non-polling state to improve latency
552+
* non-polling state to improve latency, unless the scheduler tick has
553+
* been stopped already and the shallower state's target residency is
554+
* not sufficiently large.
543555
*/
544-
if (cpu_data->utilized)
545-
idx = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
556+
if (cpu_data->utilized) {
557+
s64 span_ns;
558+
559+
i = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
560+
span_ns = teo_middle_of_bin(i, drv);
561+
if (teo_time_ok(span_ns)) {
562+
idx = i;
563+
duration_ns = span_ns;
564+
}
565+
}
546566

547567
end:
548568
/*

0 commit comments

Comments
 (0)