Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 4499143

Browse files
cloehlerafaeljw
authored andcommitted
cpuidle: teo: Remove recent intercepts metric
The logic for recent intercepts didn't work, there is an underflow of the 'recent' value that can be observed during boot already, which teo usually doesn't recover from, making the entire logic pointless. Furthermore the recent intercepts also were never reset, thus not actually being very 'recent'. Having underflowed 'recent' values lead to teo always acting as if we were in a scenario were expected sleep length based on timers is too high and it therefore unnecessarily selecting shallower states. Experiments show that the remaining 'intercept' logic is enough to quickly react to scenarios in which teo cannot rely on the timer expected sleep length. See also here: https://lore.kernel.org/lkml/0ce2d536-1125-4df8-9a5b-0d5e389cd8af@arm.com/ Fixes: 7757755 ("cpuidle: teo: Rework most recent idle duration values treatment") Link: https://patch.msgid.link/20240628095955.34096-3-christian.loehle@arm.com Signed-off-by: Christian Loehle <christian.loehle@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 0a2998f commit 4499143

File tree

1 file changed

+13
-63
lines changed
  • drivers/cpuidle/governors

1 file changed

+13
-63
lines changed

drivers/cpuidle/governors/teo.c

Lines changed: 13 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,12 @@
5454
* shallower than the one whose bin is fallen into by the sleep length (these
5555
* situations are referred to as "intercepts" below).
5656
*
57-
* In addition to the metrics described above, the governor counts recent
58-
* intercepts (that is, intercepts that have occurred during the last
59-
* %NR_RECENT invocations of it for the given CPU) for each bin.
60-
*
6157
* In order to select an idle state for a CPU, the governor takes the following
6258
* steps (modulo the possible latency constraint that must be taken into account
6359
* too):
6460
*
6561
* 1. Find the deepest CPU idle state whose target residency does not exceed
66-
* the current sleep length (the candidate idle state) and compute 3 sums as
62+
* the current sleep length (the candidate idle state) and compute 2 sums as
6763
* follows:
6864
*
6965
* - The sum of the "hits" and "intercepts" metrics for the candidate state
@@ -76,20 +72,15 @@
7672
* idle long enough to avoid being intercepted if the sleep length had been
7773
* equal to the current one).
7874
*
79-
* - The sum of the numbers of recent intercepts for all of the idle states
80-
* shallower than the candidate one.
81-
*
82-
* 2. If the second sum is greater than the first one or the third sum is
83-
* greater than %NR_RECENT / 2, the CPU is likely to wake up early, so look
84-
* for an alternative idle state to select.
75+
* 2. If the second sum is greater than the first one the CPU is likely to wake
76+
* up early, so look for an alternative idle state to select.
8577
*
8678
* - Traverse the idle states shallower than the candidate one in the
8779
* descending order.
8880
*
89-
* - For each of them compute the sum of the "intercepts" metrics and the sum
90-
* of the numbers of recent intercepts over all of the idle states between
91-
* it and the candidate one (including the former and excluding the
92-
* latter).
81+
* - For each of them compute the sum of the "intercepts" metrics over all
82+
* of the idle states between it and the candidate one (including the
83+
* former and excluding the latter).
9384
*
9485
* - If each of these sums that needs to be taken into account (because the
9586
* check related to it has indicated that the CPU is likely to wake up
@@ -116,22 +107,14 @@
116107
#define PULSE 1024
117108
#define DECAY_SHIFT 3
118109

119-
/*
120-
* Number of the most recent idle duration values to take into consideration for
121-
* the detection of recent early wakeup patterns.
122-
*/
123-
#define NR_RECENT 9
124-
125110
/**
126111
* struct teo_bin - Metrics used by the TEO cpuidle governor.
127112
* @intercepts: The "intercepts" metric.
128113
* @hits: The "hits" metric.
129-
* @recent: The number of recent "intercepts".
130114
*/
131115
struct teo_bin {
132116
unsigned int intercepts;
133117
unsigned int hits;
134-
unsigned int recent;
135118
};
136119

137120
/**
@@ -140,17 +123,13 @@ struct teo_bin {
140123
* @sleep_length_ns: Time till the closest timer event (at the selection time).
141124
* @state_bins: Idle state data bins for this CPU.
142125
* @total: Grand total of the "intercepts" and "hits" metrics for all bins.
143-
* @next_recent_idx: Index of the next @recent_idx entry to update.
144-
* @recent_idx: Indices of bins corresponding to recent "intercepts".
145126
* @tick_hits: Number of "hits" after TICK_NSEC.
146127
*/
147128
struct teo_cpu {
148129
s64 time_span_ns;
149130
s64 sleep_length_ns;
150131
struct teo_bin state_bins[CPUIDLE_STATE_MAX];
151132
unsigned int total;
152-
int next_recent_idx;
153-
int recent_idx[NR_RECENT];
154133
unsigned int tick_hits;
155134
};
156135

@@ -222,13 +201,6 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
222201
}
223202
}
224203

225-
i = cpu_data->next_recent_idx++;
226-
if (cpu_data->next_recent_idx >= NR_RECENT)
227-
cpu_data->next_recent_idx = 0;
228-
229-
if (cpu_data->recent_idx[i] >= 0)
230-
cpu_data->state_bins[cpu_data->recent_idx[i]].recent--;
231-
232204
/*
233205
* If the deepest state's target residency is below the tick length,
234206
* make a record of it to help teo_select() decide whether or not
@@ -255,14 +227,10 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
255227
* Otherwise, update the "intercepts" metric for the bin fallen into by
256228
* the measured idle duration.
257229
*/
258-
if (idx_timer == idx_duration) {
230+
if (idx_timer == idx_duration)
259231
cpu_data->state_bins[idx_timer].hits += PULSE;
260-
cpu_data->recent_idx[i] = -1;
261-
} else {
232+
else
262233
cpu_data->state_bins[idx_duration].intercepts += PULSE;
263-
cpu_data->state_bins[idx_duration].recent++;
264-
cpu_data->recent_idx[i] = idx_duration;
265-
}
266234

267235
end:
268236
cpu_data->total += PULSE;
@@ -315,13 +283,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
315283
unsigned int tick_intercept_sum = 0;
316284
unsigned int idx_intercept_sum = 0;
317285
unsigned int intercept_sum = 0;
318-
unsigned int idx_recent_sum = 0;
319-
unsigned int recent_sum = 0;
320286
unsigned int idx_hit_sum = 0;
321287
unsigned int hit_sum = 0;
322288
int constraint_idx = 0;
323289
int idx0 = 0, idx = -1;
324-
bool alt_intercepts, alt_recent;
325290
s64 duration_ns;
326291
int i;
327292

@@ -357,7 +322,6 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
357322
*/
358323
intercept_sum += prev_bin->intercepts;
359324
hit_sum += prev_bin->hits;
360-
recent_sum += prev_bin->recent;
361325

362326
if (dev->states_usage[i].disable)
363327
continue;
@@ -373,7 +337,6 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
373337
/* Save the sums for the current state. */
374338
idx_intercept_sum = intercept_sum;
375339
idx_hit_sum = hit_sum;
376-
idx_recent_sum = recent_sum;
377340
}
378341

379342
/* Avoid unnecessary overhead. */
@@ -398,37 +361,28 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
398361
* If the sum of the intercepts metric for all of the idle states
399362
* shallower than the current candidate one (idx) is greater than the
400363
* sum of the intercepts and hits metrics for the candidate state and
401-
* all of the deeper states, or the sum of the numbers of recent
402-
* intercepts over all of the states shallower than the candidate one
403-
* is greater than a half of the number of recent events taken into
404-
* account, a shallower idle state is likely to be a better choice.
364+
* all of the deeper states a shallower idle state is likely to be a
365+
* better choice.
405366
*/
406-
alt_intercepts = 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum;
407-
alt_recent = idx_recent_sum > NR_RECENT / 2;
408-
if (alt_recent || alt_intercepts) {
367+
if (2 * idx_intercept_sum > cpu_data->total - idx_hit_sum) {
409368
int first_suitable_idx = idx;
410369

411370
/*
412371
* Look for the deepest idle state whose target residency had
413372
* not exceeded the idle duration in over a half of the relevant
414-
* cases (both with respect to intercepts overall and with
415-
* respect to the recent intercepts only) in the past.
373+
* cases in the past.
416374
*
417375
* Take the possible duration limitation present if the tick
418376
* has been stopped already into account.
419377
*/
420378
intercept_sum = 0;
421-
recent_sum = 0;
422379

423380
for (i = idx - 1; i >= 0; i--) {
424381
struct teo_bin *bin = &cpu_data->state_bins[i];
425382

426383
intercept_sum += bin->intercepts;
427-
recent_sum += bin->recent;
428384

429-
if ((!alt_recent || 2 * recent_sum > idx_recent_sum) &&
430-
(!alt_intercepts ||
431-
2 * intercept_sum > idx_intercept_sum)) {
385+
if (2 * intercept_sum > idx_intercept_sum) {
432386
/*
433387
* Use the current state unless it is too
434388
* shallow or disabled, in which case take the
@@ -564,13 +518,9 @@ static int teo_enable_device(struct cpuidle_driver *drv,
564518
struct cpuidle_device *dev)
565519
{
566520
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
567-
int i;
568521

569522
memset(cpu_data, 0, sizeof(*cpu_data));
570523

571-
for (i = 0; i < NR_RECENT; i++)
572-
cpu_data->recent_idx[i] = -1;
573-
574524
return 0;
575525
}
576526

0 commit comments

Comments
 (0)