Commit c5485a7e7569ab32eea240c850198519e2a765ef

Authored by Bruno Randolf
Committed by John W. Linville
1 parent 50a9432dae

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 */
... ... @@ -210,5 +210,8 @@
210 210 config LRU_CACHE
211 211 tristate
212 212  
  213 +config AVERAGE
  214 + bool
  215 +
213 216 endmenu
... ... @@ -106,6 +106,8 @@
106 106  
107 107 obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o
108 108  
  109 +obj-$(CONFIG_AVERAGE) += average.o
  110 +
109 111 hostprogs-y := gen_crc32table
110 112 clean-files := crc32table.h
111 113  
  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);