diff options
author | Bruno Randolf <br1@einfach.org> | 2010-12-02 05:50:37 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-12-06 15:58:43 -0500 |
commit | af5568843594fb71055debe36e521fa8072fcecc (patch) | |
tree | 4f35966cb4e1018b05c87d7a10c337d888949e22 | |
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>
-rw-r--r-- | include/linux/average.h | 4 | ||||
-rw-r--r-- | lib/average.c | 20 |
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 | */ |
27 | static inline unsigned long ewma_read(const struct ewma *avg) | 25 | static 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 | */ |
33 | void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) | 36 | void 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 | } |
40 | EXPORT_SYMBOL(ewma_init); | 44 | EXPORT_SYMBOL(ewma_init); |
41 | 45 | ||
@@ -49,9 +53,9 @@ EXPORT_SYMBOL(ewma_init); | |||
49 | struct ewma *ewma_add(struct ewma *avg, unsigned long val) | 53 | struct 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 | } |
57 | EXPORT_SYMBOL(ewma_add); | 61 | EXPORT_SYMBOL(ewma_add); |