2023-04-21 13:05:02

by Benjamin Beichler

[permalink] [raw]
Subject: [RFC] average: rewrite for clearity

Move the former *_add function with its implicit initialization into a
separate function, when the user explicitly wants to init with the first
added value, altough this creates issues, when 0 is a expected value for
the internal value.

Add a separate init function with value parameter to allow init with
distinct value, which was formerly done by the implicit init of old
*_add function.

Move the compile time checks into a separate macro, as they are used
multiple times and noise up the functions.

Also fix some formatting issues.

Signed-off-by: Benjamin Beichler <[email protected]>
---
include/linux/average.h | 98 ++++++++++++++++++++++++-----------------
1 file changed, 57 insertions(+), 41 deletions(-)

diff --git a/include/linux/average.h b/include/linux/average.h
index a1a8f09631ce..2e70224b84a8 100644
--- a/include/linux/average.h
+++ b/include/linux/average.h
@@ -25,47 +25,63 @@
* that this parameter must be a power of two for efficiency.
*/

-#define DECLARE_EWMA(name, _precision, _weight_rcp) \
- struct ewma_##name { \
- unsigned long internal; \
- }; \
- static inline void ewma_##name##_init(struct ewma_##name *e) \
- { \
- BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
- BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
- /* \
- * Even if you want to feed it just 0/1 you should have \
- * some bits for the non-fractional part... \
- */ \
- BUILD_BUG_ON((_precision) > 30); \
- BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
- e->internal = 0; \
- } \
- static inline unsigned long \
- ewma_##name##_read(struct ewma_##name *e) \
- { \
- BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
- BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
- BUILD_BUG_ON((_precision) > 30); \
- BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
- return e->internal >> (_precision); \
- } \
- static inline void ewma_##name##_add(struct ewma_##name *e, \
- unsigned long val) \
- { \
- unsigned long internal = READ_ONCE(e->internal); \
- unsigned long weight_rcp = ilog2(_weight_rcp); \
- unsigned long precision = _precision; \
- \
- BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
- BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
- BUILD_BUG_ON((_precision) > 30); \
- BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
- \
- WRITE_ONCE(e->internal, internal ? \
- (((internal << weight_rcp) - internal) + \
- (val << precision)) >> weight_rcp : \
- (val << precision)); \
+#define EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
+ BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
+ BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
+ /* \
+ * Even if you want to feed it just 0/1 you should have \
+ * some bits for the non-fractional part... \
+ */ \
+ BUILD_BUG_ON((_precision) > 30); \
+ BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp);
+
+
+#define DECLARE_EWMA(name, _precision, _weight_rcp) \
+ struct ewma_##name { \
+ unsigned long internal; \
+ }; \
+ static inline void ewma_##name##_init_val(struct ewma_##name *e, \
+ unsigned long init) \
+ { \
+ EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
+ e->internal = init << _precision; \
+ } \
+ static inline void ewma_##name##_init(struct ewma_##name *e) \
+ { \
+ ewma_##name##_init_val(e, 0); \
+ } \
+ static inline unsigned long \
+ ewma_##name##_read(struct ewma_##name *e) \
+ { \
+ EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
+ return e->internal >> (_precision); \
+ } \
+ static inline void ewma_##name##_add(struct ewma_##name *e, \
+ unsigned long val) \
+ { \
+ unsigned long internal = READ_ONCE(e->internal); \
+ unsigned long weight_rcp = ilog2(_weight_rcp); \
+ unsigned long precision = _precision; \
+ \
+ EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
+ \
+ WRITE_ONCE(e->internal, \
+ (((internal << weight_rcp) - internal) + \
+ (val << precision)) >> weight_rcp); \
+ } \
+ static inline void ewma_##name##_add_or_init(struct ewma_##name *e, \
+ unsigned long val) \
+ { \
+ unsigned long internal = READ_ONCE(e->internal); \
+ unsigned long weight_rcp = ilog2(_weight_rcp); \
+ unsigned long precision = _precision; \
+ \
+ EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
+ \
+ WRITE_ONCE(e->internal, internal ? \
+ (((internal << weight_rcp) - internal) + \
+ (val << precision)) >> weight_rcp : \
+ (val << precision)); \
}

#endif /* _LINUX_AVERAGE_H */
--
2.25.1


2023-04-21 13:13:17

by Benjamin Beichler

[permalink] [raw]
Subject: Re: [RFC] average: rewrite for clearity

Sorry for the crappy formatting of line endings, I have some tab/space
issues with my editor, I will fix this ...

Am 21.04.2023 um 15:00 schrieb Benjamin Beichler:
> Move the former *_add function with its implicit initialization into a
> separate function, when the user explicitly wants to init with the first
> added value, altough this creates issues, when 0 is a expected value for
> the internal value.
>
> Add a separate init function with value parameter to allow init with
> distinct value, which was formerly done by the implicit init of old
> *_add function.
>
> Move the compile time checks into a separate macro, as they are used
> multiple times and noise up the functions.
>
> Also fix some formatting issues.
>
> Signed-off-by: Benjamin Beichler <[email protected]>
> ---
> include/linux/average.h | 98 ++++++++++++++++++++++++-----------------
> 1 file changed, 57 insertions(+), 41 deletions(-)
>
> diff --git a/include/linux/average.h b/include/linux/average.h
> index a1a8f09631ce..2e70224b84a8 100644
> --- a/include/linux/average.h
> +++ b/include/linux/average.h
> @@ -25,47 +25,63 @@
> * that this parameter must be a power of two for efficiency.
> */
>
> -#define DECLARE_EWMA(name, _precision, _weight_rcp) \
> - struct ewma_##name { \
> - unsigned long internal; \
> - }; \
> - static inline void ewma_##name##_init(struct ewma_##name *e) \
> - { \
> - BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
> - BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
> - /* \
> - * Even if you want to feed it just 0/1 you should have \
> - * some bits for the non-fractional part... \
> - */ \
> - BUILD_BUG_ON((_precision) > 30); \
> - BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
> - e->internal = 0; \
> - } \
> - static inline unsigned long \
> - ewma_##name##_read(struct ewma_##name *e) \
> - { \
> - BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
> - BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
> - BUILD_BUG_ON((_precision) > 30); \
> - BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
> - return e->internal >> (_precision); \
> - } \
> - static inline void ewma_##name##_add(struct ewma_##name *e, \
> - unsigned long val) \
> - { \
> - unsigned long internal = READ_ONCE(e->internal); \
> - unsigned long weight_rcp = ilog2(_weight_rcp); \
> - unsigned long precision = _precision; \
> - \
> - BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
> - BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
> - BUILD_BUG_ON((_precision) > 30); \
> - BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp); \
> - \
> - WRITE_ONCE(e->internal, internal ? \
> - (((internal << weight_rcp) - internal) + \
> - (val << precision)) >> weight_rcp : \
> - (val << precision)); \
> +#define EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
> + BUILD_BUG_ON(!__builtin_constant_p(_precision)); \
> + BUILD_BUG_ON(!__builtin_constant_p(_weight_rcp)); \
> + /* \
> + * Even if you want to feed it just 0/1 you should have \
> + * some bits for the non-fractional part... \
> + */ \
> + BUILD_BUG_ON((_precision) > 30); \
> + BUILD_BUG_ON_NOT_POWER_OF_2(_weight_rcp);
> +
> +
> +#define DECLARE_EWMA(name, _precision, _weight_rcp) \
> + struct ewma_##name { \
> + unsigned long internal; \
> + }; \
> + static inline void ewma_##name##_init_val(struct ewma_##name *e, \
> + unsigned long init) \
> + { \
> + EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
> + e->internal = init << _precision; \
> + } \
> + static inline void ewma_##name##_init(struct ewma_##name *e) \
> + { \
> + ewma_##name##_init_val(e, 0); \
> + } \
> + static inline unsigned long \
> + ewma_##name##_read(struct ewma_##name *e) \
> + { \
> + EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
> + return e->internal >> (_precision); \
> + } \
> + static inline void ewma_##name##_add(struct ewma_##name *e, \
> + unsigned long val) \
> + { \
> + unsigned long internal = READ_ONCE(e->internal); \
> + unsigned long weight_rcp = ilog2(_weight_rcp); \
> + unsigned long precision = _precision; \
> + \
> + EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
> + \
> + WRITE_ONCE(e->internal, \
> + (((internal << weight_rcp) - internal) + \
> + (val << precision)) >> weight_rcp); \
> + } \
> + static inline void ewma_##name##_add_or_init(struct ewma_##name *e, \
> + unsigned long val) \
> + { \
> + unsigned long internal = READ_ONCE(e->internal); \
> + unsigned long weight_rcp = ilog2(_weight_rcp); \
> + unsigned long precision = _precision; \
> + \
> + EWMA_BUILD_TIME_CHECKS(_precision, _weight_rcp) \
> + \
> + WRITE_ONCE(e->internal, internal ? \
> + (((internal << weight_rcp) - internal) + \
> + (val << precision)) >> weight_rcp : \
> + (val << precision)); \
> }
>
> #endif /* _LINUX_AVERAGE_H */


--
M.Sc. Benjamin Beichler

Universität Rostock, Fakultät für Informatik und Elektrotechnik
Institut für Angewandte Mikroelektronik und Datentechnik

University of Rostock, Department of CS and EE
Institute of Applied Microelectronics and CE

Albert-Einstein-Str. 26
18059 Rostock
Deutschland/Germany

phone: +49 (0) 381 498 - 7278
email: [email protected]
www: http://www.imd.uni-rostock.de/