aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Randolf <br1@einfach.org>2010-11-15 20:58:37 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-11-18 14:21:52 -0500
commitc5485a7e7569ab32eea240c850198519e2a765ef (patch)
tree928a8556deaec0811d1b83102b33365aab28a270
parent50a9432daeece6fc1309bef1dc0a7b8fde8204cb (diff)
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>
-rw-r--r--include/linux/average.h32
-rw-r--r--lib/Kconfig3
-rw-r--r--lib/Makefile2
-rw-r--r--lib/average.c57
4 files changed, 94 insertions, 0 deletions
diff --git a/include/linux/average.h b/include/linux/average.h
new file mode 100644
index 000000000000..7706e40f95fa
--- /dev/null
+++ b/include/linux/average.h
@@ -0,0 +1,32 @@
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
10struct ewma {
11 unsigned long internal;
12 unsigned long factor;
13 unsigned long weight;
14};
15
16extern void ewma_init(struct ewma *avg, unsigned long factor,
17 unsigned long weight);
18
19extern 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 */
27static 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 */
diff --git a/lib/Kconfig b/lib/Kconfig
index fa9bf2c06199..3116aa631af6 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -210,4 +210,7 @@ config GENERIC_ATOMIC64
210config LRU_CACHE 210config LRU_CACHE
211 tristate 211 tristate
212 212
213config AVERAGE
214 bool
215
213endmenu 216endmenu
diff --git a/lib/Makefile b/lib/Makefile
index e6a3763b8212..76d3b8514903 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -106,6 +106,8 @@ obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
106 106
107obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o 107obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o
108 108
109obj-$(CONFIG_AVERAGE) += average.o
110
109hostprogs-y := gen_crc32table 111hostprogs-y := gen_crc32table
110clean-files := crc32table.h 112clean-files := crc32table.h
111 113
diff --git a/lib/average.c b/lib/average.c
new file mode 100644
index 000000000000..f1d1b4660c42
--- /dev/null
+++ b/lib/average.c
@@ -0,0 +1,57 @@
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 */
33void 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}
40EXPORT_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 */
49struct 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}
57EXPORT_SYMBOL(ewma_add);