1*b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */ 2c5485a7eSBruno Randolf #ifndef _LINUX_AVERAGE_H 3c5485a7eSBruno Randolf #define _LINUX_AVERAGE_H 4c5485a7eSBruno Randolf 5ef4d9af6SMark Rutland #include <linux/bug.h> 6ef4d9af6SMark Rutland #include <linux/compiler.h> 7ef4d9af6SMark Rutland #include <linux/log2.h> 8ef4d9af6SMark Rutland 9eb1e011aSJohannes Berg /* 10eb1e011aSJohannes Berg * Exponentially weighted moving average (EWMA) 11eb1e011aSJohannes Berg * 12eb1e011aSJohannes Berg * This implements a fixed-precision EWMA algorithm, with both the 13eb1e011aSJohannes Berg * precision and fall-off coefficient determined at compile-time 14eb1e011aSJohannes Berg * and built into the generated helper funtions. 15eb1e011aSJohannes Berg * 16eb1e011aSJohannes Berg * The first argument to the macro is the name that will be used 17eb1e011aSJohannes Berg * for the struct and helper functions. 18eb1e011aSJohannes Berg * 19eb1e011aSJohannes Berg * The second argument, the precision, expresses how many bits are 20eb1e011aSJohannes Berg * used for the fractional part of the fixed-precision values. 21eb1e011aSJohannes Berg * 22eb1e011aSJohannes Berg * The third argument, the weight reciprocal, determines how the 23eb1e011aSJohannes Berg * new values will be weighed vs. the old state, new values will 24eb1e011aSJohannes Berg * get weight 1/weight_rcp and old values 1-1/weight_rcp. Note 25eb1e011aSJohannes Berg * that this parameter must be a power of two for efficiency. 26eb1e011aSJohannes Berg */ 27c5485a7eSBruno Randolf 28eb1e011aSJohannes Berg #define DECLARE_EWMA(name, _precision, _weight_rcp) \ 292377799cSJohannes Berg struct ewma_##name { \ 302377799cSJohannes Berg unsigned long internal; \ 312377799cSJohannes Berg }; \ 322377799cSJohannes Berg static inline void ewma_##name##_init(struct ewma_##name *e) \ 332377799cSJohannes Berg { \ 34eb1e011aSJohannes Berg BUILD_BUG_ON(!__builtin_constant_p(_precision)); \ 35eb1e011aSJohannes Berg BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \ 36eb1e011aSJohannes Berg /* \ 37eb1e011aSJohannes Berg * Even if you want to feed it just 0/1 you should have \ 38eb1e011aSJohannes Berg * some bits for the non-fractional part... \ 39eb1e011aSJohannes Berg */ \ 40eb1e011aSJohannes Berg BUILD_BUG_ON((_precision) > 30); \ 41eb1e011aSJohannes Berg BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \ 422377799cSJohannes Berg e->internal = 0; \ 432377799cSJohannes Berg } \ 442377799cSJohannes Berg static inline unsigned long \ 452377799cSJohannes Berg ewma_##name##_read(struct ewma_##name *e) \ 462377799cSJohannes Berg { \ 47eb1e011aSJohannes Berg BUILD_BUG_ON(!__builtin_constant_p(_precision)); \ 48eb1e011aSJohannes Berg BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \ 49eb1e011aSJohannes Berg BUILD_BUG_ON((_precision) > 30); \ 50eb1e011aSJohannes Berg BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \ 51eb1e011aSJohannes Berg return e->internal >> (_precision); \ 522377799cSJohannes Berg } \ 532377799cSJohannes Berg static inline void ewma_##name##_add(struct ewma_##name *e, \ 542377799cSJohannes Berg unsigned long val) \ 552377799cSJohannes Berg { \ 56ef4d9af6SMark Rutland unsigned long internal = READ_ONCE(e->internal); \ 57eb1e011aSJohannes Berg unsigned long weight_rcp = ilog2(_weight_rcp); \ 58eb1e011aSJohannes Berg unsigned long precision = _precision; \ 592377799cSJohannes Berg \ 60eb1e011aSJohannes Berg BUILD_BUG_ON(!__builtin_constant_p(_precision)); \ 61eb1e011aSJohannes Berg BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \ 62eb1e011aSJohannes Berg BUILD_BUG_ON((_precision) > 30); \ 63eb1e011aSJohannes Berg BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \ 642377799cSJohannes Berg \ 65ef4d9af6SMark Rutland WRITE_ONCE(e->internal, internal ? \ 66eb1e011aSJohannes Berg (((internal << weight_rcp) - internal) + \ 67eb1e011aSJohannes Berg (val << precision)) >> weight_rcp : \ 68ef4d9af6SMark Rutland (val << precision)); \ 692377799cSJohannes Berg } 702377799cSJohannes Berg 71c5485a7eSBruno Randolf #endif /* _LINUX_AVERAGE_H */ 72