Line data Source code
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/export.h>
9 : #include <linux/average.h>
10 : #include <linux/kernel.h>
11 : #include <linux/bug.h>
12 : #include <linux/log2.h>
13 :
14 : /**
15 : * DOC: Exponentially Weighted Moving Average (EWMA)
16 : *
17 : * These are generic functions for calculating Exponentially Weighted Moving
18 : * Averages (EWMA). We keep a structure with the EWMA parameters and a scaled
19 : * up internal representation of the average value to prevent rounding errors.
20 : * The factor for scaling up and the exponential weight (or decay rate) have to
21 : * be specified thru the init fuction. The structure should not be accessed
22 : * directly but only thru the helper functions.
23 : */
24 :
25 : /**
26 : * ewma_init() - Initialize EWMA parameters
27 : * @avg: Average structure
28 : * @factor: Factor to use for the scaled up internal value. The maximum value
29 : * of averages can be ULONG_MAX/(factor*weight). For performance reasons
30 : * factor has to be a power of 2.
31 : * @weight: Exponential weight, or decay rate. This defines how fast the
32 : * influence of older values decreases. For performance reasons weight has
33 : * to be a power of 2.
34 : *
35 : * Initialize the EWMA parameters for a given struct ewma @avg.
36 : */
37 0 : void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight)
38 : {
39 : WARN_ON(!is_power_of_2(weight) || !is_power_of_2(factor));
40 :
41 0 : avg->weight = ilog2(weight);
42 0 : avg->factor = ilog2(factor);
43 0 : avg->internal = 0;
44 0 : }
45 : EXPORT_SYMBOL(ewma_init);
46 :
47 : /**
48 : * ewma_add() - Exponentially weighted moving average (EWMA)
49 : * @avg: Average structure
50 : * @val: Current value
51 : *
52 : * Add a sample to the average.
53 : */
54 0 : struct ewma *ewma_add(struct ewma *avg, unsigned long val)
55 : {
56 0 : unsigned long internal = ACCESS_ONCE(avg->internal);
57 :
58 0 : ACCESS_ONCE(avg->internal) = internal ?
59 0 : (((internal << avg->weight) - internal) +
60 0 : (val << avg->factor)) >> avg->weight :
61 0 : (val << avg->factor);
62 0 : return avg;
63 : }
64 : EXPORT_SYMBOL(ewma_add);
|