diff options
Diffstat (limited to 'drivers/cpuidle/governors/menu.c')
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 108 |
1 files changed, 66 insertions, 42 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index bc580b67a652..cf7f2f0e4ef5 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c | |||
@@ -21,6 +21,15 @@ | |||
21 | #include <linux/math64.h> | 21 | #include <linux/math64.h> |
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | 23 | ||
24 | /* | ||
25 | * Please note when changing the tuning values: | ||
26 | * If (MAX_INTERESTING-1) * RESOLUTION > UINT_MAX, the result of | ||
27 | * a scaling operation multiplication may overflow on 32 bit platforms. | ||
28 | * In that case, #define RESOLUTION as ULL to get 64 bit result: | ||
29 | * #define RESOLUTION 1024ULL | ||
30 | * | ||
31 | * The default values do not overflow. | ||
32 | */ | ||
24 | #define BUCKETS 12 | 33 | #define BUCKETS 12 |
25 | #define INTERVALS 8 | 34 | #define INTERVALS 8 |
26 | #define RESOLUTION 1024 | 35 | #define RESOLUTION 1024 |
@@ -114,11 +123,11 @@ struct menu_device { | |||
114 | int needs_update; | 123 | int needs_update; |
115 | 124 | ||
116 | unsigned int expected_us; | 125 | unsigned int expected_us; |
117 | u64 predicted_us; | 126 | unsigned int predicted_us; |
118 | unsigned int exit_us; | 127 | unsigned int exit_us; |
119 | unsigned int bucket; | 128 | unsigned int bucket; |
120 | u64 correction_factor[BUCKETS]; | 129 | unsigned int correction_factor[BUCKETS]; |
121 | u32 intervals[INTERVALS]; | 130 | unsigned int intervals[INTERVALS]; |
122 | int interval_ptr; | 131 | int interval_ptr; |
123 | }; | 132 | }; |
124 | 133 | ||
@@ -199,16 +208,20 @@ static u64 div_round64(u64 dividend, u32 divisor) | |||
199 | */ | 208 | */ |
200 | static void get_typical_interval(struct menu_device *data) | 209 | static void get_typical_interval(struct menu_device *data) |
201 | { | 210 | { |
202 | int i = 0, divisor = 0; | 211 | int i, divisor; |
203 | uint64_t max = 0, avg = 0, stddev = 0; | 212 | unsigned int max, thresh; |
204 | int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ | 213 | uint64_t avg, stddev; |
214 | |||
215 | thresh = UINT_MAX; /* Discard outliers above this value */ | ||
205 | 216 | ||
206 | again: | 217 | again: |
207 | 218 | ||
208 | /* first calculate average and standard deviation of the past */ | 219 | /* First calculate the average of past intervals */ |
209 | max = avg = divisor = stddev = 0; | 220 | max = 0; |
221 | avg = 0; | ||
222 | divisor = 0; | ||
210 | for (i = 0; i < INTERVALS; i++) { | 223 | for (i = 0; i < INTERVALS; i++) { |
211 | int64_t value = data->intervals[i]; | 224 | unsigned int value = data->intervals[i]; |
212 | if (value <= thresh) { | 225 | if (value <= thresh) { |
213 | avg += value; | 226 | avg += value; |
214 | divisor++; | 227 | divisor++; |
@@ -218,15 +231,38 @@ again: | |||
218 | } | 231 | } |
219 | do_div(avg, divisor); | 232 | do_div(avg, divisor); |
220 | 233 | ||
234 | /* Then try to determine standard deviation */ | ||
235 | stddev = 0; | ||
221 | for (i = 0; i < INTERVALS; i++) { | 236 | for (i = 0; i < INTERVALS; i++) { |
222 | int64_t value = data->intervals[i]; | 237 | unsigned int value = data->intervals[i]; |
223 | if (value <= thresh) { | 238 | if (value <= thresh) { |
224 | int64_t diff = value - avg; | 239 | int64_t diff = value - avg; |
225 | stddev += diff * diff; | 240 | stddev += diff * diff; |
226 | } | 241 | } |
227 | } | 242 | } |
228 | do_div(stddev, divisor); | 243 | do_div(stddev, divisor); |
229 | stddev = int_sqrt(stddev); | 244 | /* |
245 | * The typical interval is obtained when standard deviation is small | ||
246 | * or standard deviation is small compared to the average interval. | ||
247 | * | ||
248 | * int_sqrt() formal parameter type is unsigned long. When the | ||
249 | * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor) | ||
250 | * the resulting squared standard deviation exceeds the input domain | ||
251 | * of int_sqrt on platforms where unsigned long is 32 bits in size. | ||
252 | * In such case reject the candidate average. | ||
253 | * | ||
254 | * Use this result only if there is no timer to wake us up sooner. | ||
255 | */ | ||
256 | if (likely(stddev <= ULONG_MAX)) { | ||
257 | stddev = int_sqrt(stddev); | ||
258 | if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) | ||
259 | || stddev <= 20) { | ||
260 | if (data->expected_us > avg) | ||
261 | data->predicted_us = avg; | ||
262 | return; | ||
263 | } | ||
264 | } | ||
265 | |||
230 | /* | 266 | /* |
231 | * If we have outliers to the upside in our distribution, discard | 267 | * If we have outliers to the upside in our distribution, discard |
232 | * those by setting the threshold to exclude these outliers, then | 268 | * those by setting the threshold to exclude these outliers, then |
@@ -235,20 +271,12 @@ again: | |||
235 | * | 271 | * |
236 | * This can deal with workloads that have long pauses interspersed | 272 | * This can deal with workloads that have long pauses interspersed |
237 | * with sporadic activity with a bunch of short pauses. | 273 | * with sporadic activity with a bunch of short pauses. |
238 | * | ||
239 | * The typical interval is obtained when standard deviation is small | ||
240 | * or standard deviation is small compared to the average interval. | ||
241 | */ | 274 | */ |
242 | if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) | 275 | if ((divisor * 4) <= INTERVALS * 3) |
243 | || stddev <= 20) { | ||
244 | data->predicted_us = avg; | ||
245 | return; | 276 | return; |
246 | 277 | ||
247 | } else if ((divisor * 4) > INTERVALS * 3) { | 278 | thresh = max - 1; |
248 | /* Exclude the max interval */ | 279 | goto again; |
249 | thresh = max - 1; | ||
250 | goto again; | ||
251 | } | ||
252 | } | 280 | } |
253 | 281 | ||
254 | /** | 282 | /** |
@@ -293,8 +321,13 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
293 | if (data->correction_factor[data->bucket] == 0) | 321 | if (data->correction_factor[data->bucket] == 0) |
294 | data->correction_factor[data->bucket] = RESOLUTION * DECAY; | 322 | data->correction_factor[data->bucket] = RESOLUTION * DECAY; |
295 | 323 | ||
296 | /* Make sure to round up for half microseconds */ | 324 | /* |
297 | data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], | 325 | * Force the result of multiplication to be 64 bits even if both |
326 | * operands are 32 bits. | ||
327 | * Make sure to round up for half microseconds. | ||
328 | */ | ||
329 | data->predicted_us = div_round64((uint64_t)data->expected_us * | ||
330 | data->correction_factor[data->bucket], | ||
298 | RESOLUTION * DECAY); | 331 | RESOLUTION * DECAY); |
299 | 332 | ||
300 | get_typical_interval(data); | 333 | get_typical_interval(data); |
@@ -360,7 +393,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
360 | unsigned int last_idle_us = cpuidle_get_last_residency(dev); | 393 | unsigned int last_idle_us = cpuidle_get_last_residency(dev); |
361 | struct cpuidle_state *target = &drv->states[last_idx]; | 394 | struct cpuidle_state *target = &drv->states[last_idx]; |
362 | unsigned int measured_us; | 395 | unsigned int measured_us; |
363 | u64 new_factor; | 396 | unsigned int new_factor; |
364 | 397 | ||
365 | /* | 398 | /* |
366 | * Ugh, this idle state doesn't support residency measurements, so we | 399 | * Ugh, this idle state doesn't support residency measurements, so we |
@@ -381,10 +414,9 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
381 | measured_us -= data->exit_us; | 414 | measured_us -= data->exit_us; |
382 | 415 | ||
383 | 416 | ||
384 | /* update our correction ratio */ | 417 | /* Update our correction ratio */ |
385 | 418 | new_factor = data->correction_factor[data->bucket]; | |
386 | new_factor = data->correction_factor[data->bucket] | 419 | new_factor -= new_factor / DECAY; |
387 | * (DECAY - 1) / DECAY; | ||
388 | 420 | ||
389 | if (data->expected_us > 0 && measured_us < MAX_INTERESTING) | 421 | if (data->expected_us > 0 && measured_us < MAX_INTERESTING) |
390 | new_factor += RESOLUTION * measured_us / data->expected_us; | 422 | new_factor += RESOLUTION * measured_us / data->expected_us; |
@@ -397,9 +429,11 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
397 | 429 | ||
398 | /* | 430 | /* |
399 | * We don't want 0 as factor; we always want at least | 431 | * We don't want 0 as factor; we always want at least |
400 | * a tiny bit of estimated time. | 432 | * a tiny bit of estimated time. Fortunately, due to rounding, |
433 | * new_factor will stay nonzero regardless of measured_us values | ||
434 | * and the compiler can eliminate this test as long as DECAY > 1. | ||
401 | */ | 435 | */ |
402 | if (new_factor == 0) | 436 | if (DECAY == 1 && unlikely(new_factor == 0)) |
403 | new_factor = 1; | 437 | new_factor = 1; |
404 | 438 | ||
405 | data->correction_factor[data->bucket] = new_factor; | 439 | data->correction_factor[data->bucket] = new_factor; |
@@ -442,14 +476,4 @@ static int __init init_menu(void) | |||
442 | return cpuidle_register_governor(&menu_governor); | 476 | return cpuidle_register_governor(&menu_governor); |
443 | } | 477 | } |
444 | 478 | ||
445 | /** | 479 | postcore_initcall(init_menu); |
446 | * exit_menu - exits the governor | ||
447 | */ | ||
448 | static void __exit exit_menu(void) | ||
449 | { | ||
450 | cpuidle_unregister_governor(&menu_governor); | ||
451 | } | ||
452 | |||
453 | MODULE_LICENSE("GPL"); | ||
454 | module_init(init_menu); | ||
455 | module_exit(exit_menu); | ||