• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "src/core/util/time.h"
16 
17 #include <grpc/support/port_platform.h>
18 #include <grpc/support/time.h>
19 
20 #include <atomic>
21 #include <chrono>
22 #include <limits>
23 #include <string>
24 #include <utility>
25 
26 #include "absl/log/check.h"
27 #include "absl/log/log.h"
28 #include "absl/strings/str_format.h"
29 #include "src/core/util/no_destruct.h"
30 
31 // IWYU pragma: no_include <ratio>
32 
33 namespace grpc_core {
34 
35 namespace {
36 
37 std::atomic<int64_t> g_process_epoch_seconds;
38 std::atomic<gpr_cycle_counter> g_process_epoch_cycles;
39 
40 class GprNowTimeSource final : public Timestamp::Source {
41  public:
Now()42   Timestamp Now() override {
43     return Timestamp::FromTimespecRoundDown(gpr_now(GPR_CLOCK_MONOTONIC));
44   }
45 };
46 
InitTime()47 GPR_ATTRIBUTE_NOINLINE std::pair<int64_t, gpr_cycle_counter> InitTime() {
48   gpr_cycle_counter cycles_start = 0;
49   gpr_cycle_counter cycles_end = 0;
50   int64_t process_epoch_seconds = 0;
51 
52   // Check the current time... if we end up with zero, try again after 100ms.
53   // If it doesn't advance after sleeping for 2100ms, crash the process.
54   for (int i = 0; i < 21; i++) {
55     cycles_start = gpr_get_cycle_counter();
56     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
57     cycles_end = gpr_get_cycle_counter();
58     process_epoch_seconds = now.tv_sec;
59     if (process_epoch_seconds > 1) {
60       break;
61     }
62     LOG(INFO) << "gpr_now(GPR_CLOCK_MONOTONIC) returns a very small number: "
63                  "sleeping for 100ms";
64     gpr_sleep_until(gpr_time_add(now, gpr_time_from_millis(100, GPR_TIMESPAN)));
65   }
66 
67   // Check time has increased past 1 second.
68   CHECK_GT(process_epoch_seconds, 1);
69   // Fake the epoch to always return >=1 second from our monotonic clock (to
70   // avoid bugs elsewhere)
71   process_epoch_seconds -= 1;
72   int64_t expected = 0;
73   gpr_cycle_counter process_epoch_cycles = (cycles_start + cycles_end) / 2;
74   CHECK_NE(process_epoch_cycles, 0);
75   if (!g_process_epoch_seconds.compare_exchange_strong(
76           expected, process_epoch_seconds, std::memory_order_relaxed,
77           std::memory_order_relaxed)) {
78     process_epoch_seconds = expected;
79     do {
80       process_epoch_cycles =
81           g_process_epoch_cycles.load(std::memory_order_relaxed);
82     } while (process_epoch_cycles == 0);
83   } else {
84     g_process_epoch_cycles.store(process_epoch_cycles,
85                                  std::memory_order_relaxed);
86   }
87   return std::make_pair(process_epoch_seconds, process_epoch_cycles);
88 }
89 
StartTime()90 gpr_timespec StartTime() {
91   int64_t sec = g_process_epoch_seconds.load(std::memory_order_relaxed);
92   if (GPR_UNLIKELY(sec == 0)) sec = InitTime().first;
93   return {sec, 0, GPR_CLOCK_MONOTONIC};
94 }
95 
StartCycleCounter()96 gpr_cycle_counter StartCycleCounter() {
97   gpr_cycle_counter cycles =
98       g_process_epoch_cycles.load(std::memory_order_relaxed);
99   if (GPR_UNLIKELY(cycles == 0)) cycles = InitTime().second;
100   return cycles;
101 }
102 
MillisecondsAsTimespec(int64_t millis,gpr_clock_type clock_type)103 gpr_timespec MillisecondsAsTimespec(int64_t millis, gpr_clock_type clock_type) {
104   // special-case infinities as Timestamp can be 32bit on some
105   // platforms while gpr_time_from_millis always takes an int64_t.
106   if (millis == std::numeric_limits<int64_t>::max()) {
107     return gpr_inf_future(clock_type);
108   }
109   if (millis == std::numeric_limits<int64_t>::min()) {
110     return gpr_inf_past(clock_type);
111   }
112 
113   if (clock_type == GPR_TIMESPAN) {
114     return gpr_time_from_millis(millis, GPR_TIMESPAN);
115   }
116   return gpr_time_add(gpr_convert_clock_type(StartTime(), clock_type),
117                       gpr_time_from_millis(millis, GPR_TIMESPAN));
118 }
119 
TimespanToMillisRoundUp(gpr_timespec ts)120 int64_t TimespanToMillisRoundUp(gpr_timespec ts) {
121   CHECK(ts.clock_type == GPR_TIMESPAN);
122   double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
123              (static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS) +
124              (static_cast<double>(GPR_NS_PER_SEC - 1) /
125               static_cast<double>(GPR_NS_PER_SEC));
126   if (x <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
127     return std::numeric_limits<int64_t>::min();
128   }
129   if (x >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
130     return std::numeric_limits<int64_t>::max();
131   }
132   return static_cast<int64_t>(x);
133 }
134 
TimespanToMillisRoundDown(gpr_timespec ts)135 int64_t TimespanToMillisRoundDown(gpr_timespec ts) {
136   CHECK(ts.clock_type == GPR_TIMESPAN);
137   double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
138              (static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS);
139   if (x <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
140     return std::numeric_limits<int64_t>::min();
141   }
142   if (x >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
143     return std::numeric_limits<int64_t>::max();
144   }
145   return static_cast<int64_t>(x);
146 }
147 
148 }  // namespace
149 
150 thread_local Timestamp::Source* Timestamp::thread_local_time_source_{
151     NoDestructSingleton<GprNowTimeSource>::Get()};
152 
Now()153 Timestamp ScopedTimeCache::Now() {
154   if (!cached_time_.has_value()) {
155     previous()->InvalidateCache();
156     cached_time_ = previous()->Now();
157   }
158   return cached_time_.value();
159 }
160 
FromTimespecRoundUp(gpr_timespec ts)161 Timestamp Timestamp::FromTimespecRoundUp(gpr_timespec ts) {
162   return FromMillisecondsAfterProcessEpoch(TimespanToMillisRoundUp(gpr_time_sub(
163       gpr_convert_clock_type(ts, GPR_CLOCK_MONOTONIC), StartTime())));
164 }
165 
FromTimespecRoundDown(gpr_timespec ts)166 Timestamp Timestamp::FromTimespecRoundDown(gpr_timespec ts) {
167   return FromMillisecondsAfterProcessEpoch(
168       TimespanToMillisRoundDown(gpr_time_sub(
169           gpr_convert_clock_type(ts, GPR_CLOCK_MONOTONIC), StartTime())));
170 }
171 
FromCycleCounterRoundUp(gpr_cycle_counter c)172 Timestamp Timestamp::FromCycleCounterRoundUp(gpr_cycle_counter c) {
173   return Timestamp::FromMillisecondsAfterProcessEpoch(
174       TimespanToMillisRoundUp(gpr_cycle_counter_sub(c, StartCycleCounter())));
175 }
176 
FromCycleCounterRoundDown(gpr_cycle_counter c)177 Timestamp Timestamp::FromCycleCounterRoundDown(gpr_cycle_counter c) {
178   return Timestamp::FromMillisecondsAfterProcessEpoch(
179       TimespanToMillisRoundDown(gpr_cycle_counter_sub(c, StartCycleCounter())));
180 }
181 
as_timespec(gpr_clock_type clock_type) const182 gpr_timespec Timestamp::as_timespec(gpr_clock_type clock_type) const {
183   return MillisecondsAsTimespec(millis_, clock_type);
184 }
185 
ToString() const186 std::string Timestamp::ToString() const {
187   if (millis_ == std::numeric_limits<int64_t>::max()) {
188     return "@∞";
189   }
190   if (millis_ == std::numeric_limits<int64_t>::min()) {
191     return "@-∞";
192   }
193   return "@" + std::to_string(millis_) + "ms";
194 }
195 
as_timespec() const196 gpr_timespec Duration::as_timespec() const {
197   return MillisecondsAsTimespec(millis_, GPR_TIMESPAN);
198 }
199 
FromTimespec(gpr_timespec t)200 Duration Duration::FromTimespec(gpr_timespec t) {
201   return Duration::Milliseconds(TimespanToMillisRoundUp(t));
202 }
203 
ToString() const204 std::string Duration::ToString() const {
205   if (millis_ == std::numeric_limits<int64_t>::max()) {
206     return "∞";
207   }
208   if (millis_ == std::numeric_limits<int64_t>::min()) {
209     return "-∞";
210   }
211   return std::to_string(millis_) + "ms";
212 }
213 
ToJsonString() const214 std::string Duration::ToJsonString() const {
215   gpr_timespec ts = as_timespec();
216   return absl::StrFormat("%d.%09ds", ts.tv_sec, ts.tv_nsec);
217 }
218 
operator grpc_event_engine::experimental::EventEngine::Duration() const219 Duration::operator grpc_event_engine::experimental::EventEngine::Duration()
220     const {
221   return std::chrono::milliseconds(
222       Clamp(millis_, std::numeric_limits<int64_t>::min() / GPR_NS_PER_MS,
223             std::numeric_limits<int64_t>::max() / GPR_NS_PER_MS));
224 }
225 
TestOnlySetProcessEpoch(gpr_timespec epoch)226 void TestOnlySetProcessEpoch(gpr_timespec epoch) {
227   g_process_epoch_seconds.store(
228       gpr_convert_clock_type(epoch, GPR_CLOCK_MONOTONIC).tv_sec);
229   g_process_epoch_cycles.store(gpr_get_cycle_counter());
230 }
231 
operator <<(std::ostream & out,Timestamp timestamp)232 std::ostream& operator<<(std::ostream& out, Timestamp timestamp) {
233   return out << timestamp.ToString();
234 }
235 
operator <<(std::ostream & out,Duration duration)236 std::ostream& operator<<(std::ostream& out, Duration duration) {
237   return out << duration.ToString();
238 }
239 
240 }  // namespace grpc_core
241