2022-05-17 19:34:53 +00:00
|
|
|
// Copyright 2019-2022, Collabora, Ltd.
|
2019-09-24 13:43:21 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Wrapper around OS native time functions.
|
2020-03-02 19:59:06 +00:00
|
|
|
*
|
|
|
|
* These should be preferred over directly using native OS time functions in
|
|
|
|
* potentially-portable code. Additionally, in most cases these are preferred
|
|
|
|
* over timepoints from @ref time_state for general usage in drivers, etc.
|
|
|
|
*
|
2019-09-24 13:43:21 +00:00
|
|
|
* @author Drew DeVault <sir@cmpwn.com>
|
2020-03-02 18:09:56 +00:00
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
2022-05-17 19:34:53 +00:00
|
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
2019-09-24 13:43:21 +00:00
|
|
|
*
|
|
|
|
* @ingroup aux_os
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2020-03-02 15:44:00 +00:00
|
|
|
#include "xrt/xrt_config_os.h"
|
2019-09-24 13:43:21 +00:00
|
|
|
#include "xrt/xrt_compiler.h"
|
|
|
|
|
2020-10-21 22:04:44 +00:00
|
|
|
#include "util/u_time.h"
|
|
|
|
|
2019-09-24 13:43:21 +00:00
|
|
|
#ifdef XRT_OS_LINUX
|
|
|
|
#include <time.h>
|
2020-02-27 13:53:03 +00:00
|
|
|
#include <sys/time.h>
|
2020-03-02 18:09:56 +00:00
|
|
|
#define XRT_HAVE_TIMESPEC
|
|
|
|
#define XRT_HAVE_TIMEVAL
|
|
|
|
|
2020-07-15 13:49:49 +00:00
|
|
|
#elif defined(XRT_OS_WINDOWS)
|
|
|
|
#include <time.h>
|
|
|
|
#define XRT_HAVE_TIMESPEC
|
|
|
|
|
2020-03-02 18:09:56 +00:00
|
|
|
#elif defined(XRT_DOXYGEN)
|
|
|
|
#include <time.h>
|
|
|
|
#define XRT_HAVE_TIMESPEC
|
|
|
|
#define XRT_HAVE_TIMEVAL
|
|
|
|
|
2019-09-24 13:43:21 +00:00
|
|
|
#else
|
|
|
|
#error "No time support on non-Linux platforms yet."
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2020-03-02 18:09:56 +00:00
|
|
|
/*!
|
|
|
|
* @defgroup aux_os_time Portable Timekeeping
|
|
|
|
* @ingroup aux_os
|
|
|
|
*
|
|
|
|
* @brief Unifying wrapper around system time retrieval functions.
|
|
|
|
*/
|
|
|
|
|
2020-02-27 13:53:03 +00:00
|
|
|
|
2019-09-24 13:43:21 +00:00
|
|
|
/*!
|
2020-03-02 18:09:56 +00:00
|
|
|
* @defgroup aux_os_time_extra Extra Timekeeping Utilities
|
|
|
|
* @ingroup aux_os_time
|
|
|
|
*
|
|
|
|
* @brief Less-portable utility functions for manipulating system time, for
|
|
|
|
* interoperation with platform APIs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
2022-05-17 19:34:53 +00:00
|
|
|
* Return a monotonic clock in nanoseconds.
|
|
|
|
* @ingroup aux_os_time
|
|
|
|
*/
|
|
|
|
static inline uint64_t
|
|
|
|
os_monotonic_get_ns(void);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Sleep the given number of nanoseconds.
|
2021-03-30 16:20:01 +00:00
|
|
|
*
|
|
|
|
* Note that on some platforms, this may be somewhat less accurate than you might want.
|
|
|
|
* On all platforms, the system scheduler has the final say.
|
|
|
|
*
|
2022-05-17 19:34:53 +00:00
|
|
|
* @see os_precise_sleeper
|
|
|
|
*
|
2020-03-02 18:09:56 +00:00
|
|
|
* @ingroup aux_os_time
|
2019-09-24 13:43:21 +00:00
|
|
|
*/
|
2020-03-02 20:01:18 +00:00
|
|
|
static inline void
|
2022-05-17 19:34:53 +00:00
|
|
|
os_nanosleep(int64_t nsec);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* A structure for storing state as needed for more precise sleeping, mostly for compositor use.
|
|
|
|
* @ingroup aux_os_time
|
|
|
|
*/
|
|
|
|
struct os_precise_sleeper;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Initialize members of @ref os_precise_sleeper.
|
|
|
|
* @public @memberof os_precise_sleeper
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
os_precise_sleeper_init(struct os_precise_sleeper *ops);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* De-initialize members of @ref os_precise_sleeper, and free resources, without actually freeing the given
|
|
|
|
* pointer.
|
|
|
|
* @public @memberof os_precise_sleeper
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
os_precise_sleeper_deinit(struct os_precise_sleeper *ops);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Sleep the given number of nanoseconds, trying harder to be precise.
|
|
|
|
*
|
|
|
|
* On some platforms, there is no way to improve sleep precision easily with some OS-specific state, so we forward
|
|
|
|
* to os_nanosleep().
|
|
|
|
*
|
|
|
|
* Note that on all platforms, the system scheduler has the final say.
|
|
|
|
*
|
|
|
|
* @public @memberof os_precise_sleeper
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
os_precise_sleeper_nanosleep(struct os_precise_sleeper *ops, int32_t nsec);
|
|
|
|
|
|
|
|
#if defined(XRT_HAVE_TIMESPEC) || defined(XRT_DOXYGEN)
|
|
|
|
/*!
|
|
|
|
* Convert a timespec struct to nanoseconds.
|
|
|
|
*
|
|
|
|
* Note that this only does the value combining, no adjustment for epochs is performed.
|
|
|
|
*
|
|
|
|
* @ingroup aux_os_time_extra
|
|
|
|
*/
|
|
|
|
static inline uint64_t
|
|
|
|
os_timespec_to_ns(const struct timespec *spec);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Convert an nanosecond integer to a timespec struct.
|
|
|
|
*
|
|
|
|
* Note that this only does the value splitting, no adjustment for epochs is performed.
|
|
|
|
* @ingroup aux_os_time_extra
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
os_ns_to_timespec(uint64_t ns, struct timespec *spec);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(XRT_HAVE_TIMEVAL) || defined(XRT_DOXYGEN)
|
|
|
|
/*!
|
|
|
|
* Convert a timeval struct to nanoseconds.
|
|
|
|
* @ingroup aux_os_time_extra
|
|
|
|
*/
|
|
|
|
static inline uint64_t
|
|
|
|
os_timeval_to_ns(struct timeval *val);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(XRT_OS_LINUX) || defined(XRT_DOXYGEN)
|
|
|
|
/*!
|
|
|
|
* Return a realtime clock in nanoseconds (Linux-only)
|
|
|
|
*
|
|
|
|
* @ingroup aux_os_time_extra
|
|
|
|
*/
|
|
|
|
static inline uint64_t
|
|
|
|
os_realtime_get_ns(void);
|
|
|
|
#endif
|
|
|
|
|
2022-04-27 03:06:59 +00:00
|
|
|
#if defined(XRT_OS_WINDOWS) || defined(XRT_DOXYGEN)
|
|
|
|
/*!
|
|
|
|
* @brief Return a qpc freq in nanoseconds.
|
|
|
|
* @ingroup aux_os_time
|
|
|
|
*/
|
|
|
|
static inline int64_t
|
|
|
|
os_ns_per_qpc_tick_get();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2022-05-17 19:34:53 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* implementations follow
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static inline void
|
2021-10-24 01:25:56 +00:00
|
|
|
os_nanosleep(int64_t nsec)
|
2019-09-24 13:43:21 +00:00
|
|
|
{
|
2020-07-15 17:19:44 +00:00
|
|
|
#if defined(XRT_OS_LINUX)
|
2020-04-16 12:22:57 +00:00
|
|
|
struct timespec spec;
|
2020-10-21 22:04:44 +00:00
|
|
|
spec.tv_sec = (nsec / U_1_000_000_000);
|
|
|
|
spec.tv_nsec = (nsec % U_1_000_000_000);
|
2020-09-07 13:25:00 +00:00
|
|
|
nanosleep(&spec, NULL);
|
2020-07-15 17:19:44 +00:00
|
|
|
#elif defined(XRT_OS_WINDOWS)
|
2022-04-12 19:23:54 +00:00
|
|
|
Sleep((DWORD)(nsec / U_TIME_1MS_IN_NS));
|
2019-09-24 13:43:21 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-03-30 16:20:39 +00:00
|
|
|
struct os_precise_sleeper
|
|
|
|
{
|
|
|
|
#if defined(XRT_OS_WINDOWS)
|
|
|
|
HANDLE timer;
|
|
|
|
#else
|
|
|
|
int unused_;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
os_precise_sleeper_init(struct os_precise_sleeper *ops)
|
|
|
|
{
|
|
|
|
#if defined(XRT_OS_WINDOWS)
|
|
|
|
ops->timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
os_precise_sleeper_deinit(struct os_precise_sleeper *ops)
|
|
|
|
{
|
|
|
|
#if defined(XRT_OS_WINDOWS)
|
|
|
|
if (ops->timer) {
|
|
|
|
CloseHandle(ops->timer);
|
|
|
|
ops->timer = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
os_precise_sleeper_nanosleep(struct os_precise_sleeper *ops, int32_t nsec)
|
|
|
|
{
|
|
|
|
#if defined(XRT_OS_WINDOWS)
|
|
|
|
if (ops->timer) {
|
|
|
|
LARGE_INTEGER timeperiod;
|
2021-08-16 17:43:52 +00:00
|
|
|
timeperiod.QuadPart = -(nsec / 100);
|
2021-03-30 16:20:39 +00:00
|
|
|
if (SetWaitableTimer(ops->timer, &timeperiod, 0, NULL, NULL, FALSE)) {
|
|
|
|
// OK we could set up the timer, now let's wait.
|
|
|
|
WaitForSingleObject(ops->timer, INFINITE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2022-05-17 21:58:36 +00:00
|
|
|
// If we fall through from an implementation, or there's no implementation needed for a platform, we
|
2021-03-30 16:20:39 +00:00
|
|
|
// delegate to the regular os_nanosleep.
|
|
|
|
os_nanosleep(nsec);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(XRT_HAVE_TIMESPEC)
|
2020-03-02 20:01:18 +00:00
|
|
|
static inline uint64_t
|
2020-08-17 14:42:30 +00:00
|
|
|
os_timespec_to_ns(const struct timespec *spec)
|
2020-02-27 13:53:03 +00:00
|
|
|
{
|
|
|
|
uint64_t ns = 0;
|
2020-10-21 22:04:44 +00:00
|
|
|
ns += (uint64_t)spec->tv_sec * U_1_000_000_000;
|
2020-02-27 13:53:03 +00:00
|
|
|
ns += (uint64_t)spec->tv_nsec;
|
|
|
|
return ns;
|
|
|
|
}
|
2020-06-23 17:01:13 +00:00
|
|
|
|
|
|
|
static inline void
|
|
|
|
os_ns_to_timespec(uint64_t ns, struct timespec *spec)
|
|
|
|
{
|
2020-10-21 22:04:44 +00:00
|
|
|
spec->tv_sec = (ns / U_1_000_000_000);
|
|
|
|
spec->tv_nsec = (ns % U_1_000_000_000);
|
2020-06-23 17:01:13 +00:00
|
|
|
}
|
2020-03-02 18:09:56 +00:00
|
|
|
#endif // XRT_HAVE_TIMESPEC
|
|
|
|
|
2020-02-27 13:53:03 +00:00
|
|
|
|
2021-03-30 16:53:10 +00:00
|
|
|
#if defined(XRT_HAVE_TIMEVAL) && defined(XRT_OS_LINUX)
|
|
|
|
|
|
|
|
#define OS_NS_PER_USEC (1000)
|
|
|
|
|
2020-03-02 20:01:18 +00:00
|
|
|
static inline uint64_t
|
2020-02-27 13:53:03 +00:00
|
|
|
os_timeval_to_ns(struct timeval *val)
|
|
|
|
{
|
|
|
|
uint64_t ns = 0;
|
2020-10-21 22:04:44 +00:00
|
|
|
ns += (uint64_t)val->tv_sec * U_1_000_000_000;
|
|
|
|
ns += (uint64_t)val->tv_usec * OS_NS_PER_USEC;
|
2020-02-27 13:53:03 +00:00
|
|
|
return ns;
|
|
|
|
}
|
2022-05-17 19:34:53 +00:00
|
|
|
#endif // defined(XRT_HAVE_TIMEVAL) && defined(XRT_OS_LINUX)
|
|
|
|
|
2022-04-27 03:06:59 +00:00
|
|
|
#if defined(XRT_OS_WINDOWS)
|
|
|
|
static inline int64_t
|
|
|
|
os_ns_per_qpc_tick_get()
|
|
|
|
{
|
|
|
|
static int64_t ns_per_qpc_tick = 0;
|
|
|
|
if (ns_per_qpc_tick == 0) {
|
|
|
|
// Fixed at startup, so we can cache this.
|
|
|
|
LARGE_INTEGER freq;
|
|
|
|
QueryPerformanceFrequency(&freq);
|
|
|
|
ns_per_qpc_tick = U_1_000_000_000 / freq.QuadPart;
|
|
|
|
}
|
|
|
|
return ns_per_qpc_tick;
|
|
|
|
}
|
|
|
|
#endif // defined(XRT_OS_WINDOWS)
|
2020-03-02 18:09:56 +00:00
|
|
|
|
2020-03-02 20:01:18 +00:00
|
|
|
static inline uint64_t
|
2020-02-27 13:53:03 +00:00
|
|
|
os_monotonic_get_ns(void)
|
|
|
|
{
|
2021-03-30 16:19:41 +00:00
|
|
|
#if defined(XRT_OS_LINUX)
|
2020-02-27 13:53:03 +00:00
|
|
|
struct timespec ts;
|
|
|
|
int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
|
|
if (ret != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return os_timespec_to_ns(&ts);
|
2021-03-30 16:19:41 +00:00
|
|
|
#elif defined(XRT_OS_WINDOWS)
|
|
|
|
LARGE_INTEGER qpc;
|
|
|
|
QueryPerformanceCounter(&qpc);
|
2022-04-27 03:06:59 +00:00
|
|
|
return qpc.QuadPart * os_ns_per_qpc_tick_get();
|
2021-03-30 16:19:41 +00:00
|
|
|
#else
|
|
|
|
#error "need port"
|
2020-02-27 13:53:03 +00:00
|
|
|
#endif
|
2020-03-02 18:09:56 +00:00
|
|
|
}
|
2020-02-27 13:53:03 +00:00
|
|
|
|
2020-08-17 14:43:35 +00:00
|
|
|
#ifdef XRT_OS_LINUX
|
|
|
|
static inline uint64_t
|
|
|
|
os_realtime_get_ns(void)
|
|
|
|
{
|
|
|
|
struct timespec ts;
|
|
|
|
int ret = clock_gettime(CLOCK_REALTIME, &ts);
|
|
|
|
if (ret != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return os_timespec_to_ns(&ts);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-02-27 13:53:03 +00:00
|
|
|
|
2019-09-24 13:43:21 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|