xref: /openbmc/linux/include/linux/average.h (revision ca55b2fef3a9373fcfc30f82fd26bc7fccbda732)
1 #ifndef _LINUX_AVERAGE_H
2 #define _LINUX_AVERAGE_H
3 
4 /* Exponentially weighted moving average (EWMA) */
5 
6 #define DECLARE_EWMA(name, _factor, _weight)				\
7 	struct ewma_##name {						\
8 		unsigned long internal;					\
9 	};								\
10 	static inline void ewma_##name##_init(struct ewma_##name *e)	\
11 	{								\
12 		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
13 		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
14 		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
15 		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
16 		e->internal = 0;					\
17 	}								\
18 	static inline unsigned long					\
19 	ewma_##name##_read(struct ewma_##name *e)			\
20 	{								\
21 		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
22 		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
23 		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
24 		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
25 		return e->internal >> ilog2(_factor);			\
26 	}								\
27 	static inline void ewma_##name##_add(struct ewma_##name *e,	\
28 					     unsigned long val)		\
29 	{								\
30 		unsigned long internal = ACCESS_ONCE(e->internal);	\
31 		unsigned long weight = ilog2(_weight);			\
32 		unsigned long factor = ilog2(_factor);			\
33 									\
34 		BUILD_BUG_ON(!__builtin_constant_p(_factor));		\
35 		BUILD_BUG_ON(!__builtin_constant_p(_weight));		\
36 		BUILD_BUG_ON_NOT_POWER_OF_2(_factor);			\
37 		BUILD_BUG_ON_NOT_POWER_OF_2(_weight);			\
38 									\
39 		ACCESS_ONCE(e->internal) = internal ?			\
40 			(((internal << weight) - internal) +		\
41 				(val << factor)) >> weight :		\
42 			(val << factor);				\
43 	}
44 
45 #endif /* _LINUX_AVERAGE_H */
46