aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/average.h
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2015-07-13 12:17:25 +0200
committerJohannes Berg <johannes.berg@intel.com>2015-08-14 17:49:52 +0200
commit2377799c084d86d22074cd4acd20edc32024d669 (patch)
tree1ab7ba67a7ef1a70f84808c7ac3eed8bd6c6376f /include/linux/average.h
parentmac80211_hwsim: unregister genetlink family properly (diff)
downloadlinux-dev-2377799c084d86d22074cd4acd20edc32024d669.tar.xz
linux-dev-2377799c084d86d22074cd4acd20edc32024d669.zip
average: provide macro to create static EWMA
Having the EWMA parameters stored in the runtime struct imposes memory requirements for the constant values that could just be inlined in the code. This particularly makes sense if there are a lot of such structs, for example in mac80211 in the station table where each station has a number of these in an array, and there can be many stations. Provide a macro DECLARE_EWMA() that declares the necessary struct and inline functions to access it with the parameters hard-coded; using this also means the user no longer needs to 'select AVERAGE' as it's entirely self-contained. In the mac80211 case, on x86-64, this actually slightly *reduces* code size, while also saving 80 bytes of runtime memory per sta. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'include/linux/average.h')
-rw-r--r--include/linux/average.h39
1 files changed, 39 insertions, 0 deletions
diff --git a/include/linux/average.h b/include/linux/average.h
index c6028fd742c1..60f8226c5652 100644
--- a/include/linux/average.h
+++ b/include/linux/average.h
@@ -27,4 +27,43 @@ static inline unsigned long ewma_read(const struct ewma *avg)
return avg->internal >> avg->factor;
}
+#define DECLARE_EWMA(name, _factor, _weight) \
+ struct ewma_##name { \
+ unsigned long internal; \
+ }; \
+ static inline void ewma_##name##_init(struct ewma_##name *e) \
+ { \
+ BUILD_BUG_ON(!__builtin_constant_p(_factor)); \
+ BUILD_BUG_ON(!__builtin_constant_p(_weight)); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_factor); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_weight); \
+ e->internal = 0; \
+ } \
+ static inline unsigned long \
+ ewma_##name##_read(struct ewma_##name *e) \
+ { \
+ BUILD_BUG_ON(!__builtin_constant_p(_factor)); \
+ BUILD_BUG_ON(!__builtin_constant_p(_weight)); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_factor); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_weight); \
+ return e->internal >> ilog2(_factor); \
+ } \
+ static inline void ewma_##name##_add(struct ewma_##name *e, \
+ unsigned long val) \
+ { \
+ unsigned long internal = ACCESS_ONCE(e->internal); \
+ unsigned long weight = ilog2(_weight); \
+ unsigned long factor = ilog2(_factor); \
+ \
+ BUILD_BUG_ON(!__builtin_constant_p(_factor)); \
+ BUILD_BUG_ON(!__builtin_constant_p(_weight)); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_factor); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_weight); \
+ \
+ ACCESS_ONCE(e->internal) = internal ? \
+ (((internal << weight) - internal) + \
+ (val << factor)) >> weight : \
+ (val << factor); \
+ }
+
#endif /* _LINUX_AVERAGE_H */