diff options
author | Bruno Randolf <br1@einfach.org> | 2010-12-02 19:50:37 +0900 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-06 15:58:43 -0500 |
commit | af5568843594fb71055debe36e521fa8072fcecc (patch) | |
tree | 4f35966cb4e1018b05c87d7a10c337d888949e22 /lib | |
parent | 5dcc03fe29537edd7819f5b121bf3d779693f37b (diff) |
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>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/average.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/lib/average.c b/lib/average.c index f1d1b4660c4..5576c284149 100644 --- a/lib/average.c +++ b/lib/average.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/average.h> #include <linux/bug.h> +#include <linux/log2.h> /** * DOC: Exponentially Weighted Moving Average (EWMA) @@ -24,18 +25,21 @@ * ewma_init() - Initialize EWMA parameters * @avg: Average structure * @factor: Factor to use for the scaled up internal value. The maximum value - * of averages can be ULONG_MAX/(factor*weight). + * of averages can be ULONG_MAX/(factor*weight). For performance reasons + * factor has to be a power of 2. * @weight: Exponential weight, or decay rate. This defines how fast the - * influence of older values decreases. Has to be bigger than 1. + * influence of older values decreases. For performance reasons weight has + * to be a power of 2. * * Initialize the EWMA parameters for a given struct ewma @avg. */ void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) { - WARN_ON(weight <= 1 || factor == 0); + WARN_ON(!is_power_of_2(weight) || !is_power_of_2(factor)); + + avg->weight = ilog2(weight); + avg->factor = ilog2(factor); avg->internal = 0; - avg->weight = weight; - avg->factor = factor; } EXPORT_SYMBOL(ewma_init); @@ -49,9 +53,9 @@ EXPORT_SYMBOL(ewma_init); struct ewma *ewma_add(struct ewma *avg, unsigned long val) { avg->internal = avg->internal ? - (((avg->internal * (avg->weight - 1)) + - (val * avg->factor)) / avg->weight) : - (val * avg->factor); + (((avg->internal << avg->weight) - avg->internal) + + (val << avg->factor)) >> avg->weight : + (val << avg->factor); return avg; } EXPORT_SYMBOL(ewma_add); |