From 50c7c7b1e4027b08a594f108df5d62bce1fc229f Mon Sep 17 00:00:00 2001 From: Krzysztof Chruscinski Date: Wed, 12 Jan 2022 10:35:38 +0100 Subject: [PATCH] sys: time_units: Add Kconfig option for algorithm selection Add maximum timeout used for conversion to Kconfig. Option is used to determine which conversion algorithm to use: faster but overflowing earlier or slower without early overflow. Signed-off-by: Krzysztof Chruscinski --- include/sys/time_units.h | 25 +++++++++++++++++++++++++ kernel/Kconfig | 11 +++++++++++ subsys/testsuite/ztest/include/ztest.h | 1 + 3 files changed, 37 insertions(+) diff --git a/include/sys/time_units.h b/include/sys/time_units.h index 1205bbdc066..0d181d1c41a 100644 --- a/include/sys/time_units.h +++ b/include/sys/time_units.h @@ -64,6 +64,21 @@ static TIME_CONSTEXPR inline int sys_clock_hw_cycles_per_sec(void) #endif } +/** @internal + * Macro determines if fast conversion algorithm can be used. It checks if + * maximum timeout represented in source frequency domain and multiplied by + * target frequency fits in 64 bits. + * + * @param from_hz Source frequency. + * @param to_hz Target frequency. + * + * @retval true Use faster algorithm. + * @retval false Use algorithm preventing overflow of intermediate value. + */ +#define Z_TMCVT_USE_FAST_ALGO(from_hz, to_hz) \ + ((ceiling_fraction(CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS * 24ULL * 3600ULL * from_hz, \ + UINT32_MAX) * to_hz) <= UINT32_MAX) + /* Time converter generator gadget. Selects from one of three * conversion algorithms: ones that take advantage when the * frequencies are an integer ratio (in either direction), or a full @@ -131,7 +146,17 @@ static TIME_CONSTEXPR ALWAYS_INLINE uint64_t z_tmcvt(uint64_t t, uint32_t from_h } else { if (result32) { return (uint32_t)((t * to_hz + off) / from_hz); + } else if (const_hz && Z_TMCVT_USE_FAST_ALGO(from_hz, to_hz)) { + /* Faster algorithm but source is first multiplied by target frequency + * and it can overflow even though final result would not overflow. + * Kconfig option shall prevent use of this algorithm when there is a + * risk of overflow. + */ + return ((t * to_hz + off) / from_hz); } else { + /* Slower algorithm but input is first divided before being multiplied + * which prevents overflow of intermediate value. + */ return (t / from_hz) * to_hz + ((t % from_hz) * to_hz + off) / from_hz; } } diff --git a/kernel/Kconfig b/kernel/Kconfig index ade29675b5e..3fbf1e8497f 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -644,6 +644,17 @@ config TIMEOUT_64BIT availability of absolute timeout values (which require the extra precision). +config SYS_CLOCK_MAX_TIMEOUT_DAYS + int "Max timeout (in days) used in conversions" + default 365 + help + Value is used in the time conversion static inline function to determine + at compile time which algorithm to use. One algorithm is faster, takes + less code but may overflow if multiplication of source and target + frequency exceeds 64 bits. Second algorithm prevents that. Faster + algorithm is selected for conversion if maximum timeout represented in + source frequency domain multiplied by target frequency fits in 64 bits. + config XIP bool "Execute in place" help diff --git a/subsys/testsuite/ztest/include/ztest.h b/subsys/testsuite/ztest/include/ztest.h index c0b5fcc92cf..6aa4306948b 100644 --- a/subsys/testsuite/ztest/include/ztest.h +++ b/subsys/testsuite/ztest/include/ztest.h @@ -38,6 +38,7 @@ #define CONFIG_MP_NUM_CPUS 1 #define CONFIG_SYS_CLOCK_TICKS_PER_SEC 100 #define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 10000000 +#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365 #define ARCH_STACK_PTR_ALIGN 8 /* FIXME: Properly integrate with Zephyr's arch specific code */ #define CONFIG_X86 1