Fist commit
This commit is contained in:
134
lib/timbre_core/SessionClock.cpp
Executable file
134
lib/timbre_core/SessionClock.cpp
Executable file
@@ -0,0 +1,134 @@
|
||||
#include "SessionClock.h"
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace timbre_core {
|
||||
|
||||
std::uint64_t SessionClock::readMonotonic() const {
|
||||
if (clock_ != nullptr) {
|
||||
return clock_->nowMs();
|
||||
}
|
||||
if (callback_) {
|
||||
return callback_();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SessionClock::setObservation(std::int64_t wallSeconds, std::uint64_t monotonicMs,
|
||||
bool first, bool regression, bool resynchronized) {
|
||||
Observation observation;
|
||||
observation.valid = CivilTime::fromUnixSeconds(wallSeconds, observation.local);
|
||||
observation.firstObservation = first;
|
||||
observation.monotonicRegression = regression;
|
||||
observation.resynchronized = resynchronized;
|
||||
observation.monotonicMs = monotonicMs;
|
||||
observation.utcEpochSeconds = wallSeconds;
|
||||
if (!observation.valid) {
|
||||
lastObservation_ = observation;
|
||||
return false;
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
if (first) {
|
||||
anchorMonotonicMs_ = monotonicMs;
|
||||
anchorWallSeconds_ = wallSeconds;
|
||||
}
|
||||
lastMonotonicMs_ = monotonicMs;
|
||||
lastWallSeconds_ = wallSeconds;
|
||||
lastLocal_ = observation.local;
|
||||
lastObservation_ = observation;
|
||||
return true;
|
||||
}
|
||||
|
||||
SessionClock::Observation SessionClock::observeAt(std::int64_t utcEpochSeconds,
|
||||
std::uint64_t monotonicMs) {
|
||||
if (!initialized_) {
|
||||
(void)setObservation(utcEpochSeconds, monotonicMs, true, false, false);
|
||||
return lastObservation_;
|
||||
}
|
||||
|
||||
if (monotonicMs < lastMonotonicMs_) {
|
||||
// A monotonic source must never run backwards. Keep the last good
|
||||
// anchor and reject the sample rather than manufacturing elapsed time.
|
||||
Observation observation = lastObservation_;
|
||||
observation.valid = false;
|
||||
observation.firstObservation = false;
|
||||
observation.monotonicRegression = true;
|
||||
observation.resynchronized = false;
|
||||
observation.monotonicMs = monotonicMs;
|
||||
lastObservation_ = observation;
|
||||
return observation;
|
||||
}
|
||||
|
||||
const std::uint64_t delta = monotonicMs - lastMonotonicMs_;
|
||||
const std::int64_t predicted = lastWallSeconds_ +
|
||||
static_cast<std::int64_t>(delta / 1000ULL);
|
||||
// A wall-clock correction is resynchronized at the current sample, never
|
||||
// expanded into a stream of historical minutes.
|
||||
const std::uint64_t difference = predicted >= utcEpochSeconds
|
||||
? static_cast<std::uint64_t>(predicted - utcEpochSeconds)
|
||||
: static_cast<std::uint64_t>(utcEpochSeconds - predicted);
|
||||
const bool resynchronized = difference > 1ULL;
|
||||
(void)setObservation(utcEpochSeconds, monotonicMs, false, false, resynchronized);
|
||||
return lastObservation_;
|
||||
}
|
||||
|
||||
SessionClock::Observation SessionClock::observe(std::int64_t utcEpochSeconds) {
|
||||
return observeAt(utcEpochSeconds, readMonotonic());
|
||||
}
|
||||
|
||||
SessionClock::Observation SessionClock::tick() {
|
||||
if (!initialized_) {
|
||||
return Observation{};
|
||||
}
|
||||
const std::uint64_t sample = readMonotonic();
|
||||
if (sample < lastMonotonicMs_) {
|
||||
Observation observation = lastObservation_;
|
||||
observation.valid = false;
|
||||
observation.firstObservation = false;
|
||||
observation.monotonicRegression = true;
|
||||
observation.resynchronized = false;
|
||||
observation.monotonicMs = sample;
|
||||
lastObservation_ = observation;
|
||||
return observation;
|
||||
}
|
||||
const std::uint64_t delta = sample - lastMonotonicMs_;
|
||||
// Do not use a platform wall clock and do not add a whole missed interval
|
||||
// to a queue. This is the monotonic, bounded session-time path.
|
||||
const std::int64_t wall = lastWallSeconds_ + static_cast<std::int64_t>(delta / 1000ULL);
|
||||
(void)setObservation(wall, sample, false, false, false);
|
||||
return lastObservation_;
|
||||
}
|
||||
|
||||
std::uint64_t SessionClock::monotonicNowMs() const {
|
||||
return readMonotonic();
|
||||
}
|
||||
|
||||
std::uint64_t SessionClock::elapsedMs() const noexcept {
|
||||
if (!initialized_) {
|
||||
return 0;
|
||||
}
|
||||
const std::uint64_t sample = monotonicNowMs();
|
||||
return sample < lastMonotonicMs_ ? 0 : sample - lastMonotonicMs_;
|
||||
}
|
||||
|
||||
std::uint64_t SessionClock::sessionElapsedMs() const noexcept {
|
||||
if (!initialized_) {
|
||||
return 0;
|
||||
}
|
||||
const std::uint64_t sample = monotonicNowMs();
|
||||
return sample < anchorMonotonicMs_ ? 0 : sample - anchorMonotonicMs_;
|
||||
}
|
||||
|
||||
void SessionClock::reset() noexcept {
|
||||
initialized_ = false;
|
||||
anchorMonotonicMs_ = 0;
|
||||
lastMonotonicMs_ = 0;
|
||||
anchorWallSeconds_ = 0;
|
||||
lastWallSeconds_ = 0;
|
||||
lastLocal_ = CivilDateTime{};
|
||||
lastObservation_ = Observation{};
|
||||
}
|
||||
|
||||
} // namespace timbre_core
|
||||
Reference in New Issue
Block a user