Skip to content

Commit a971f98

Browse files
committed
cpuidle: governors: teo: Refine intercepts-based idle state lookup
There are cases in which decisions made by the teo governor are arguably overly conservative. For instance, suppose that there are 4 idle states and the values of the intercepts metric for the first 3 of them are 400, 250, and 251, respectively. If the total sum computed in teo_update() is 1000, the governor will select idle state 1 (provided that all idle states are enabled and the scheduler tick has not been stopped) although arguably idle state 0 would be a better choice because the likelihood of getting an idle duration below the target residency of idle state 1 is greater than the likelihood of getting an idle duration between the target residency of idle state 1 and the target residency of idle state 2. To address this, refine the candidate idle state lookup based on intercepts to start at the state with the maximum intercepts metric, below the deepest enabled one, to avoid the cases in which the search may stop before reaching that state. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Christian Loehle <christian.loehle@arm.com> [ rjw: Fixed typo "intercetps" in new comments (3 places) ] Link: https://patch.msgid.link/2417298.ElGaqSPkdT@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent f36de72 commit a971f98

1 file changed

Lines changed: 43 additions & 7 deletions

File tree

  • drivers/cpuidle/governors

drivers/cpuidle/governors/teo.c

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,17 @@
7474
* than the candidate one (it represents the cases in which the CPU was
7575
* likely woken up by a non-timer wakeup source).
7676
*
77+
* Also find the idle state with the maximum intercepts metric (if there are
78+
* multiple states with the maximum intercepts metric, choose the one with
79+
* the highest index).
80+
*
7781
* 2. If the second sum computed in step 1 is greater than a half of the sum of
7882
* both metrics for the candidate state bin and all subsequent bins (if any),
7983
* a shallower idle state is likely to be more suitable, so look for it.
8084
*
8185
* - Traverse the enabled idle states shallower than the candidate one in the
82-
* descending order.
86+
* descending order, starting at the state with the maximum intercepts
87+
* metric found in step 1.
8388
*
8489
* - For each of them compute the sum of the "intercepts" metrics over all
8590
* of the idle states between it and the candidate one (including the
@@ -308,8 +313,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
308313
ktime_t delta_tick = TICK_NSEC / 2;
309314
unsigned int idx_intercept_sum = 0;
310315
unsigned int intercept_sum = 0;
316+
unsigned int intercept_max = 0;
311317
unsigned int idx_hit_sum = 0;
312318
unsigned int hit_sum = 0;
319+
int intercept_max_idx = -1;
313320
int constraint_idx = 0;
314321
int idx0 = 0, idx = -1;
315322
s64 duration_ns;
@@ -340,17 +347,32 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
340347
if (!dev->states_usage[0].disable)
341348
idx = 0;
342349

343-
/* Compute the sums of metrics for early wakeup pattern detection. */
350+
/*
351+
* Compute the sums of metrics for early wakeup pattern detection and
352+
* look for the state bin with the maximum intercepts metric below the
353+
* deepest enabled one (if there are multiple states with the maximum
354+
* intercepts metric, choose the one with the highest index).
355+
*/
344356
for (i = 1; i < drv->state_count; i++) {
345357
struct teo_bin *prev_bin = &cpu_data->state_bins[i-1];
358+
unsigned int prev_intercepts = prev_bin->intercepts;
346359
struct cpuidle_state *s = &drv->states[i];
347360

348361
/*
349362
* Update the sums of idle state metrics for all of the states
350363
* shallower than the current one.
351364
*/
352-
intercept_sum += prev_bin->intercepts;
353365
hit_sum += prev_bin->hits;
366+
intercept_sum += prev_intercepts;
367+
/*
368+
* Check if this is the bin with the maximum number of
369+
* intercepts so far and in that case update the index of
370+
* the state with the maximum intercepts metric.
371+
*/
372+
if (prev_intercepts >= intercept_max) {
373+
intercept_max = prev_intercepts;
374+
intercept_max_idx = i - 1;
375+
}
354376

355377
if (dev->states_usage[i].disable)
356378
continue;
@@ -414,9 +436,22 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
414436
}
415437

416438
/*
417-
* Look for the deepest idle state whose target residency had
418-
* not exceeded the idle duration in over a half of the relevant
419-
* cases in the past.
439+
* If the minimum state index is greater than or equal to the
440+
* index of the state with the maximum intercepts metric and
441+
* the corresponding state is enabled, there is no need to look
442+
* at the deeper states.
443+
*/
444+
if (min_idx >= intercept_max_idx &&
445+
!dev->states_usage[min_idx].disable) {
446+
idx = min_idx;
447+
goto constraint;
448+
}
449+
450+
/*
451+
* Look for the deepest enabled idle state, at most as deep as
452+
* the one with the maximum intercepts metric, whose target
453+
* residency had not been greater than the idle duration in over
454+
* a half of the relevant cases in the past.
420455
*
421456
* Take the possible duration limitation present if the tick
422457
* has been stopped already into account.
@@ -428,7 +463,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
428463
continue;
429464

430465
idx = i;
431-
if (2 * intercept_sum > idx_intercept_sum)
466+
if (2 * intercept_sum > idx_intercept_sum &&
467+
i <= intercept_max_idx)
432468
break;
433469
}
434470
}

0 commit comments

Comments
 (0)