Commit af5568843594fb71055debe36e521fa8072fcecc
Committed by
John W. Linville
1 parent
5dcc03fe29
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 13 additions and 11 deletions Side-by-side Diff
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 */ |
... | ... | @@ -26,7 +24,7 @@ |
26 | 24 | */ |
27 | 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 | 30 | #endif /* _LINUX_AVERAGE_H */ |
lib/average.c
... | ... | @@ -8,6 +8,7 @@ |
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) |
14 | 15 | |
15 | 16 | |
16 | 17 | |
... | ... | @@ -24,18 +25,21 @@ |
24 | 25 | * ewma_init() - Initialize EWMA parameters |
25 | 26 | * @avg: Average structure |
26 | 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 | 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 | 34 | * Initialize the EWMA parameters for a given struct ewma @avg. |
32 | 35 | */ |
33 | 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 | 42 | avg->internal = 0; |
37 | - avg->weight = weight; | |
38 | - avg->factor = factor; | |
39 | 43 | } |
40 | 44 | EXPORT_SYMBOL(ewma_init); |
41 | 45 | |
... | ... | @@ -49,9 +53,9 @@ |
49 | 53 | struct ewma *ewma_add(struct ewma *avg, unsigned long val) |
50 | 54 | { |
51 | 55 | avg->internal = avg->internal ? |
52 | - (((avg->internal * (avg->weight - 1)) + | |
53 | - (val * avg->factor)) / avg->weight) : | |
54 | - (val * avg->factor); | |
56 | + (((avg->internal << avg->weight) - avg->internal) + | |
57 | + (val << avg->factor)) >> avg->weight : | |
58 | + (val << avg->factor); | |
55 | 59 | return avg; |
56 | 60 | } |
57 | 61 | EXPORT_SYMBOL(ewma_add); |