UPSTREAM: 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. Bug: 254441685 Fixes: 9ce0f7c4bc64 ("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> (cherry picked from commit 3f0b0966b30982e843950b170b7a9ddfd8094428) Signed-off-by: Lee Jones <joneslee@google.com> Change-Id: I4f944d1b825f721dae7c406c73bac2a683d94cd6
This commit is contained in:
parent
d8e99e1af8
commit
ed6694a682
@ -410,14 +410,24 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|||||||
* the shallowest non-polling state and exit.
|
* the shallowest non-polling state and exit.
|
||||||
*/
|
*/
|
||||||
if (drv->state_count < 3 && cpu_data->utilized) {
|
if (drv->state_count < 3 && cpu_data->utilized) {
|
||||||
for (i = 0; i < drv->state_count; ++i) {
|
/* The CPU is utilized, so assume a short idle duration. */
|
||||||
if (!dev->states_usage[i].disable &&
|
duration_ns = teo_middle_of_bin(0, drv);
|
||||||
!(drv->states[i].flags & CPUIDLE_FLAG_POLLING)) {
|
/*
|
||||||
idx = i;
|
* If state 0 is enabled and it is not a polling one, select it
|
||||||
|
* right away unless the scheduler tick has been stopped, in
|
||||||
|
* which case care needs to be taken to leave the CPU in a deep
|
||||||
|
* enough state in case it is not woken up any time soon after
|
||||||
|
* all. If state 1 is disabled, though, state 0 must be used
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
|
if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
|
||||||
|
teo_time_ok(duration_ns)) || dev->states_usage[1].disable)
|
||||||
|
idx = 0;
|
||||||
|
else /* Assume that state 1 is not a polling one and use it. */
|
||||||
|
idx = 1;
|
||||||
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the deepest idle state whose target residency does not exceed
|
* Find the deepest idle state whose target residency does not exceed
|
||||||
@ -552,10 +562,20 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the CPU is being utilized over the threshold, choose a shallower
|
* If the CPU is being utilized over the threshold, choose a shallower
|
||||||
* non-polling state to improve latency
|
* non-polling state to improve latency, unless the scheduler tick has
|
||||||
|
* been stopped already and the shallower state's target residency is
|
||||||
|
* not sufficiently large.
|
||||||
*/
|
*/
|
||||||
if (cpu_data->utilized)
|
if (cpu_data->utilized) {
|
||||||
idx = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
|
s64 span_ns;
|
||||||
|
|
||||||
|
i = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
|
||||||
|
span_ns = teo_middle_of_bin(i, drv);
|
||||||
|
if (teo_time_ok(span_ns)) {
|
||||||
|
idx = i;
|
||||||
|
duration_ns = span_ns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user