Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5485a7e authored by Bruno Randolf's avatar Bruno Randolf Committed by John W. Linville
Browse files

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: default avatarBruno Randolf <br1@einfach.org>
Reviewed-by: default avatarKOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 50a9432d
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
#ifndef _LINUX_AVERAGE_H
#define _LINUX_AVERAGE_H

#include <linux/kernel.h>

/* Exponentially weighted moving average (EWMA) */

/* For more documentation see lib/average.c */

struct ewma {
	unsigned long internal;
	unsigned long factor;
	unsigned long weight;
};

extern void ewma_init(struct ewma *avg, unsigned long factor,
		      unsigned long weight);

extern struct ewma *ewma_add(struct ewma *avg, unsigned long val);

/**
 * ewma_read() - Get average value
 * @avg: Average structure
 *
 * Returns the average value held in @avg.
 */
static inline unsigned long ewma_read(const struct ewma *avg)
{
	return DIV_ROUND_CLOSEST(avg->internal, avg->factor);
}

#endif /* _LINUX_AVERAGE_H */
+3 −0
Original line number Diff line number Diff line
@@ -210,4 +210,7 @@ config GENERIC_ATOMIC64
config LRU_CACHE
	tristate

config AVERAGE
	bool

endmenu
+2 −0
Original line number Diff line number Diff line
@@ -106,6 +106,8 @@ obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o

obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o

obj-$(CONFIG_AVERAGE) += average.o

hostprogs-y	:= gen_crc32table
clean-files	:= crc32table.h

lib/average.c

0 → 100644
+57 −0
Original line number Diff line number Diff line
/*
 * lib/average.c
 *
 * This source code is licensed under the GNU General Public License,
 * Version 2.  See the file COPYING for more details.
 */

#include <linux/module.h>
#include <linux/average.h>
#include <linux/bug.h>

/**
 * DOC: Exponentially Weighted Moving Average (EWMA)
 *
 * These are generic functions for calculating Exponentially Weighted Moving
 * Averages (EWMA). We keep a structure with the EWMA parameters and a scaled
 * up internal representation of the average value to prevent rounding errors.
 * The factor for scaling up and the exponential weight (or decay rate) have to
 * be specified thru the init fuction. The structure should not be accessed
 * directly but only thru the helper functions.
 */

/**
 * ewma_init() - Initialize EWMA parameters
 * @avg: Average structure
 * @factor: Factor to use for the scaled up internal value. The maximum value
 *	of averages can be ULONG_MAX/(factor*weight).
 * @weight: Exponential weight, or decay rate. This defines how fast the
 *	influence of older values decreases. Has to be bigger than 1.
 *
 * Initialize the EWMA parameters for a given struct ewma @avg.
 */
void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight)
{
	WARN_ON(weight <= 1 || factor == 0);
	avg->internal = 0;
	avg->weight = weight;
	avg->factor = factor;
}
EXPORT_SYMBOL(ewma_init);

/**
 * ewma_add() - Exponentially weighted moving average (EWMA)
 * @avg: Average structure
 * @val: Current value
 *
 * Add a sample to the average.
 */
struct ewma *ewma_add(struct ewma *avg, unsigned long val)
{
	avg->internal = avg->internal  ?
		(((avg->internal * (avg->weight - 1)) +
			(val * avg->factor)) / avg->weight) :
		(val * avg->factor);
	return avg;
}
EXPORT_SYMBOL(ewma_add);