Commit af5568843594fb71055debe36e521fa8072fcecc

Authored by Bruno Randolf
Committed by John W. Linville
1 parent 5dcc03fe29

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 */
... ... @@ -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);