Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib: Improve EWMA efficiency by using bitshifts

Using bitshifts instead of division and multiplication should improve
performance. That requires weight and factor to be powers of two, but i think
this is something we can live with.

Thanks to Peter Zijlstra for the improved formula!

Signed-off-by: Bruno Randolf <br1@einfach.org>

--

v2: use log2.h functions
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Bruno Randolf and committed by
John W. Linville
af556884 5dcc03fe

+13 -11
+1 -3
include/linux/average.h
··· 1 1 #ifndef _LINUX_AVERAGE_H 2 2 #define _LINUX_AVERAGE_H 3 3 4 - #include <linux/kernel.h> 5 - 6 4 /* Exponentially weighted moving average (EWMA) */ 7 5 8 6 /* For more documentation see lib/average.c */ ··· 24 26 */ 25 27 static inline unsigned long ewma_read(const struct ewma *avg) 26 28 { 27 - return DIV_ROUND_CLOSEST(avg->internal, avg->factor); 29 + return avg->internal >> avg->factor; 28 30 } 29 31 30 32 #endif /* _LINUX_AVERAGE_H */
+12 -8
lib/average.c
··· 8 8 #include <linux/module.h> 9 9 #include <linux/average.h> 10 10 #include <linux/bug.h> 11 + #include <linux/log2.h> 11 12 12 13 /** 13 14 * DOC: Exponentially Weighted Moving Average (EWMA) ··· 25 24 * ewma_init() - Initialize EWMA parameters 26 25 * @avg: Average structure 27 26 * @factor: Factor to use for the scaled up internal value. The maximum value 28 - * of averages can be ULONG_MAX/(factor*weight). 27 + * of averages can be ULONG_MAX/(factor*weight). For performance reasons 28 + * factor has to be a power of 2. 29 29 * @weight: Exponential weight, or decay rate. This defines how fast the 30 - * influence of older values decreases. Has to be bigger than 1. 30 + * influence of older values decreases. For performance reasons weight has 31 + * to be a power of 2. 31 32 * 32 33 * Initialize the EWMA parameters for a given struct ewma @avg. 33 34 */ 34 35 void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) 35 36 { 36 - WARN_ON(weight <= 1 || factor == 0); 37 + WARN_ON(!is_power_of_2(weight) || !is_power_of_2(factor)); 38 + 39 + avg->weight = ilog2(weight); 40 + avg->factor = ilog2(factor); 37 41 avg->internal = 0; 38 - avg->weight = weight; 39 - avg->factor = factor; 40 42 } 41 43 EXPORT_SYMBOL(ewma_init); 42 44 ··· 53 49 struct ewma *ewma_add(struct ewma *avg, unsigned long val) 54 50 { 55 51 avg->internal = avg->internal ? 56 - (((avg->internal * (avg->weight - 1)) + 57 - (val * avg->factor)) / avg->weight) : 58 - (val * avg->factor); 52 + (((avg->internal << avg->weight) - avg->internal) + 53 + (val << avg->factor)) >> avg->weight : 54 + (val << avg->factor); 59 55 return avg; 60 56 } 61 57 EXPORT_SYMBOL(ewma_add);