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 | |
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')
-rw-r--r-- | library/cpp/time_provider/monotonic.cpp | 83 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic.h | 197 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic_provider.cpp | 44 | ||||
-rw-r--r-- | library/cpp/time_provider/monotonic_provider.h | 28 | ||||
-rw-r--r-- | library/cpp/time_provider/time_provider.cpp | 2 |
5 files changed, 213 insertions, 141 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) diff --git a/library/cpp/time_provider/monotonic.h b/library/cpp/time_provider/monotonic.h index e36902d884..a1258e3342 100644 --- a/library/cpp/time_provider/monotonic.h +++ b/library/cpp/time_provider/monotonic.h @@ -1,111 +1,124 @@ #pragma once #include <util/datetime/base.h> -namespace NMonotonic { -/** - * Returns current monotonic time in microseconds - */ -ui64 GetMonotonicMicroSeconds(); - -/** - * Similar to TInstant, but measuring monotonic time - */ -class TMonotonic: public TTimeBase<TMonotonic> { - using TBase = TTimeBase<TMonotonic>; - -private: - constexpr explicit TMonotonic(TValue value) noexcept - : TBase(value) { - } - -public: - constexpr TMonotonic() noexcept { - } - - static constexpr TMonotonic FromValue(TValue value) noexcept { - return TMonotonic(value); - } - - static inline TMonotonic Now() { - return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds()); - } - - using TBase::Days; - using TBase::Hours; - using TBase::MicroSeconds; - using TBase::MilliSeconds; - using TBase::Minutes; - using TBase::Seconds; - static constexpr TMonotonic Max() noexcept { - return TMonotonic(::Max<ui64>()); - } - - static constexpr TMonotonic Zero() noexcept { - return TMonotonic(); - } - - static constexpr TMonotonic MicroSeconds(ui64 us) noexcept { - return TMonotonic(TInstant::MicroSeconds(us).GetValue()); - } - - static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept { - return TMonotonic(TInstant::MilliSeconds(ms).GetValue()); - } - - static constexpr TMonotonic Seconds(ui64 s) noexcept { - return TMonotonic(TInstant::Seconds(s).GetValue()); - } - - static constexpr TMonotonic Minutes(ui64 m) noexcept { - return TMonotonic(TInstant::Minutes(m).GetValue()); - } - - static constexpr TMonotonic Hours(ui64 h) noexcept { - return TMonotonic(TInstant::Hours(h).GetValue()); - } - - static constexpr TMonotonic Days(ui64 d) noexcept { - return TMonotonic(TInstant::Days(d).GetValue()); - } +namespace NMonotonic { - template<class T> - inline TMonotonic& operator+=(const T& t) noexcept { - return (*this = (*this + t)); - } + /** + * Returns current monotonic time in microseconds + * + * On Linux uses CLOCK_BOOTTIME under the hood, so it includes time passed + * during suspend and makes it safe for measuring lease times. + */ + ui64 GetMonotonicMicroSeconds(); + + /** + * Similar to TInstant, but measuring monotonic time + * + * On Linux uses CLOCK_BOOTTIME under the hood, so it includes time passed + * during suspend and makes it safe for measuring lease times. + */ + class TMonotonic: public TTimeBase<TMonotonic> { + using TBase = TTimeBase<TMonotonic>; + + protected: + constexpr explicit TMonotonic(TValue value) noexcept + : TBase(value) + { + } + + public: + constexpr TMonotonic() noexcept { + } + + static constexpr TMonotonic FromValue(TValue value) noexcept { + return TMonotonic(value); + } + + static inline TMonotonic Now() { + return TMonotonic::MicroSeconds(GetMonotonicMicroSeconds()); + } + + using TBase::Days; + using TBase::Hours; + using TBase::MicroSeconds; + using TBase::MilliSeconds; + using TBase::Minutes; + using TBase::Seconds; + + static constexpr TMonotonic Max() noexcept { + return TMonotonic::FromValue(::Max<ui64>()); + } + + static constexpr TMonotonic Zero() noexcept { + return TMonotonic::FromValue(0); + } + + static constexpr TMonotonic MicroSeconds(ui64 us) noexcept { + return TMonotonic::FromValue(TInstant::MicroSeconds(us).GetValue()); + } + + static constexpr TMonotonic MilliSeconds(ui64 ms) noexcept { + return TMonotonic::FromValue(TInstant::MilliSeconds(ms).GetValue()); + } + + static constexpr TMonotonic Seconds(ui64 s) noexcept { + return TMonotonic::FromValue(TInstant::Seconds(s).GetValue()); + } + + static constexpr TMonotonic Minutes(ui64 m) noexcept { + return TMonotonic::FromValue(TInstant::Minutes(m).GetValue()); + } + + static constexpr TMonotonic Hours(ui64 h) noexcept { + return TMonotonic::FromValue(TInstant::Hours(h).GetValue()); + } + + static constexpr TMonotonic Days(ui64 d) noexcept { + return TMonotonic::FromValue(TInstant::Days(d).GetValue()); + } + + template <class T> + inline TMonotonic& operator+=(const T& t) noexcept { + return (*this = (*this + t)); + } + + template <class T> + inline TMonotonic& operator-=(const T& t) noexcept { + return (*this = (*this - t)); + } + }; - template<class T> - inline TMonotonic& operator-=(const T& t) noexcept { - return (*this = (*this - t)); - } -}; } // namespace NMonotonic Y_DECLARE_PODTYPE(NMonotonic::TMonotonic); -template<> -struct THash<NMonotonic::TMonotonic> { - size_t operator()(const NMonotonic::TMonotonic& key) const { - return THash<NMonotonic::TMonotonic::TValue>()(key.GetValue()); - } -}; +namespace std { + template <> + struct hash<NMonotonic::TMonotonic> { + size_t operator()(const NMonotonic::TMonotonic& key) const noexcept { + return hash<NMonotonic::TMonotonic::TValue>()(key.GetValue()); + } + }; +} namespace NMonotonic { -constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) { - return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue()); -} + constexpr TDuration operator-(const TMonotonic& l, const TMonotonic& r) { + return TInstant::FromValue(l.GetValue()) - TInstant::FromValue(r.GetValue()); + } -constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) { - TInstant result = TInstant::FromValue(l.GetValue()) + r; - return TMonotonic::FromValue(result.GetValue()); -} + constexpr TMonotonic operator+(const TMonotonic& l, const TDuration& r) { + TInstant result = TInstant::FromValue(l.GetValue()) + r; + return TMonotonic::FromValue(result.GetValue()); + } -constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) { - TInstant result = TInstant::FromValue(l.GetValue()) - r; - return TMonotonic::FromValue(result.GetValue()); -} + constexpr TMonotonic operator-(const TMonotonic& l, const TDuration& r) { + TInstant result = TInstant::FromValue(l.GetValue()) - r; + return TMonotonic::FromValue(result.GetValue()); + } } // namespace NMonotonic +// TODO: remove, alias for compatibility using TMonotonic = NMonotonic::TMonotonic; diff --git a/library/cpp/time_provider/monotonic_provider.cpp b/library/cpp/time_provider/monotonic_provider.cpp index 22937bd873..6b116a0e73 100644 --- a/library/cpp/time_provider/monotonic_provider.cpp +++ b/library/cpp/time_provider/monotonic_provider.cpp @@ -1,32 +1,32 @@ #include "monotonic_provider.h" -namespace { -TIntrusivePtr<IMonotonicTimeProvider> GlobalMonotonicTimeProvider; -} - -void TMonotonicOperator::RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider) { - GlobalMonotonicTimeProvider = provider; -} +namespace NMonotonic { -NMonotonic::TMonotonic TMonotonicOperator::Now() { - if (GlobalMonotonicTimeProvider) { - return GlobalMonotonicTimeProvider->Now(); - } else { - return TMonotonic::Now(); + namespace { + TIntrusivePtr<IMonotonicTimeProvider> GlobalMonotonicTimeProvider; } -} -namespace NMonotonic { + void TMonotonicOperator::RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider) { + GlobalMonotonicTimeProvider = provider; + } -class TDefaultMonotonicTimeProvider: public IMonotonicTimeProvider { -public: - TMonotonic Now() override { - return TMonotonic::Now(); + NMonotonic::TMonotonic TMonotonicOperator::Now() { + if (GlobalMonotonicTimeProvider) { + return GlobalMonotonicTimeProvider->Now(); + } else { + return TMonotonic::Now(); + } } -}; -TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() { - return TIntrusivePtr<IMonotonicTimeProvider>(new TDefaultMonotonicTimeProvider); -} + class TDefaultMonotonicTimeProvider: public IMonotonicTimeProvider { + public: + TMonotonic Now() override { + return TMonotonic::Now(); + } + }; + + TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider() { + return TIntrusivePtr<IMonotonicTimeProvider>(new TDefaultMonotonicTimeProvider); + } } diff --git a/library/cpp/time_provider/monotonic_provider.h b/library/cpp/time_provider/monotonic_provider.h index 966e2e496b..17b57e4075 100644 --- a/library/cpp/time_provider/monotonic_provider.h +++ b/library/cpp/time_provider/monotonic_provider.h @@ -3,19 +3,25 @@ #include <util/datetime/base.h> #include "monotonic.h" -class IMonotonicTimeProvider: public TThrRefBase { -public: - virtual TMonotonic Now() = 0; -}; +namespace NMonotonic { -class TMonotonicOperator { -public: - static void RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider); - static TMonotonic Now(); -}; + class IMonotonicTimeProvider: public TThrRefBase { + public: + virtual TMonotonic Now() = 0; + }; -namespace NMonotonic { + class TMonotonicOperator { + public: + static void RegisterProvider(TIntrusivePtr<IMonotonicTimeProvider> provider); + static TMonotonic Now(); + }; -TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider(); + TIntrusivePtr<IMonotonicTimeProvider> CreateDefaultMonotonicTimeProvider(); } + +// TODO: remove, alias for compatibility +using IMonotonicTimeProvider = NMonotonic::IMonotonicTimeProvider; + +// TODO: remove, alias for compatibility +using NMonotonic::CreateDefaultMonotonicTimeProvider; diff --git a/library/cpp/time_provider/time_provider.cpp b/library/cpp/time_provider/time_provider.cpp index 687681f1ff..e1045dae05 100644 --- a/library/cpp/time_provider/time_provider.cpp +++ b/library/cpp/time_provider/time_provider.cpp @@ -30,7 +30,7 @@ TIntrusivePtr<ITimeProvider> CreateDeterministicTimeProvider(ui64 seed) { } namespace { -TIntrusivePtr<ITimeProvider> GlobalTimeProvider; + TIntrusivePtr<ITimeProvider> GlobalTimeProvider; } void TInstantOperator::RegisterProvider(TIntrusivePtr<ITimeProvider> provider) { |