Skip to content

Commit 8de7606

Browse files
committed
cpuidle: menu: Eliminate outliers on both ends of the sample set
Currently, get_typical_interval() attempts to eliminate outliers at the high end of the sample set only (probably in order to bias the prediction toward lower values), but this it problematic because if the outliers are present at the low end of the sample set, discarding the highest values will not help to reduce the variance. Since the presence of outliers at the low end of the sample set is generally as likely as their presence at the high end of the sample set, modify get_typical_interval() to treat samples at the largest distances from the average (on both ends of the sample set) as outliers. This should increase the likelihood of making a meaningful prediction in some cases. Signed-off-by: Rafael J. Wysocki <[email protected]> Reported-by: Artem Bityutskiy <[email protected]> Tested-by: Artem Bityutskiy <[email protected]> Reviewed-by: Christian Loehle <[email protected]> Tested-by: Christian Loehle <[email protected]> Tested-by: Aboorva Devarajan <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 60256e4 commit 8de7606

File tree

1 file changed

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

1 file changed

+22
-10
lines changed

drivers/cpuidle/governors/menu.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,30 +116,37 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
116116
*/
117117
static unsigned int get_typical_interval(struct menu_device *data)
118118
{
119-
unsigned int max, divisor, thresh = UINT_MAX;
119+
s64 value, min_thresh = -1, max_thresh = UINT_MAX;
120+
unsigned int max, min, divisor;
120121
u64 avg, variance, avg_sq;
121122
int i;
122123

123124
again:
124125
/* Compute the average and variance of past intervals. */
125126
max = 0;
127+
min = UINT_MAX;
126128
avg = 0;
127129
variance = 0;
128130
divisor = 0;
129131
for (i = 0; i < INTERVALS; i++) {
130-
unsigned int value = data->intervals[i];
131-
132-
/* Discard data points above or at the threshold. */
133-
if (value >= thresh)
132+
value = data->intervals[i];
133+
/*
134+
* Discard the samples outside the interval between the min and
135+
* max thresholds.
136+
*/
137+
if (value <= min_thresh || value >= max_thresh)
134138
continue;
135139

136140
divisor++;
137141

138142
avg += value;
139-
variance += (u64)value * value;
143+
variance += value * value;
140144

141145
if (value > max)
142146
max = value;
147+
148+
if (value < min)
149+
min = value;
143150
}
144151

145152
if (!max)
@@ -175,18 +182,23 @@ static unsigned int get_typical_interval(struct menu_device *data)
175182
}
176183

177184
/*
178-
* If we have outliers to the upside in our distribution, discard
179-
* those by setting the threshold to exclude these outliers, then
185+
* If there are outliers, discard them by setting thresholds to exclude
186+
* data points at a large enough distance from the average, then
180187
* calculate the average and standard deviation again. Once we get
181-
* down to the bottom 3/4 of our samples, stop excluding samples.
188+
* down to the last 3/4 of our samples, stop excluding samples.
182189
*
183190
* This can deal with workloads that have long pauses interspersed
184191
* with sporadic activity with a bunch of short pauses.
185192
*/
186193
if ((divisor * 4) <= INTERVALS * 3)
187194
return UINT_MAX;
188195

189-
thresh = max;
196+
/* Update the thresholds for the next round. */
197+
if (avg - min > max - avg)
198+
min_thresh = min;
199+
else
200+
max_thresh = max;
201+
190202
goto again;
191203
}
192204

0 commit comments

Comments
 (0)