aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Randolf <br1@einfach.org>2010-12-02 05:50:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-12-06 15:58:43 -0500
commitaf5568843594fb71055debe36e521fa8072fcecc (patch)
tree4f35966cb4e1018b05c87d7a10c337d888949e22
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>
-rw-r--r--include/linux/average.h4
-rw-r--r--lib/average.c20
2 files changed, 13 insertions, 11 deletions
diff --git a/include/linux/average.h b/include/linux/average.h
index 7706e40f95fa..c6028fd742c1 100644
--- a/include/linux/average.h
+++ b/include/linux/average.h
@@ -1,8 +1,6 @@
1#ifndef _LINUX_AVERAGE_H 1#ifndef _LINUX_AVERAGE_H
2#define _LINUX_AVERAGE_H 2#define _LINUX_AVERAGE_H
3 3
4#include <linux/kernel.h>
5
6/* Exponentially weighted moving average (EWMA) */ 4/* Exponentially weighted moving average (EWMA) */
7 5
8/* For more documentation see lib/average.c */ 6/* For more documentation see lib/average.c */
@@ -26,7 +24,7 @@ extern struct ewma *ewma_add(struct ewma *avg, unsigned long val);
26 */ 24 */
27static inline unsigned long ewma_read(const struct ewma *avg) 25static inline unsigned long ewma_read(const struct ewma *avg)
28{ 26{
29 return DIV_ROUND_CLOSEST(avg->internal, avg->factor); 27 return avg->internal >> avg->factor;
30} 28}
31 29
32#endif /* _LINUX_AVERAGE_H */ 30#endif /* _LINUX_AVERAGE_H */
diff --git a/lib/average.c b/lib/average.c
index f1d1b4660c42..5576c2841496 100644
--- a/lib/average.c
+++ b/lib/average.c
@@ -8,6 +8,7 @@
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/average.h> 9#include <linux/average.h>
10#include <linux/bug.h> 10#include <linux/bug.h>
11#include <linux/log2.h>
11 12
12/** 13/**
13 * DOC: Exponentially Weighted Moving Average (EWMA) 14 * DOC: Exponentially Weighted Moving Average (EWMA)
@@ -24,18 +25,21 @@
24 * ewma_init() - Initialize EWMA parameters 25 * ewma_init() - Initialize EWMA parameters
25 * @avg: Average structure 26 * @avg: Average structure
26 * @factor: Factor to use for the scaled up internal value. The maximum value 27 * @factor: Factor to use for the scaled up internal value. The maximum value
27 * of averages can be ULONG_MAX/(factor*weight). 28 * of averages can be ULONG_MAX/(factor*weight). For performance reasons
29 * factor has to be a power of 2.
28 * @weight: Exponential weight, or decay rate. This defines how fast the 30 * @weight: Exponential weight, or decay rate. This defines how fast the
29 * influence of older values decreases. Has to be bigger than 1. 31 * influence of older values decreases. For performance reasons weight has
32 * to be a power of 2.
30 * 33 *
31 * Initialize the EWMA parameters for a given struct ewma @avg. 34 * Initialize the EWMA parameters for a given struct ewma @avg.
32 */ 35 */
33void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) 36void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight)
34{ 37{
35 WARN_ON(weight <= 1 || factor == 0); 38 WARN_ON(!is_power_of_2(weight) || !is_power_of_2(factor));
39
40 avg->weight = ilog2(weight);
41 avg->factor = ilog2(factor);
36 avg->internal = 0; 42 avg->internal = 0;
37 avg->weight = weight;
38 avg->factor = factor;
39} 43}
40EXPORT_SYMBOL(ewma_init); 44EXPORT_SYMBOL(ewma_init);
41 45
@@ -49,9 +53,9 @@ EXPORT_SYMBOL(ewma_init);
49struct ewma *ewma_add(struct ewma *avg, unsigned long val) 53struct ewma *ewma_add(struct ewma *avg, unsigned long val)
50{ 54{
51 avg->internal = avg->internal ? 55 avg->internal = avg->internal ?
52 (((avg->internal * (avg->weight - 1)) + 56 (((avg->internal << avg->weight) - avg->internal) +
53 (val * avg->factor)) / avg->weight) : 57 (val << avg->factor)) >> avg->weight :
54 (val * avg->factor); 58 (val << avg->factor);
55 return avg; 59 return avg;
56} 60}
57EXPORT_SYMBOL(ewma_add); 61EXPORT_SYMBOL(ewma_add);