aboutsummaryrefslogtreecommitdiff
path: root/lib/average.c
diff options
context:
space:
mode:
authorBruno Randolf <br1@einfach.org>2010-12-02 19:50:37 +0900
committerJohn W. Linville <linville@tuxdriver.com>2010-12-06 15:58:43 -0500
commitaf5568843594fb71055debe36e521fa8072fcecc (patch)
tree4f35966cb4e1018b05c87d7a10c337d888949e22 /lib/average.c
parent5dcc03fe29537edd7819f5b121bf3d779693f37b (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/average.c')
-rw-r--r--lib/average.c20
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);