aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/time_provider/monotonic.cpp
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2023-06-15 18:24:59 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2023-06-15 18:26:33 +0300
commit068d4453cf9fc68c875eee73f5c637bb076f6a71 (patch)
treeda3e83fdb9488ea08faa39d8b41916744f9acad7 /library/cpp/time_provider/monotonic.cpp
parent7e7de263d4acbc6eacf92b618bcb5f9049bccc9b (diff)
downloadydb-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.cpp83
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)