Commit c5485a7e7569ab32eea240c850198519e2a765ef
Committed by
John W. Linville
1 parent
50a9432dae
Exists in
master
and in
4 other branches
lib: Add generic exponentially weighted moving average (EWMA) function
This adds generic functions for calculating Exponentially Weighted Moving Averages (EWMA). This implementation makes use of a structure which keeps the EWMA parameters and a scaled up internal representation to reduce rounding errors. The original idea for this implementation came from the rt2x00 driver (rt2x00link.c). I would like to use it in several places in the mac80211 and ath5k code and I hope it can be useful in many other places in the kernel code. Signed-off-by: Bruno Randolf <br1@einfach.org> Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Showing 4 changed files with 94 additions and 0 deletions Side-by-side Diff
include/linux/average.h
1 | +#ifndef _LINUX_AVERAGE_H | |
2 | +#define _LINUX_AVERAGE_H | |
3 | + | |
4 | +#include <linux/kernel.h> | |
5 | + | |
6 | +/* Exponentially weighted moving average (EWMA) */ | |
7 | + | |
8 | +/* For more documentation see lib/average.c */ | |
9 | + | |
10 | +struct ewma { | |
11 | + unsigned long internal; | |
12 | + unsigned long factor; | |
13 | + unsigned long weight; | |
14 | +}; | |
15 | + | |
16 | +extern void ewma_init(struct ewma *avg, unsigned long factor, | |
17 | + unsigned long weight); | |
18 | + | |
19 | +extern struct ewma *ewma_add(struct ewma *avg, unsigned long val); | |
20 | + | |
21 | +/** | |
22 | + * ewma_read() - Get average value | |
23 | + * @avg: Average structure | |
24 | + * | |
25 | + * Returns the average value held in @avg. | |
26 | + */ | |
27 | +static inline unsigned long ewma_read(const struct ewma *avg) | |
28 | +{ | |
29 | + return DIV_ROUND_CLOSEST(avg->internal, avg->factor); | |
30 | +} | |
31 | + | |
32 | +#endif /* _LINUX_AVERAGE_H */ |
lib/Kconfig
lib/Makefile
lib/average.c
1 | +/* | |
2 | + * lib/average.c | |
3 | + * | |
4 | + * This source code is licensed under the GNU General Public License, | |
5 | + * Version 2. See the file COPYING for more details. | |
6 | + */ | |
7 | + | |
8 | +#include <linux/module.h> | |
9 | +#include <linux/average.h> | |
10 | +#include <linux/bug.h> | |
11 | + | |
12 | +/** | |
13 | + * DOC: Exponentially Weighted Moving Average (EWMA) | |
14 | + * | |
15 | + * These are generic functions for calculating Exponentially Weighted Moving | |
16 | + * Averages (EWMA). We keep a structure with the EWMA parameters and a scaled | |
17 | + * up internal representation of the average value to prevent rounding errors. | |
18 | + * The factor for scaling up and the exponential weight (or decay rate) have to | |
19 | + * be specified thru the init fuction. The structure should not be accessed | |
20 | + * directly but only thru the helper functions. | |
21 | + */ | |
22 | + | |
23 | +/** | |
24 | + * ewma_init() - Initialize EWMA parameters | |
25 | + * @avg: Average structure | |
26 | + * @factor: Factor to use for the scaled up internal value. The maximum value | |
27 | + * of averages can be ULONG_MAX/(factor*weight). | |
28 | + * @weight: Exponential weight, or decay rate. This defines how fast the | |
29 | + * influence of older values decreases. Has to be bigger than 1. | |
30 | + * | |
31 | + * Initialize the EWMA parameters for a given struct ewma @avg. | |
32 | + */ | |
33 | +void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight) | |
34 | +{ | |
35 | + WARN_ON(weight <= 1 || factor == 0); | |
36 | + avg->internal = 0; | |
37 | + avg->weight = weight; | |
38 | + avg->factor = factor; | |
39 | +} | |
40 | +EXPORT_SYMBOL(ewma_init); | |
41 | + | |
42 | +/** | |
43 | + * ewma_add() - Exponentially weighted moving average (EWMA) | |
44 | + * @avg: Average structure | |
45 | + * @val: Current value | |
46 | + * | |
47 | + * Add a sample to the average. | |
48 | + */ | |
49 | +struct ewma *ewma_add(struct ewma *avg, unsigned long val) | |
50 | +{ | |
51 | + avg->internal = avg->internal ? | |
52 | + (((avg->internal * (avg->weight - 1)) + | |
53 | + (val * avg->factor)) / avg->weight) : | |
54 | + (val * avg->factor); | |
55 | + return avg; | |
56 | +} | |
57 | +EXPORT_SYMBOL(ewma_add); |