2010-11-16 04:58:37 +03:00
/*
* lib / average . c
*
* This source code is licensed under the GNU General Public License ,
* Version 2. See the file COPYING for more details .
*/
2011-11-17 06:29:17 +04:00
# include <linux/export.h>
2010-11-16 04:58:37 +03:00
# include <linux/average.h>
2011-11-17 06:29:17 +04:00
# include <linux/kernel.h>
2010-11-16 04:58:37 +03:00
# include <linux/bug.h>
2010-12-02 13:50:37 +03:00
# include <linux/log2.h>
2010-11-16 04:58:37 +03:00
/**
* 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
2010-12-02 13:50:37 +03:00
* of averages can be ULONG_MAX / ( factor * weight ) . For performance reasons
* factor has to be a power of 2.
2010-11-16 04:58:37 +03:00
* @ weight : Exponential weight , or decay rate . This defines how fast the
2010-12-02 13:50:37 +03:00
* influence of older values decreases . For performance reasons weight has
* to be a power of 2.
2010-11-16 04:58:37 +03:00
*
* Initialize the EWMA parameters for a given struct ewma @ avg .
*/
void ewma_init ( struct ewma * avg , unsigned long factor , unsigned long weight )
{
2010-12-02 13:50:37 +03:00
WARN_ON ( ! is_power_of_2 ( weight ) | | ! is_power_of_2 ( factor ) ) ;
avg - > weight = ilog2 ( weight ) ;
avg - > factor = ilog2 ( factor ) ;
2010-11-16 04:58:37 +03:00
avg - > internal = 0 ;
}
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 )
{
2014-01-17 10:23:29 +04:00
unsigned long internal = ACCESS_ONCE ( avg - > internal ) ;
ACCESS_ONCE ( avg - > internal ) = internal ?
( ( ( internal < < avg - > weight ) - internal ) +
2010-12-02 13:50:37 +03:00
( val < < avg - > factor ) ) > > avg - > weight :
( val < < avg - > factor ) ;
2010-11-16 04:58:37 +03:00
return avg ;
}
EXPORT_SYMBOL ( ewma_add ) ;