summaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle
diff options
context:
space:
mode:
authorRasmus Villemoes <linux@rasmusvillemoes.dk>2016-02-16 14:19:18 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-02-16 18:27:16 -0500
commit7024b18ca461bab45e5fb329f6e3d904d5109401 (patch)
tree2dd0d4bc8479ccf843094e6c584fafb7dd3260ac /drivers/cpuidle
parent18558cae0272f8fd9647e69d3fec1565a7949865 (diff)
cpuidle: menu: avoid expensive square root computation
Computing the integer square root is a rather expensive operation, at least compared to doing a 64x64 -> 64 multiply (avg*avg) and, on 64 bit platforms, doing an extra comparison to a constant (variance <= U64_MAX/36). On 64 bit platforms, this does mean that we add a restriction on the range of the variance where we end up using the estimate (since previously the stddev <= ULONG_MAX was a tautology), but on the other hand, we extend the range quite substantially on 32 bit platforms - in both cases, we now allow standard deviations up to 715 seconds, which is for example guaranteed if all observations are less than 1430 seconds. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r--drivers/cpuidle/governors/menu.c35
1 files changed, 17 insertions, 18 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 0742b3296673..beef7ae123ba 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -200,7 +200,7 @@ static void get_typical_interval(struct menu_device *data)
200{ 200{
201 int i, divisor; 201 int i, divisor;
202 unsigned int max, thresh; 202 unsigned int max, thresh;
203 uint64_t avg, stddev; 203 uint64_t avg, variance;
204 204
205 thresh = UINT_MAX; /* Discard outliers above this value */ 205 thresh = UINT_MAX; /* Discard outliers above this value */
206 206
@@ -224,36 +224,35 @@ again:
224 else 224 else
225 do_div(avg, divisor); 225 do_div(avg, divisor);
226 226
227 /* Then try to determine standard deviation */ 227 /* Then try to determine variance */
228 stddev = 0; 228 variance = 0;
229 for (i = 0; i < INTERVALS; i++) { 229 for (i = 0; i < INTERVALS; i++) {
230 unsigned int value = data->intervals[i]; 230 unsigned int value = data->intervals[i];
231 if (value <= thresh) { 231 if (value <= thresh) {
232 int64_t diff = value - avg; 232 int64_t diff = value - avg;
233 stddev += diff * diff; 233 variance += diff * diff;
234 } 234 }
235 } 235 }
236 if (divisor == INTERVALS) 236 if (divisor == INTERVALS)
237 stddev >>= INTERVAL_SHIFT; 237 variance >>= INTERVAL_SHIFT;
238 else 238 else
239 do_div(stddev, divisor); 239 do_div(variance, divisor);
240 240
241 /* 241 /*
242 * The typical interval is obtained when standard deviation is small 242 * The typical interval is obtained when standard deviation is
243 * or standard deviation is small compared to the average interval. 243 * small (stddev <= 20 us, variance <= 400 us^2) or standard
244 * 244 * deviation is small compared to the average interval (avg >
245 * int_sqrt() formal parameter type is unsigned long. When the 245 * 6*stddev, avg^2 > 36*variance). The average is smaller than
246 * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor) 246 * UINT_MAX aka U32_MAX, so computing its square does not
247 * the resulting squared standard deviation exceeds the input domain 247 * overflow a u64. We simply reject this candidate average if
248 * of int_sqrt on platforms where unsigned long is 32 bits in size. 248 * the standard deviation is greater than 715 s (which is
249 * In such case reject the candidate average. 249 * rather unlikely).
250 * 250 *
251 * Use this result only if there is no timer to wake us up sooner. 251 * Use this result only if there is no timer to wake us up sooner.
252 */ 252 */
253 if (likely(stddev <= ULONG_MAX)) { 253 if (likely(variance <= U64_MAX/36)) {
254 stddev = int_sqrt(stddev); 254 if (((avg*avg > variance*36) && (divisor * 4 >= INTERVALS * 3))
255 if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) 255 || variance <= 400) {
256 || stddev <= 20) {
257 if (data->next_timer_us > avg) 256 if (data->next_timer_us > avg)
258 data->predicted_us = avg; 257 data->predicted_us = avg;
259 return; 258 return;