From: Rafael J. Wysocki Date: Thu, 6 Feb 2025 14:24:18 +0000 (+0100) Subject: cpuidle: menu: Use one loop for average and variance computations X-Git-Tag: io_uring-6.15-20250403~113^2~3^2~1^2~1^2~4 X-Git-Url: https://git.kernel.dk/?a=commitdiff_plain;h=13982929fb08ed4691256072856f50bf7b206b9b;p=linux-block.git cpuidle: menu: Use one loop for average and variance computations Use the observation that one loop is sufficient to compute the average of an array of values and their variance to eliminate one of the loops from get_typical_interval(). While at it, make get_typical_interval() consistently use u64 as the 64-bit unsigned integer data type and rearrange some white space and the declarations of local variables in it (to make them follow the reverse X-mas tree pattern). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Tested-by: Artem Bityutskiy Reviewed-by: Christian Loehle Tested-by: Christian Loehle Tested-by: Aboorva Devarajan Link: https://patch.msgid.link/3339073.aeNJFYEL58@rjwysocki.net --- diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index b19406502b56..ec472af38de6 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -116,49 +116,45 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); */ static unsigned int get_typical_interval(struct menu_device *data) { - int i, divisor; - unsigned int max, thresh, avg; - uint64_t sum, variance; - - thresh = INT_MAX; /* Discard outliers above this value */ + unsigned int max, divisor, thresh = INT_MAX; + u64 avg, variance, avg_sq; + int i; again: - - /* First calculate the average of past intervals */ + /* Compute the average and variance of past intervals. */ max = 0; - sum = 0; + avg = 0; + variance = 0; divisor = 0; for (i = 0; i < INTERVALS; i++) { unsigned int value = data->intervals[i]; - if (value <= thresh) { - sum += value; - divisor++; - if (value > max) - max = value; - } + + /* Discard data points above the threshold. */ + if (value > thresh) + continue; + + divisor++; + + avg += value; + variance += (u64)value * value; + + if (value > max) + max = value; } if (!max) return UINT_MAX; - if (divisor == INTERVALS) - avg = sum >> INTERVAL_SHIFT; - else - avg = div_u64(sum, divisor); - - /* Then try to determine variance */ - variance = 0; - for (i = 0; i < INTERVALS; i++) { - unsigned int value = data->intervals[i]; - if (value <= thresh) { - int64_t diff = (int64_t)value - avg; - variance += diff * diff; - } - } - if (divisor == INTERVALS) + if (divisor == INTERVALS) { + avg >>= INTERVAL_SHIFT; variance >>= INTERVAL_SHIFT; - else + } else { + do_div(avg, divisor); do_div(variance, divisor); + } + + avg_sq = avg * avg; + variance -= avg_sq; /* * The typical interval is obtained when standard deviation is @@ -173,10 +169,9 @@ again: * Use this result only if there is no timer to wake us up sooner. */ if (likely(variance <= U64_MAX/36)) { - if ((((u64)avg*avg > variance*36) && (divisor * 4 >= INTERVALS * 3)) - || variance <= 400) { + if ((avg_sq > variance * 36 && divisor * 4 >= INTERVALS * 3) || + variance <= 400) return avg; - } } /*