aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/governors/menu.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index b81ad9c731ae..52ff8aa63f84 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -21,9 +21,12 @@
21#include <linux/math64.h> 21#include <linux/math64.h>
22 22
23#define BUCKETS 12 23#define BUCKETS 12
24#define INTERVALS 8
24#define RESOLUTION 1024 25#define RESOLUTION 1024
25#define DECAY 4 26#define DECAY 8
26#define MAX_INTERESTING 50000 27#define MAX_INTERESTING 50000
28#define STDDEV_THRESH 400
29
27 30
28/* 31/*
29 * Concepts and ideas behind the menu governor 32 * Concepts and ideas behind the menu governor
@@ -64,6 +67,16 @@
64 * indexed based on the magnitude of the expected duration as well as the 67 * indexed based on the magnitude of the expected duration as well as the
65 * "is IO outstanding" property. 68 * "is IO outstanding" property.
66 * 69 *
70 * Repeatable-interval-detector
71 * ----------------------------
72 * There are some cases where "next timer" is a completely unusable predictor:
73 * Those cases where the interval is fixed, for example due to hardware
74 * interrupt mitigation, but also due to fixed transfer rate devices such as
75 * mice.
76 * For this, we use a different predictor: We track the duration of the last 8
77 * intervals and if the stand deviation of these 8 intervals is below a
78 * threshold value, we use the average of these intervals as prediction.
79 *
67 * Limiting Performance Impact 80 * Limiting Performance Impact
68 * --------------------------- 81 * ---------------------------
69 * C states, especially those with large exit latencies, can have a real 82 * C states, especially those with large exit latencies, can have a real
@@ -104,6 +117,8 @@ struct menu_device {
104 unsigned int exit_us; 117 unsigned int exit_us;
105 unsigned int bucket; 118 unsigned int bucket;
106 u64 correction_factor[BUCKETS]; 119 u64 correction_factor[BUCKETS];
120 u32 intervals[INTERVALS];
121 int interval_ptr;
107}; 122};
108 123
109 124
@@ -175,6 +190,42 @@ static u64 div_round64(u64 dividend, u32 divisor)
175 return div_u64(dividend + (divisor / 2), divisor); 190 return div_u64(dividend + (divisor / 2), divisor);
176} 191}
177 192
193/*
194 * Try detecting repeating patterns by keeping track of the last 8
195 * intervals, and checking if the standard deviation of that set
196 * of points is below a threshold. If it is... then use the
197 * average of these 8 points as the estimated value.
198 */
199static void detect_repeating_patterns(struct menu_device *data)
200{
201 int i;
202 uint64_t avg = 0;
203 uint64_t stddev = 0; /* contains the square of the std deviation */
204
205 /* first calculate average and standard deviation of the past */
206 for (i = 0; i < INTERVALS; i++)
207 avg += data->intervals[i];
208 avg = avg / INTERVALS;
209
210 /* if the avg is beyond the known next tick, it's worthless */
211 if (avg > data->expected_us)
212 return;
213
214 for (i = 0; i < INTERVALS; i++)
215 stddev += (data->intervals[i] - avg) *
216 (data->intervals[i] - avg);
217
218 stddev = stddev / INTERVALS;
219
220 /*
221 * now.. if stddev is small.. then assume we have a
222 * repeating pattern and predict we keep doing this.
223 */
224
225 if (avg && stddev < STDDEV_THRESH)
226 data->predicted_us = avg;
227}
228
178/** 229/**
179 * menu_select - selects the next idle state to enter 230 * menu_select - selects the next idle state to enter
180 * @dev: the CPU 231 * @dev: the CPU
@@ -218,6 +269,8 @@ static int menu_select(struct cpuidle_device *dev)
218 data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], 269 data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
219 RESOLUTION * DECAY); 270 RESOLUTION * DECAY);
220 271
272 detect_repeating_patterns(data);
273
221 /* 274 /*
222 * We want to default to C1 (hlt), not to busy polling 275 * We want to default to C1 (hlt), not to busy polling
223 * unless the timer is happening really really soon. 276 * unless the timer is happening really really soon.
@@ -310,6 +363,11 @@ static void menu_update(struct cpuidle_device *dev)
310 new_factor = 1; 363 new_factor = 1;
311 364
312 data->correction_factor[data->bucket] = new_factor; 365 data->correction_factor[data->bucket] = new_factor;
366
367 /* update the repeating-pattern data */
368 data->intervals[data->interval_ptr++] = last_idle_us;
369 if (data->interval_ptr >= INTERVALS)
370 data->interval_ptr = 0;
313} 371}
314 372
315/** 373/**