lib: Improve EWMA efficiency by using bitshifts
Using bitshifts instead of division and multiplication should improve performance. That requires weight and factor to be powers of two, but i think this is something we can live with. Thanks to Peter Zijlstra for the improved formula! Signed-off-by: Bruno Randolf <br1@einfach.org> -- v2: use log2.h functions Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
5dcc03fe29
commit
af55688435
|
@ -1,8 +1,6 @@
|
|||
#ifndef _LINUX_AVERAGE_H
|
||||
#define _LINUX_AVERAGE_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/* Exponentially weighted moving average (EWMA) */
|
||||
|
||||
/* For more documentation see lib/average.c */
|
||||
|
@ -26,7 +24,7 @@ extern struct ewma *ewma_add(struct ewma *avg, unsigned long val);
|
|||
*/
|
||||
static inline unsigned long ewma_read(const struct ewma *avg)
|
||||
{
|
||||
return DIV_ROUND_CLOSEST(avg->internal, avg->factor);
|
||||
return avg->internal >> avg->factor;
|
||||
}
|
||||
|
||||
#endif /* _LINUX_AVERAGE_H */
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/average.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
/**
|
||||
* DOC: Exponentially Weighted Moving Average (EWMA)
|
||||
|
@ -24,18 +25,21 @@
|
|||
* 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).
|
||||
* of averages can be ULONG_MAX/(factor*weight). For performance reasons
|
||||
* factor has to be a power of 2.
|
||||
* @weight: Exponential weight, or decay rate. This defines how fast the
|
||||
* influence of older values decreases. Has to be bigger than 1.
|
||||
* influence of older values decreases. For performance reasons weight has
|
||||
* to be a power of 2.
|
||||
*
|
||||
* 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);
|
||||
WARN_ON(!is_power_of_2(weight) || !is_power_of_2(factor));
|
||||
|
||||
avg->weight = ilog2(weight);
|
||||
avg->factor = ilog2(factor);
|
||||
avg->internal = 0;
|
||||
avg->weight = weight;
|
||||
avg->factor = factor;
|
||||
}
|
||||
EXPORT_SYMBOL(ewma_init);
|
||||
|
||||
|
@ -49,9 +53,9 @@ EXPORT_SYMBOL(ewma_init);
|
|||
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);
|
||||
(((avg->internal << avg->weight) - avg->internal) +
|
||||
(val << avg->factor)) >> avg->weight :
|
||||
(val << avg->factor);
|
||||
return avg;
|
||||
}
|
||||
EXPORT_SYMBOL(ewma_add);
|
||||
|
|
Loading…
Reference in New Issue