xref: /linux-6.15/include/linux/average.h (revision 2377799c)
1 #ifndef _LINUX_AVERAGE_H
2 #define _LINUX_AVERAGE_H
3 
4 /* Exponentially weighted moving average (EWMA) */
5 
6 /* For more documentation see lib/average.c */
7 
8 struct ewma {
9 	unsigned long internal;
10 	unsigned long factor;
11 	unsigned long weight;
12 };
13 
14 extern void ewma_init(struct ewma *avg, unsigned long factor,
15 		      unsigned long weight);
16 
17 extern struct ewma *ewma_add(struct ewma *avg, unsigned long val);
18 
19 /**
20  * ewma_read() - Get average value
21  * @avg: Average structure
22  *
23  * Returns the average value held in @avg.
24  */
25 static inline unsigned long ewma_read(const struct ewma *avg)
26 {
27 	return avg->internal >> avg->factor;
28 }
29 
30 #define DECLARE_EWMA(name, _factor, _weight)				\
31 	struct ewma_##name {						\
32 		unsigned long internal;					\
33 	};								\
34 	static inline void ewma_##name##_init(struct ewma_##name *e)	\
35 	{								\
36 		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
37 		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
38 		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
39 		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
40 		e->internal = 0;					\
41 	}								\
42 	static inline unsigned long					\
43 	ewma_##name##_read(struct ewma_##name *e)			\
44 	{								\
45 		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
46 		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
47 		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
48 		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
49 		return e->internal >> ilog2(_factor);			\
50 	}								\
51 	static inline void ewma_##name##_add(struct ewma_##name *e,	\
52 					     unsigned long val)		\
53 	{								\
54 		unsigned long internal = ACCESS_ONCE(e->internal);	\
55 		unsigned long weight = ilog2(_weight);			\
56 		unsigned long factor = ilog2(_factor);			\
57 									\
58 		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
59 		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
60 		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
61 		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
62 									\
63 		ACCESS_ONCE(e->internal) = internal ?			\
64 			(((internal << weight) - internal) +		\
65 				(val << factor)) >> weight :		\
66 			(val << factor);				\
67 	}
68 
69 #endif /* _LINUX_AVERAGE_H */
70