diff options
| author | Vaxry <vaxry@vaxry.net> | 2025-04-16 01:37:48 +0100 |
|---|---|---|
| committer | Vaxry <vaxry@vaxry.net> | 2025-04-16 01:37:48 +0100 |
| commit | 877fb5b93ada9b25b4d2f5ca5f69370fa345f1ac (patch) | |
| tree | 5b52ad19c695590ae50c7adae06b8e3aeccf34c1 /src/helpers/time/Time.cpp | |
| parent | 0e521788bcc414c9cf81648d3167757d83deb60f (diff) | |
time: move to stl's clocks and move timer
Diffstat (limited to 'src/helpers/time/Time.cpp')
| -rw-r--r-- | src/helpers/time/Time.cpp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/helpers/time/Time.cpp b/src/helpers/time/Time.cpp new file mode 100644 index 00000000..791f5ea1 --- /dev/null +++ b/src/helpers/time/Time.cpp @@ -0,0 +1,139 @@ +#include "Time.hpp" + +#define chr std::chrono +#define TIMESPEC_NSEC_PER_SEC 1000000000L + +using s_ns = std::pair<uint64_t, uint64_t>; + +// HAS to be a > b +static s_ns timediff(const s_ns& a, const s_ns& b) { + s_ns d; + + d.first = a.first - b.first; + if (a.second >= b.second) + d.second = a.second - b.second; + else { + d.second = b.second - a.second; + d.first -= 1; + } + + return d; +} + +static s_ns timeadd(const s_ns& a, const s_ns& b) { + s_ns d; + + d.first = a.first + b.first; + if (a.second + b.second >= TIMESPEC_NSEC_PER_SEC) { + d.second = a.second + b.second - TIMESPEC_NSEC_PER_SEC; + d.first += 1; + } else + d.second = a.second + b.second; + + return d; +} + +Time::steady_tp Time::steadyNow() { + return chr::steady_clock::now(); +} + +Time::system_tp Time::systemNow() { + return chr::system_clock::now(); +} + +uint64_t Time::millis(const steady_tp& tp) { + return chr::duration_cast<chr::milliseconds>(tp.time_since_epoch()).count(); +} + +s_ns Time::secNsec(const steady_tp& tp) { + const uint64_t sec = chr::duration_cast<chr::seconds>(tp.time_since_epoch()).count(); + const chr::steady_clock::duration nsecdur = tp - chr::steady_clock::time_point(chr::seconds(sec)); + return std::make_pair<>(sec, chr::duration_cast<chr::nanoseconds>(nsecdur).count()); +} + +uint64_t Time::millis(const system_tp& tp) { + return chr::duration_cast<chr::milliseconds>(tp.time_since_epoch()).count(); +} + +s_ns Time::secNsec(const system_tp& tp) { + const uint64_t sec = chr::duration_cast<chr::seconds>(tp.time_since_epoch()).count(); + const chr::steady_clock::duration nsecdur = tp - chr::system_clock::time_point(chr::seconds(sec)); + return std::make_pair<>(sec, chr::duration_cast<chr::nanoseconds>(nsecdur).count()); +} + +// TODO: this is a mess, but C++ doesn't define what steady_clock is. +// At least on Linux, system_clock == CLOCK_REALTIME +// and steady_clock == CLOCK_MONOTONIC, +// or at least it seems so with gcc and gcc's stl. +// but, since we can't *ever* be sure, we have to guess. +// In general, this may shift the time around by a couple hundred ns. Doesn't matter, realistically. + +Time::steady_tp Time::fromTimespec(const timespec* ts) { + struct timespec mono, real; + clock_gettime(CLOCK_MONOTONIC, &mono); + clock_gettime(CLOCK_REALTIME, &real); + Time::steady_tp now = Time::steadyNow(); + Time::system_tp nowSys = Time::systemNow(); + s_ns stdSteady, stdReal; + stdSteady = Time::secNsec(now); + stdReal = Time::secNsec(nowSys); + + // timespec difference, REAL - MONO + s_ns diff; + diff.first = real.tv_sec - mono.tv_sec; + if (real.tv_nsec >= mono.tv_nsec) + diff.second = real.tv_nsec - mono.tv_nsec; + else { + diff.second = mono.tv_nsec - real.tv_nsec; + diff.first -= 1; + } + + // STD difference, REAL - MONO + s_ns diff2 = timediff(stdReal, stdSteady); + + s_ns diffFinal; + s_ns monotime = {ts->tv_sec, ts->tv_nsec}; + + if (diff.first >= diff2.first || (diff.first == diff2.first && diff.second >= diff2.second)) + diffFinal = timediff(diff, diff2); + else + diffFinal = timediff(diff2, diff); + + auto sum = timeadd(monotime, diffFinal); + return chr::steady_clock::time_point(std::chrono::seconds(sum.first)) + chr::nanoseconds(sum.second); +} + +struct timespec Time::toTimespec(const steady_tp& tp) { + struct timespec mono, real; + clock_gettime(CLOCK_MONOTONIC, &mono); + clock_gettime(CLOCK_REALTIME, &real); + Time::steady_tp now = Time::steadyNow(); + Time::system_tp nowSys = Time::systemNow(); + s_ns stdSteady, stdReal; + stdSteady = Time::secNsec(now); + stdReal = Time::secNsec(nowSys); + + // timespec difference, REAL - MONO + s_ns diff; + diff.first = real.tv_sec - mono.tv_sec; + if (real.tv_nsec >= mono.tv_nsec) + diff.second = real.tv_nsec - mono.tv_nsec; + else { + diff.second = mono.tv_nsec - real.tv_nsec; + diff.first -= 1; + } + + // STD difference, REAL - MONO + s_ns diff2 = timediff(stdReal, stdSteady); + + s_ns diffFinal; + s_ns tpTime = secNsec(tp); + + if (diff.first >= diff2.first || (diff.first == diff2.first && diff.second >= diff2.second)) + diffFinal = timediff(diff, diff2); + else + diffFinal = timediff(diff2, diff); + + auto sum = timeadd(tpTime, diffFinal); + return timespec{.tv_sec = sum.first, .tv_nsec = sum.second}; +} |
