From 838ad07c1dce27b338caba3be8ea08cf19a8ec3c Mon Sep 17 00:00:00 2001 From: Florian Grandel Date: Fri, 14 Jul 2023 23:23:15 +0200 Subject: [PATCH] kernel: introduce scalar nanosecond time representation Introduces a well-defined intermediate concept of scalar nanosecond resolution time with overflow protection above low-level counters/cycles/ticks and below higher level time abstractions (timescales, calenders, etc.). See https://github.com/zephyrproject-rtos/zephyr/issues/19030#issuecomment-1597226731 for its embedding in a larger clock subsystem architecture relevant to the network stack, IEEE 802.15.4 and the POSIX roadmap. The rationale of this type has been extensively documented and contrasted to already existing time representations to ensure that it fills a well defined gap without overlap. This change prepares for an upcoming change set that will unify the usage of time across the network subsystem (RX/TX timestamps, timed TX, CSL, scheduled reception windows, (g)PTP integration, etc.). Signed-off-by: Florian Grandel --- include/zephyr/sys/ktime.h | 138 +++++++++++++++++++++++++++++++++++++ include/zephyr/sys_clock.h | 20 +----- 2 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 include/zephyr/sys/ktime.h diff --git a/include/zephyr/sys/ktime.h b/include/zephyr/sys/ktime.h new file mode 100644 index 000000000000000..57bea9b56c6c3e8 --- /dev/null +++ b/include/zephyr/sys/ktime.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2023 Zephyr Project + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Representation and conversion of nanosecond resolution time and + * timestamps. + * + * Declare types and utilities to represent high resolution time and timers used + * by the kernel as well as by applications. + * + * Inspired by + * https://github.com/torvalds/linux/blob/master/include/linux/ktime.h and + * https://github.com/torvalds/linux/blob/master/[tools/]include/linux/time64.h + */ + +#ifndef ZEPHYR_INCLUDE_SYS_KTIME_H_ +#define ZEPHYR_INCLUDE_SYS_KTIME_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond INTERNAL_HIDDEN */ + +/** number of nsec per usec */ +#define NSEC_PER_USEC 1000U + +/** number of nsec per msec */ +#define NSEC_PER_MSEC 1000000U + +/** number of microseconds per millisecond */ +#define USEC_PER_MSEC 1000U + +/** number of milliseconds per second */ +#define MSEC_PER_SEC 1000U + +/** number of microseconds per second */ +#define USEC_PER_SEC ((USEC_PER_MSEC) * (MSEC_PER_SEC)) + +/** number of nanoseconds per second */ +#define NSEC_PER_SEC ((NSEC_PER_USEC) * (USEC_PER_MSEC) * (MSEC_PER_SEC)) + +/** @endcond */ + +/** + * @defgroup timeutil_ktime_apis Scalar Nanosecond Time Representation APIs + * @ingroup timeutil_apis + * @{ + */ + +/** + * @brief Any occurrence of ktime_t specifies a well defined concept of + * nanosecond resolution scalar time span, future (positive) or past (negative) + * relative time or absolute timestamp referred to some local nanosecond clock + * that does not wrap during uptime. + * + * @details This concept is strictly reserved for low-level scalar nanosecond + * resolution time representation. + * + * ktime_t cannot represent general clocks referred to an arbitrary epoch as it + * only covers roughly +/- ~290 years. It also cannot be used to represent time + * according to a more complex timescale (e.g. including leap seconds, time + * adjustments, complex calendars or time zones). In these cases you may use + * @ref timespec (C11, POSIX.1-2001), @ref timeval (POSIX.1-2001) or broken down + * time as in @ref tm (C90). The advantage of ktime_t over these structured time + * representations is lower memory footprint, faster and simpler scalar + * arithmetics and easier conversion from/to low-level hardware counter values. + * Also ktime_t can be used in the kernel as well as in applications while POSIX + * concepts cannot. Converting ktime_t from/to structured time representations + * is possible in a limited way but - except for @ref timespec - requires + * concepts that must be implemented by higher-level APIs. Utility functions + * converting from to @ref timespec are provided as part of the ktime_t API as + * and when needed. + * + * If you want to represent more coarse grained scalar time, use @ref time_t + * (C99, POSIX.1-2001) which is specified to represent seconds or + * @ref suseconds_t (POSIX.1-2001) for microsecond resolution. Kernel + * @ref k_ticks_t and cycles (both specific to Zephyr) have an unspecified + * resolution but are useful to represent kernel timer values and high + * resolution spinning. The advantage of ktime_t over these alternative scalar + * time representations in certain applications is obviously its higher and/or + * well-defined resolution. Any of these concepts can easily be converted + * from/to ktime_t as long as the values are within ktime_t's range. Utility + * functions for such conversions are provided as part of the ktime_t API as and + * when needed. + * + * If you need even finer grained time resolution, you may want to look at + * (g)PTP concepts, see @ref net_ptp_extended_time. + * + * A prototypical application of ktime_t would be to represent a monotonic, + * continuous low level clock source with well defined resolution and overflow + * protection above a potentially overflowing raw counter (e.g. a counter.h + * compatible driver or kernel ticks/cycles) and below high level (e.g. POSIX) + * clock, timescale or calendar representations. Another typical application is + * for high resolution timers or representation of relatively short high + * resolution time spans. + * + * The reason why we don't use int64_t directly to represent nanosecond + * resolution times is that it has been shown in the past that fields using this + * type will often not be used correctly (e.g. with the wrong resolution or to + * represent underspecified timestamp concepts with unclear semantics). + * + * Any API that exposes or consumes ktime_t values SHALL ensure that it + * maintains the specified contract and therefore clients can rely on common + * semantics of this type. This makes times coming from different hardware + * peripherals, clock sources and timer implementations comparable and therefore + * ktime_t is the ideal intermediate building block for higher-level time + * concepts. + */ +typedef int64_t ktime_t; + +/** The largest positive time value that can be represented by ktime_t */ +#define KTIME_MAX INT64_MAX + +/** The smallest negative time value that can be represented by ktime_t */ +#define KTIME_MIN INT64_MIN + +/** The largest positive number of seconds that can be safely represented by ktime_t */ +#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) + +/** The smallest negative number of seconds that can be safely represented by ktime_t */ +#define KTIME_SEC_MIN (KTIME_MIN / NSEC_PER_SEC) + +/* TODO: define conversion utilities as required in practice */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_SYS_KTIME_H_ */ diff --git a/include/zephyr/sys_clock.h b/include/zephyr/sys_clock.h index 52c88b170e98e4a..0496f5ccf84e4b5 100644 --- a/include/zephyr/sys_clock.h +++ b/include/zephyr/sys_clock.h @@ -22,6 +22,7 @@ #include #include +#include #include #ifdef __cplusplus @@ -120,25 +121,6 @@ extern void z_enable_sys_clock(void); #error "SYS_CLOCK_HW_CYCLES_PER_SEC must be non-zero!" #endif -/* number of nsec per usec */ -#define NSEC_PER_USEC 1000U - -/* number of nsec per msec */ -#define NSEC_PER_MSEC 1000000U - -/* number of microseconds per millisecond */ -#define USEC_PER_MSEC 1000U - -/* number of milliseconds per second */ -#define MSEC_PER_SEC 1000U - -/* number of microseconds per second */ -#define USEC_PER_SEC ((USEC_PER_MSEC) * (MSEC_PER_SEC)) - -/* number of nanoseconds per second */ -#define NSEC_PER_SEC ((NSEC_PER_USEC) * (USEC_PER_MSEC) * (MSEC_PER_SEC)) - - /* kernel clocks */ /*