2020-03-02 18:16:15 +00:00
|
|
|
// Copyright 2019-2020, Collabora, Ltd.
|
2019-03-18 05:52:32 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Time-keeping: a clock that is steady, convertible to system time, and
|
|
|
|
* ideally high-resolution.
|
2020-03-02 18:16:15 +00:00
|
|
|
*
|
|
|
|
* Designed to suit the needs of OpenXR: you can and should use something
|
|
|
|
* simpler (like @ref aux_os_time) for most purposes that aren't in OpenXR
|
|
|
|
* interface code.
|
|
|
|
*
|
2019-03-18 05:52:32 +00:00
|
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*
|
|
|
|
* @see time_state
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
2021-02-24 03:50:07 +00:00
|
|
|
//! Helper define to make code more readable.
|
2022-04-12 21:21:02 +00:00
|
|
|
#define U_1_000_000_000 (1000 * 1000 * 1000)
|
2021-02-24 03:50:07 +00:00
|
|
|
|
2020-10-21 22:05:13 +00:00
|
|
|
/*!
|
|
|
|
* The number of nanoseconds in a second.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup time_ns_to_s
|
|
|
|
*/
|
2021-02-24 03:50:07 +00:00
|
|
|
#define U_TIME_1S_IN_NS U_1_000_000_000
|
|
|
|
|
|
|
|
/*!
|
2022-04-12 21:21:02 +00:00
|
|
|
* The number of nanoseconds in a millisecond.
|
2021-02-24 03:50:07 +00:00
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
*/
|
2022-04-12 21:21:02 +00:00
|
|
|
#define U_TIME_1MS_IN_NS (1000 * 1000)
|
2021-02-24 03:50:07 +00:00
|
|
|
|
|
|
|
/*!
|
2022-04-12 21:21:02 +00:00
|
|
|
* The number of nanoseconds in half a millisecond.
|
2021-02-24 03:50:07 +00:00
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
*/
|
2022-04-12 21:21:02 +00:00
|
|
|
#define U_TIME_HALF_MS_IN_NS (U_TIME_1MS_IN_NS / 2.0)
|
2020-10-21 22:05:13 +00:00
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
/*!
|
|
|
|
* Integer timestamp type.
|
|
|
|
*
|
|
|
|
* @see time_state
|
2019-03-22 15:57:18 +00:00
|
|
|
* @see time_duration_ns
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
typedef int64_t timepoint_ns;
|
|
|
|
|
2019-03-22 15:57:18 +00:00
|
|
|
/*!
|
|
|
|
* Integer duration type in nanoseconds.
|
|
|
|
*
|
|
|
|
* Logical type of timepoint differences.
|
|
|
|
*
|
|
|
|
* @see time_state
|
|
|
|
* @see timepoint_ns
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-22 15:57:18 +00:00
|
|
|
*/
|
|
|
|
typedef int64_t time_duration_ns;
|
|
|
|
|
|
|
|
/*!
|
2021-02-24 03:48:47 +00:00
|
|
|
* Convert nanoseconds duration to double seconds.
|
2019-03-22 15:57:18 +00:00
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-22 15:57:18 +00:00
|
|
|
*/
|
2021-02-24 03:48:47 +00:00
|
|
|
static inline double
|
2019-03-22 15:57:18 +00:00
|
|
|
time_ns_to_s(time_duration_ns ns)
|
|
|
|
{
|
2022-04-12 21:21:02 +00:00
|
|
|
return (double)(ns) / (double)(U_TIME_1S_IN_NS);
|
2019-03-22 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Convert float seconds to nanoseconds.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-22 15:57:18 +00:00
|
|
|
*/
|
|
|
|
static inline time_duration_ns
|
2021-01-11 17:47:04 +00:00
|
|
|
time_s_to_ns(double duration)
|
2019-03-22 15:57:18 +00:00
|
|
|
{
|
2021-02-24 03:50:07 +00:00
|
|
|
return (time_duration_ns)(duration * (double)U_TIME_1S_IN_NS);
|
2019-03-22 15:57:18 +00:00
|
|
|
}
|
|
|
|
|
2021-04-05 21:51:26 +00:00
|
|
|
/*!
|
|
|
|
* Convert nanoseconds to double float milliseconds, useful for printing.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline double
|
|
|
|
time_ns_to_ms_f(time_duration_ns ns)
|
|
|
|
{
|
2022-04-12 21:21:02 +00:00
|
|
|
return (double)(ns) / (double)(U_TIME_1MS_IN_NS);
|
2021-04-05 21:51:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Checks if two timepoints are with a certain range of each other.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
time_is_within_range_of_each_other(timepoint_ns a, timepoint_ns b, uint64_t range)
|
|
|
|
{
|
|
|
|
int64_t t = (int64_t)a - (int64_t)b;
|
|
|
|
return (-(int64_t)range < t) && (t < (int64_t)range);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Checks if two timepoints are with half a millisecond of each other.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
time_is_within_half_ms(timepoint_ns a, timepoint_ns b)
|
|
|
|
{
|
|
|
|
return time_is_within_range_of_each_other(a, b, U_TIME_HALF_MS_IN_NS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Fuzzy comparisons.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
time_is_less_then_or_within_range(timepoint_ns a, timepoint_ns b, uint64_t range)
|
|
|
|
{
|
|
|
|
return a < b || time_is_within_range_of_each_other(a, b, range);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Fuzzy comparisons.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
time_is_less_then_or_within_half_ms(timepoint_ns a, timepoint_ns b)
|
|
|
|
{
|
|
|
|
return time_is_less_then_or_within_range(a, b, U_TIME_HALF_MS_IN_NS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Fuzzy comparisons.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
time_is_greater_then_or_within_range(timepoint_ns a, timepoint_ns b, uint64_t range)
|
|
|
|
{
|
|
|
|
return a > b || time_is_within_range_of_each_other(a, b, range);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Fuzzy comparisons.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
static inline bool
|
|
|
|
time_is_greater_then_or_within_half_ms(timepoint_ns a, timepoint_ns b)
|
|
|
|
{
|
|
|
|
return time_is_greater_then_or_within_range(a, b, U_TIME_HALF_MS_IN_NS);
|
|
|
|
}
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
/*!
|
|
|
|
* @struct time_state util/u_time.h
|
|
|
|
* @brief Time-keeping state structure.
|
|
|
|
*
|
|
|
|
* Exposed as an opaque pointer.
|
|
|
|
*
|
|
|
|
* @see timepoint_ns
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
struct time_state;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Create a struct time_state.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
2019-09-29 10:43:23 +00:00
|
|
|
struct time_state *
|
2019-03-18 05:52:32 +00:00
|
|
|
time_state_create();
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Destroy a struct time_state.
|
|
|
|
*
|
|
|
|
* Should not be called simultaneously with any other time_state function.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
void
|
2019-11-15 20:30:01 +00:00
|
|
|
time_state_destroy(struct time_state **state);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Get the current time as an integer timestamp.
|
|
|
|
*
|
|
|
|
* Does not update internal state for timekeeping.
|
|
|
|
* Should not be called simultaneously with time_state_get_now_and_update.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
timepoint_ns
|
2019-09-29 10:43:23 +00:00
|
|
|
time_state_get_now(struct time_state const *state);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Get the current time as an integer timestamp and update internal state.
|
|
|
|
*
|
|
|
|
* This should be called regularly, but only from one thread.
|
|
|
|
* It updates the association between the timing sources.
|
|
|
|
*
|
|
|
|
* Should not be called simultaneously with any other time_state function.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
timepoint_ns
|
2019-09-29 10:43:23 +00:00
|
|
|
time_state_get_now_and_update(struct time_state *state);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Convert an integer timestamp to a struct timespec (system time).
|
|
|
|
*
|
|
|
|
* Should not be called simultaneously with time_state_get_now_and_update.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
void
|
2021-01-14 14:13:48 +00:00
|
|
|
time_state_to_timespec(struct time_state const *state, timepoint_ns timestamp, struct timespec *out);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Convert a struct timespec (system time) to an integer timestamp.
|
|
|
|
*
|
|
|
|
* Should not be called simultaneously with time_state_get_now_and_update.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
2019-04-06 11:28:56 +00:00
|
|
|
* @ingroup aux_util
|
2019-03-18 05:52:32 +00:00
|
|
|
*/
|
|
|
|
timepoint_ns
|
2021-01-14 14:13:48 +00:00
|
|
|
time_state_from_timespec(struct time_state const *state, const struct timespec *timespecTime);
|
2019-03-18 05:52:32 +00:00
|
|
|
|
2020-03-02 18:16:15 +00:00
|
|
|
/*!
|
|
|
|
* Convert a monotonic system time (such as from @ref aux_os_time) to an
|
|
|
|
* adjusted integer timestamp.
|
|
|
|
*
|
|
|
|
* Adjustments may need to be applied to achieve the other guarantees that e.g.
|
|
|
|
* CLOCK_MONOTONIC does not provide: this function performs those adjustments.
|
|
|
|
*
|
|
|
|
* Should not be called simultaneously with time_state_get_now_and_update.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
timepoint_ns
|
2021-01-14 14:13:48 +00:00
|
|
|
time_state_monotonic_to_ts_ns(struct time_state const *state, uint64_t monotonic_ns);
|
2020-05-26 19:09:56 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* Convert a adjusted integer timestamp to an monotonic system time (such as
|
|
|
|
* from @ref aux_os_time).
|
|
|
|
*
|
|
|
|
* Should not be called simultaneously with time_state_get_now_and_update.
|
|
|
|
*
|
|
|
|
* @public @memberof time_state
|
|
|
|
* @ingroup aux_util
|
|
|
|
*/
|
|
|
|
uint64_t
|
2021-01-14 14:13:48 +00:00
|
|
|
time_state_ts_to_monotonic_ns(struct time_state const *state, timepoint_ns timestamp);
|
2020-05-26 19:09:56 +00:00
|
|
|
|
|
|
|
|
2019-03-18 05:52:32 +00:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|