Skip to content

Commit 80606f4

Browse files
committed
cpuidle: governors: menu: Always check timers with tick stopped
After commit 5484e31 ("cpuidle: menu: Skip tick_nohz_get_sleep_length() call in some cases"), if the return value of get_typical_interval() multiplied by NSEC_PER_USEC is not greater than RESIDENCY_THRESHOLD_NS, the menu governor will skip computing the time till the closest timer. If that happens when the tick has been stopped already, the selected idle state may be too deep due to the subsequent check comparing predicted_ns with TICK_NSEC and causing its value to be replaced with the expected time till the closest timer, which is KTIME_MAX in that case. That will cause the deepest enabled idle state to be selected, but the time till the closest timer very well may be shorter than the target residency of that state, in which case a shallower state should be used. Address this by making menu_select() always compute the time till the closest timer when the tick has been stopped. Also move the predicted_ns check mentioned above into the branch in which the time till the closest timer is determined because it only needs to be done in that case. Fixes: 5484e31 ("cpuidle: menu: Skip tick_nohz_get_sleep_length() call in some cases") Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Christian Loehle <christian.loehle@arm.com> Link: https://patch.msgid.link/5959091.DvuYhMxLoT@rafael.j.wysocki
1 parent fd0d287 commit 80606f4

1 file changed

Lines changed: 11 additions & 11 deletions

File tree

  • drivers/cpuidle/governors

drivers/cpuidle/governors/menu.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
239239

240240
/* Find the shortest expected idle interval. */
241241
predicted_ns = get_typical_interval(data) * NSEC_PER_USEC;
242-
if (predicted_ns > RESIDENCY_THRESHOLD_NS) {
242+
if (predicted_ns > RESIDENCY_THRESHOLD_NS || tick_nohz_tick_stopped()) {
243243
unsigned int timer_us;
244244

245245
/* Determine the time till the closest timer. */
@@ -259,6 +259,16 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
259259
RESOLUTION * DECAY * NSEC_PER_USEC);
260260
/* Use the lowest expected idle interval to pick the idle state. */
261261
predicted_ns = min((u64)timer_us * NSEC_PER_USEC, predicted_ns);
262+
/*
263+
* If the tick is already stopped, the cost of possible short
264+
* idle duration misprediction is much higher, because the CPU
265+
* may be stuck in a shallow idle state for a long time as a
266+
* result of it. In that case, say we might mispredict and use
267+
* the known time till the closest timer event for the idle
268+
* state selection.
269+
*/
270+
if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC)
271+
predicted_ns = data->next_timer_ns;
262272
} else {
263273
/*
264274
* Because the next timer event is not going to be determined
@@ -284,16 +294,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
284294
return 0;
285295
}
286296

287-
/*
288-
* If the tick is already stopped, the cost of possible short idle
289-
* duration misprediction is much higher, because the CPU may be stuck
290-
* in a shallow idle state for a long time as a result of it. In that
291-
* case, say we might mispredict and use the known time till the closest
292-
* timer event for the idle state selection.
293-
*/
294-
if (tick_nohz_tick_stopped() && predicted_ns < TICK_NSEC)
295-
predicted_ns = data->next_timer_ns;
296-
297297
/*
298298
* Find the idle state with the lowest power while satisfying
299299
* our constraints.

0 commit comments

Comments
 (0)