u/time: Use a very large hammer to "fix" time_state

This commit is contained in:
Jakob Bornecrantz 2020-05-26 20:09:56 +01:00
parent 18fbd3f819
commit ef41cf2088
4 changed files with 58 additions and 92 deletions

View file

@ -7,61 +7,41 @@
* @ingroup aux_util * @ingroup aux_util
*/ */
#include "u_time.h"
#include "xrt/xrt_config_os.h" #include "xrt/xrt_config_os.h"
#include "xrt/xrt_compiler.h" #include "xrt/xrt_compiler.h"
#include <chrono> #include "os/os_time.h"
#include "u_time.h"
#include <new> #include <new>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#ifdef XRT_OS_LINUX
#include <sys/time.h>
#endif
using namespace std::chrono; /*
*
struct MatchingTimePoints * Structs.
{ *
MatchingTimePoints() */
{
#ifdef XRT_OS_LINUX
clock_gettime(CLOCK_MONOTONIC, &clock_monotonic);
#endif
}
system_clock::time_point sys = system_clock::now();
steady_clock::time_point steady = steady_clock::now();
// high_resolution_clock::time_point highRes;
#ifdef XRT_OS_LINUX
struct timespec clock_monotonic;
#endif
timepoint_ns
getTimestamp(time_state const &prevState);
};
struct time_state struct time_state
{ {
MatchingTimePoints lastTimePoints = {}; // Hardcoded to one second offset.
timepoint_ns lastTime = {}; timepoint_ns offset = 1000 * 1000 * 1000;
}; };
timepoint_ns
MatchingTimePoints::getTimestamp(time_state const &prevState) /*
{ *
//! @todo right now just doing steady clock for simplicity. * 'Exported' functions.
//! @todo Eventually need to make the high-res clock steady. *
auto elapsed = steady - prevState.lastTimePoints.steady; */
return prevState.lastTime + duration_cast<nanoseconds>(elapsed).count();
}
extern "C" struct time_state * extern "C" struct time_state *
time_state_create() time_state_create()
{ {
time_state *state = new (std::nothrow) time_state; time_state *state = new (std::nothrow) time_state;
return state; return state;
} }
@ -83,24 +63,16 @@ extern "C" timepoint_ns
time_state_get_now(struct time_state const *state) time_state_get_now(struct time_state const *state)
{ {
assert(state != NULL); assert(state != NULL);
auto now = MatchingTimePoints();
return now.getTimestamp(*state); return time_state_monotonic_to_ts_ns(state, os_monotonic_get_ns());
} }
extern "C" timepoint_ns extern "C" timepoint_ns
time_state_get_now_and_update(struct time_state *state) time_state_get_now_and_update(struct time_state *state)
{ {
assert(state != NULL); assert(state != NULL);
auto now = MatchingTimePoints();
auto timestamp = now.getTimestamp(*state); return time_state_get_now(state);
// Update the state
state->lastTimePoints = now;
state->lastTime = timestamp;
return timestamp;
} }
extern "C" void extern "C" void
@ -110,60 +82,39 @@ time_state_to_timespec(struct time_state const *state,
{ {
assert(state != NULL); assert(state != NULL);
assert(out != NULL); assert(out != NULL);
// Subject to some jitter, roughly up to the magnitude of the actual
// resolution difference between the used time source and the system
// clock, as well as the non-simultaneity of the calls in
// MatchingTimePoints::getNow()
auto sinceLastUpdate = nanoseconds{timestamp - state->lastTime};
auto equivSystemTimepoint = state->lastTimePoints.sys + sinceLastUpdate;
// System clock epoch is same as unix epoch for all known uint64_t ns = time_state_ts_to_monotonic_ns(state, timestamp);
// implementations, but not strictly standard-required yet, see
// wg21.link/p0355 out->tv_sec = ns / (1000 * 1000 * 1000);
auto sinceEpoch = equivSystemTimepoint.time_since_epoch(); out->tv_nsec = ns % (1000 * 1000 * 1000);
auto secondsSinceEpoch = duration_cast<seconds>(sinceEpoch);
sinceEpoch -= secondsSinceEpoch;
out->tv_sec = secondsSinceEpoch.count();
out->tv_nsec = duration_cast<nanoseconds>(sinceEpoch).count();
} }
extern "C" timepoint_ns extern "C" timepoint_ns
time_state_from_timespec(struct time_state const *state, time_state_from_timespec(struct time_state const *state,
const struct timespec *timespecTime) const struct timespec *timespecTime)
{ {
assert(state != NULL); assert(state != NULL);
assert(timespecTime != NULL); assert(timespecTime != NULL);
auto sinceEpoch =
seconds{timespecTime->tv_sec} + nanoseconds{timespecTime->tv_nsec};
uint64_t ns = 0;
ns += timespecTime->tv_nsec;
ns += timespecTime->tv_sec * 1000 * 1000 * 1000;
// System clock epoch is same as unix epoch for all known return time_state_monotonic_to_ts_ns(state, ns);
// implementations, but not strictly standard-required yet, see
// wg21.link/p0355
auto systemTimePoint = time_point<system_clock, nanoseconds>{
duration_cast<system_clock::duration>(sinceEpoch)};
// duration between last update and the supplied timespec
auto sinceLastUpdate = state->lastTimePoints.sys - systemTimePoint;
// Offset the last timestamp by that duration.
return state->lastTime +
duration_cast<nanoseconds>(sinceLastUpdate).count();
} }
extern "C" timepoint_ns
timepoint_ns time_state_monotonic_to_ts_ns(struct time_state const *state,
time_state_from_monotonic_ns(struct time_state const *state, uint64_t monotonic_ns)
uint64_t monotonic_ns)
{ {
assert(state != NULL); assert(state != NULL);
auto sinceLastUpdate =
seconds{state->lastTimePoints.clock_monotonic.tv_sec} +
nanoseconds{state->lastTimePoints.clock_monotonic.tv_nsec} -
nanoseconds{monotonic_ns};
// Offset the last timestamp by that duration. return monotonic_ns + state->offset;
return state->lastTime + }
duration_cast<nanoseconds>(sinceLastUpdate).count();
extern "C" uint64_t
time_state_ts_to_monotonic_ns(struct time_state const *state,
timepoint_ns timestamp)
{
return timestamp - state->offset;
} }

View file

@ -164,8 +164,23 @@ time_state_from_timespec(struct time_state const *state,
* @ingroup aux_util * @ingroup aux_util
*/ */
timepoint_ns timepoint_ns
time_state_from_monotonic_ns(struct time_state const *state, time_state_monotonic_to_ts_ns(struct time_state const *state,
uint64_t monotonic_ns); uint64_t monotonic_ns);
/*!
* 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
time_state_ts_to_monotonic_ns(struct time_state const *state,
timepoint_ns timestamp);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -407,13 +407,13 @@ oxr_session_frame_wait(struct oxr_logger *log,
frameState->shouldRender = should_render(sess->state); frameState->shouldRender = should_render(sess->state);
frameState->predictedDisplayPeriod = predicted_display_period; frameState->predictedDisplayPeriod = predicted_display_period;
frameState->predictedDisplayTime = time_state_from_monotonic_ns( frameState->predictedDisplayTime = time_state_monotonic_to_ts_ns(
sess->sys->inst->timekeeping, predicted_display_time); sess->sys->inst->timekeeping, predicted_display_time);
if (frameState->predictedDisplayTime <= 0) { if (frameState->predictedDisplayTime <= 0) {
return oxr_error( return oxr_error(
log, XR_ERROR_RUNTIME_FAILURE, log, XR_ERROR_RUNTIME_FAILURE,
" time_state_from_monotonic_ns returned '%" PRIi64 "'", " time_state_monotonic_to_ts_ns returned '%" PRIi64 "'",
frameState->predictedDisplayTime); frameState->predictedDisplayTime);
} }

View file

@ -129,7 +129,7 @@ oxr_xdev_get_relation_at(struct oxr_logger *log,
// Always make those to base things valid. // Always make those to base things valid.
ensure_valid_position_and_orientation(&relation, offset); ensure_valid_position_and_orientation(&relation, offset);
*out_relation_timestamp_ns = time_state_from_monotonic_ns( *out_relation_timestamp_ns = time_state_monotonic_to_ts_ns(
inst->timekeeping, relation_timestamp_ns); inst->timekeeping, relation_timestamp_ns);
*out_relation = relation; *out_relation = relation;