diff options
author | Daniil Cherednik <dan.cherednik@gmail.com> | 2023-06-15 18:24:59 +0300 |
---|---|---|
committer | Daniil Cherednik <dan.cherednik@gmail.com> | 2023-06-15 18:26:33 +0300 |
commit | 068d4453cf9fc68c875eee73f5c637bb076f6a71 (patch) | |
tree | da3e83fdb9488ea08faa39d8b41916744f9acad7 /library/cpp/time_provider/monotonic.cpp | |
parent | 7e7de263d4acbc6eacf92b618bcb5f9049bccc9b (diff) | |
download | ydb-068d4453cf9fc68c875eee73f5c637bb076f6a71.tar.gz |
Create stable-23-2 branch
x-stable-origin-commit: 3fd4d58117c143ed9e6b21813ccd9e507d2cd4d3
Diffstat (limited to 'library/cpp/time_provider/monotonic.cpp')
-rw-r--r-- | library/cpp/time_provider/monotonic.cpp | 83 |
1 files changed, 68 insertions, 15 deletions
diff --git a/library/cpp/time_provider/monotonic.cpp b/library/cpp/time_provider/monotonic.cpp index 99126080e2..f9fb6c5e19 100644 --- a/library/cpp/time_provider/monotonic.cpp +++ b/library/cpp/time_provider/monotonic.cpp @@ -1,28 +1,81 @@ #include "monotonic.h" #include <chrono> +#include <optional> +#include <system_error> +#include <util/system/platform.h> + +#ifdef _linux_ + #include <time.h> + #include <string.h> +#endif namespace NMonotonic { -namespace { -// Unfortunately time_since_epoch() is sometimes negative on wine -// Remember initial time point at program start and use offsets from that -std::chrono::steady_clock::time_point MonotonicOffset = std::chrono::steady_clock::now(); -} + namespace { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + std::optional<ui64> GetClockBootTimeMicroSeconds() { + struct timespec t; + std::optional<ui64> r; + if (0 == ::clock_gettime(CLOCK_BOOTTIME, &t)) { + r.emplace(t.tv_nsec / 1000ULL + t.tv_sec * 1000000ULL); + } + return r; + } +#endif + + struct TMonotonicSupport { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + // We remember initial offset to measure time relative to program + // start and so we never return a zero time. + std::optional<ui64> BootTimeOffset; +#endif + // Unfortunately time_since_epoch() is sometimes negative on wine + // Remember initial time point at program start and use offsets from that + std::chrono::steady_clock::time_point SteadyClockOffset; + + TMonotonicSupport() { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + BootTimeOffset = GetClockBootTimeMicroSeconds(); +#endif + SteadyClockOffset = std::chrono::steady_clock::now(); + } + + ui64 GetMicroSeconds() const { +#if defined(_linux_) && defined(CLOCK_BOOTTIME) + if (Y_LIKELY(BootTimeOffset)) { + auto r = GetClockBootTimeMicroSeconds(); + if (Y_UNLIKELY(!r)) { + throw std::system_error( + std::error_code(errno, std::system_category()), + "clock_gettime(CLOCK_BOOTTIME) failed"); + } + // Note: we add 1 so we never return zero + return *r - *BootTimeOffset + 1; + } +#endif + auto elapsed = std::chrono::steady_clock::now() - SteadyClockOffset; + auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count(); + // Steady clock is supposed to never jump backwards, but it's + // better to be safe in case of buggy implementations + if (Y_UNLIKELY(microseconds < 0)) { + microseconds = 0; + } + // Note: we add 1 so we never return zero + return ui64(microseconds) + 1; + } + }; -ui64 GetMonotonicMicroSeconds() { - auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - MonotonicOffset).count(); - // Steady clock is supposed to never jump backwards, but it's better to be safe in case of buggy implementations - if (Y_UNLIKELY(microseconds < 0)) { - microseconds = 0; + TMonotonicSupport MonotonicSupport; + } + + ui64 GetMonotonicMicroSeconds() { + return MonotonicSupport.GetMicroSeconds(); } - // Add one so we never return zero - return microseconds + 1; -} -} // namespace TMonotonic +} -template<> +template <> void Out<NMonotonic::TMonotonic>( IOutputStream& o, NMonotonic::TMonotonic t) |