blob: 3f462292269cc388ccb94eff3fb8d0fe459ffa0a [file] [log] [blame]
Bruno Randolfc5485a72010-11-16 10:58:37 +09001#ifndef _LINUX_AVERAGE_H
2#define _LINUX_AVERAGE_H
3
Mark Rutlandef4d9af2017-10-23 14:07:19 -07004#include <linux/bug.h>
5#include <linux/compiler.h>
6#include <linux/log2.h>
7
Johannes Bergeb1e0112017-02-15 09:49:26 +01008/*
9 * Exponentially weighted moving average (EWMA)
10 *
11 * This implements a fixed-precision EWMA algorithm, with both the
12 * precision and fall-off coefficient determined at compile-time
13 * and built into the generated helper funtions.
14 *
15 * The first argument to the macro is the name that will be used
16 * for the struct and helper functions.
17 *
18 * The second argument, the precision, expresses how many bits are
19 * used for the fractional part of the fixed-precision values.
20 *
21 * The third argument, the weight reciprocal, determines how the
22 * new values will be weighed vs. the old state, new values will
23 * get weight 1/weight_rcp and old values 1-1/weight_rcp. Note
24 * that this parameter must be a power of two for efficiency.
25 */
Bruno Randolfc5485a72010-11-16 10:58:37 +090026
Johannes Bergeb1e0112017-02-15 09:49:26 +010027#define DECLARE_EWMA(name, _precision, _weight_rcp) \
Johannes Berg23777992015-07-13 12:17:25 +020028 struct ewma_##name { \
29 unsigned long internal; \
30 }; \
31 static inline void ewma_##name##_init(struct ewma_##name *e) \
32 { \
Johannes Bergeb1e0112017-02-15 09:49:26 +010033 BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
34 BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
35 /* \
36 * Even if you want to feed it just 0/1 you should have \
37 * some bits for the non-fractional part... \
38 */ \
39 BUILD_BUG_ON((_precision) > 30); \
40 BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
Johannes Berg23777992015-07-13 12:17:25 +020041 e->internal = 0; \
42 } \
43 static inline unsigned long \
44 ewma_##name##_read(struct ewma_##name *e) \
45 { \
Johannes Bergeb1e0112017-02-15 09:49:26 +010046 BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
47 BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
48 BUILD_BUG_ON((_precision) > 30); \
49 BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
50 return e->internal >> (_precision); \
Johannes Berg23777992015-07-13 12:17:25 +020051 } \
52 static inline void ewma_##name##_add(struct ewma_##name *e, \
53 unsigned long val) \
54 { \
Mark Rutlandef4d9af2017-10-23 14:07:19 -070055 unsigned long internal = READ_ONCE(e->internal); \
Johannes Bergeb1e0112017-02-15 09:49:26 +010056 unsigned long weight_rcp = ilog2(_weight_rcp); \
57 unsigned long precision = _precision; \
Johannes Berg23777992015-07-13 12:17:25 +020058 \
Johannes Bergeb1e0112017-02-15 09:49:26 +010059 BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
60 BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
61 BUILD_BUG_ON((_precision) > 30); \
62 BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
Johannes Berg23777992015-07-13 12:17:25 +020063 \
Mark Rutlandef4d9af2017-10-23 14:07:19 -070064 WRITE_ONCE(e->internal, internal ? \
Johannes Bergeb1e0112017-02-15 09:49:26 +010065 (((internal << weight_rcp) - internal) + \
66 (val << precision)) >> weight_rcp : \
Mark Rutlandef4d9af2017-10-23 14:07:19 -070067 (val << precision)); \
Johannes Berg23777992015-07-13 12:17:25 +020068 }
69
Bruno Randolfc5485a72010-11-16 10:58:37 +090070#endif /* _LINUX_AVERAGE_H */