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>
This commit is contained in:
Bruno Randolf 2010-11-16 10:58:37 +09:00 коммит произвёл John W. Linville
Родитель 50a9432dae
Коммит c5485a7e75
4 изменённых файлов: 94 добавлений и 0 удалений

32
include/linux/average.h Normal file
Просмотреть файл

@ -0,0 +1,32 @@
#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 */

Просмотреть файл

@ -210,4 +210,7 @@ config GENERIC_ATOMIC64
config LRU_CACHE
tristate
config AVERAGE
bool
endmenu

Просмотреть файл

@ -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

57
lib/average.c Normal file
Просмотреть файл

@ -0,0 +1,57 @@
/*
* 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);