Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _LINUX_AVERAGE_H
0003 #define _LINUX_AVERAGE_H
0004 
0005 #include <linux/bug.h>
0006 #include <linux/compiler.h>
0007 #include <linux/log2.h>
0008 
0009 /*
0010  * Exponentially weighted moving average (EWMA)
0011  *
0012  * This implements a fixed-precision EWMA algorithm, with both the
0013  * precision and fall-off coefficient determined at compile-time
0014  * and built into the generated helper funtions.
0015  *
0016  * The first argument to the macro is the name that will be used
0017  * for the struct and helper functions.
0018  *
0019  * The second argument, the precision, expresses how many bits are
0020  * used for the fractional part of the fixed-precision values.
0021  *
0022  * The third argument, the weight reciprocal, determines how the
0023  * new values will be weighed vs. the old state, new values will
0024  * get weight 1/weight_rcp and old values 1-1/weight_rcp. Note
0025  * that this parameter must be a power of two for efficiency.
0026  */
0027 
0028 #define DECLARE_EWMA(name, _precision, _weight_rcp)         \
0029     struct ewma_##name {                        \
0030         unsigned long internal;                 \
0031     };                              \
0032     static inline void ewma_##name##_init(struct ewma_##name *e)    \
0033     {                               \
0034         BUILD_BUG_ON(!__builtin_constant_p(_precision));    \
0035         BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp));   \
0036         /*                          \
0037          * Even if you want to feed it just 0/1 you should have \
0038          * some bits for the non-fractional part...     \
0039          */                         \
0040         BUILD_BUG_ON((_precision) > 30);            \
0041         BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp);       \
0042         e->internal = 0;                    \
0043     }                               \
0044     static inline unsigned long                 \
0045     ewma_##name##_read(struct ewma_##name *e)           \
0046     {                               \
0047         BUILD_BUG_ON(!__builtin_constant_p(_precision));    \
0048         BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp));   \
0049         BUILD_BUG_ON((_precision) > 30);            \
0050         BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp);       \
0051         return e->internal >> (_precision);         \
0052     }                               \
0053     static inline void ewma_##name##_add(struct ewma_##name *e, \
0054                          unsigned long val)     \
0055     {                               \
0056         unsigned long internal = READ_ONCE(e->internal);    \
0057         unsigned long weight_rcp = ilog2(_weight_rcp);      \
0058         unsigned long precision = _precision;           \
0059                                     \
0060         BUILD_BUG_ON(!__builtin_constant_p(_precision));    \
0061         BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp));   \
0062         BUILD_BUG_ON((_precision) > 30);            \
0063         BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp);       \
0064                                     \
0065         WRITE_ONCE(e->internal, internal ?          \
0066             (((internal << weight_rcp) - internal) +    \
0067                 (val << precision)) >> weight_rcp : \
0068             (val << precision));                \
0069     }
0070 
0071 #endif /* _LINUX_AVERAGE_H */