• 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 <grpc/support/port_platform.h>
16 
17 #include "src/core/lib/gprpp/time.h"
18 
19 #include <atomic>
20 #include <chrono>
21 #include <limits>
22 #include <string>
23 #include <utility>
24 
25 #include "absl/strings/str_format.h"
26 
27 #include <grpc/support/log.h>
28 #include <grpc/support/time.h>
29 
30 #include "src/core/lib/gprpp/no_destruct.h"
31 
32 // IWYU pragma: no_include <ratio>
33 
34 namespace grpc_core {
35 
36 namespace {
37 
38 std::atomic<int64_t> g_process_epoch_seconds;
39 std::atomic<gpr_cycle_counter> g_process_epoch_cycles;
40 
41 class GprNowTimeSource final : public Timestamp::Source {
42  public:
Now()43   Timestamp Now() override {
44     return Timestamp::FromTimespecRoundDown(gpr_now(GPR_CLOCK_MONOTONIC));
45   }
46 };
47 
InitTime()48 GPR_ATTRIBUTE_NOINLINE std::pair<int64_t, gpr_cycle_counter> InitTime() {
49   gpr_cycle_counter cycles_start = 0;
50   gpr_cycle_counter cycles_end = 0;
51   int64_t process_epoch_seconds = 0;
52 
53   // Check the current time... if we end up with zero, try again after 100ms.
54   // If it doesn't advance after sleeping for 2100ms, crash the process.
55   for (int i = 0; i < 21; i++) {
56     cycles_start = gpr_get_cycle_counter();
57     gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
58     cycles_end = gpr_get_cycle_counter();
59     process_epoch_seconds = now.tv_sec;
60     if (process_epoch_seconds > 1) {
61       break;
62     }
63     gpr_log(GPR_INFO,
64             "gpr_now(GPR_CLOCK_MONOTONIC) returns a very small number: "
65             "sleeping for 100ms");
66     gpr_sleep_until(gpr_time_add(now, gpr_time_from_millis(100, GPR_TIMESPAN)));
67   }
68 
69   // Check time has increased past 1 second.
70   GPR_ASSERT(process_epoch_seconds > 1);
71   // Fake the epoch to always return >=1 second from our monotonic clock (to
72   // avoid bugs elsewhere)
73   process_epoch_seconds -= 1;
74   int64_t expected = 0;
75   gpr_cycle_counter process_epoch_cycles = (cycles_start + cycles_end) / 2;
76   GPR_ASSERT(process_epoch_cycles != 0);
77   if (!g_process_epoch_seconds.compare_exchange_strong(
78           expected, process_epoch_seconds, std::memory_order_relaxed,
79           std::memory_order_relaxed)) {
80     process_epoch_seconds = expected;
81     do {
82       process_epoch_cycles =
83           g_process_epoch_cycles.load(std::memory_order_relaxed);
84     } while (process_epoch_cycles == 0);
85   } else {
86     g_process_epoch_cycles.store(process_epoch_cycles,
87                                  std::memory_order_relaxed);
88   }
89   return std::make_pair(process_epoch_seconds, process_epoch_cycles);
90 }
91 
StartTime()92 gpr_timespec StartTime() {
93   int64_t sec = g_process_epoch_seconds.load(std::memory_order_relaxed);
94   if (GPR_UNLIKELY(sec == 0)) sec = InitTime().first;
95   return {sec, 0, GPR_CLOCK_MONOTONIC};
96 }
97 
StartCycleCounter()98 gpr_cycle_counter StartCycleCounter() {
99   gpr_cycle_counter cycles =
100       g_process_epoch_cycles.load(std::memory_order_relaxed);
101   if (GPR_UNLIKELY(cycles == 0)) cycles = InitTime().second;
102   return cycles;
103 }
104 
MillisecondsAsTimespec(int64_t millis,gpr_clock_type clock_type)105 gpr_timespec MillisecondsAsTimespec(int64_t millis, gpr_clock_type clock_type) {
106   // special-case infinities as Timestamp can be 32bit on some
107   // platforms while gpr_time_from_millis always takes an int64_t.
108   if (millis == std::numeric_limits<int64_t>::max()) {
109     return gpr_inf_future(clock_type);
110   }
111   if (millis == std::numeric_limits<int64_t>::min()) {
112     return gpr_inf_past(clock_type);
113   }
114 
115   if (clock_type == GPR_TIMESPAN) {
116     return gpr_time_from_millis(millis, GPR_TIMESPAN);
117   }
118   return gpr_time_add(gpr_convert_clock_type(StartTime(), clock_type),
119                       gpr_time_from_millis(millis, GPR_TIMESPAN));
120 }
121 
TimespanToMillisRoundUp(gpr_timespec ts)122 int64_t TimespanToMillisRoundUp(gpr_timespec ts) {
123   GPR_ASSERT(ts.clock_type == GPR_TIMESPAN);
124   double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
125              static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS +
126              static_cast<double>(GPR_NS_PER_SEC - 1) /
127                  static_cast<double>(GPR_NS_PER_SEC);
128   if (x <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
129     return std::numeric_limits<int64_t>::min();
130   }
131   if (x >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
132     return std::numeric_limits<int64_t>::max();
133   }
134   return static_cast<int64_t>(x);
135 }
136 
TimespanToMillisRoundDown(gpr_timespec ts)137 int64_t TimespanToMillisRoundDown(gpr_timespec ts) {
138   GPR_ASSERT(ts.clock_type == GPR_TIMESPAN);
139   double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) +
140              static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS;
141   if (x <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
142     return std::numeric_limits<int64_t>::min();
143   }
144   if (x >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
145     return std::numeric_limits<int64_t>::max();
146   }
147   return static_cast<int64_t>(x);
148 }
149 
150 }  // namespace
151 
152 thread_local Timestamp::Source* Timestamp::thread_local_time_source_{
153     NoDestructSingleton<GprNowTimeSource>::Get()};
154 
Now()155 Timestamp ScopedTimeCache::Now() {
156   if (!cached_time_.has_value()) {
157     previous()->InvalidateCache();
158     cached_time_ = previous()->Now();
159   }
160   return cached_time_.value();
161 }
162 
FromTimespecRoundUp(gpr_timespec ts)163 Timestamp Timestamp::FromTimespecRoundUp(gpr_timespec ts) {
164   return FromMillisecondsAfterProcessEpoch(TimespanToMillisRoundUp(gpr_time_sub(
165       gpr_convert_clock_type(ts, GPR_CLOCK_MONOTONIC), StartTime())));
166 }
167 
FromTimespecRoundDown(gpr_timespec ts)168 Timestamp Timestamp::FromTimespecRoundDown(gpr_timespec ts) {
169   return FromMillisecondsAfterProcessEpoch(
170       TimespanToMillisRoundDown(gpr_time_sub(
171           gpr_convert_clock_type(ts, GPR_CLOCK_MONOTONIC), StartTime())));
172 }
173 
FromCycleCounterRoundUp(gpr_cycle_counter c)174 Timestamp Timestamp::FromCycleCounterRoundUp(gpr_cycle_counter c) {
175   return Timestamp::FromMillisecondsAfterProcessEpoch(
176       TimespanToMillisRoundUp(gpr_cycle_counter_sub(c, StartCycleCounter())));
177 }
178 
FromCycleCounterRoundDown(gpr_cycle_counter c)179 Timestamp Timestamp::FromCycleCounterRoundDown(gpr_cycle_counter c) {
180   return Timestamp::FromMillisecondsAfterProcessEpoch(
181       TimespanToMillisRoundDown(gpr_cycle_counter_sub(c, StartCycleCounter())));
182 }
183 
as_timespec(gpr_clock_type clock_type) const184 gpr_timespec Timestamp::as_timespec(gpr_clock_type clock_type) const {
185   return MillisecondsAsTimespec(millis_, clock_type);
186 }
187 
ToString() const188 std::string Timestamp::ToString() const {
189   if (millis_ == std::numeric_limits<int64_t>::max()) {
190     return "@∞";
191   }
192   if (millis_ == std::numeric_limits<int64_t>::min()) {
193     return "@-∞";
194   }
195   return "@" + std::to_string(millis_) + "ms";
196 }
197 
as_timespec() const198 gpr_timespec Duration::as_timespec() const {
199   return MillisecondsAsTimespec(millis_, GPR_TIMESPAN);
200 }
201 
FromTimespec(gpr_timespec t)202 Duration Duration::FromTimespec(gpr_timespec t) {
203   return Duration::Milliseconds(TimespanToMillisRoundUp(t));
204 }
205 
ToString() const206 std::string Duration::ToString() const {
207   if (millis_ == std::numeric_limits<int64_t>::max()) {
208     return "∞";
209   }
210   if (millis_ == std::numeric_limits<int64_t>::min()) {
211     return "-∞";
212   }
213   return std::to_string(millis_) + "ms";
214 }
215 
ToJsonString() const216 std::string Duration::ToJsonString() const {
217   gpr_timespec ts = as_timespec();
218   return absl::StrFormat("%d.%09ds", ts.tv_sec, ts.tv_nsec);
219 }
220 
operator grpc_event_engine::experimental::EventEngine::Duration() const221 Duration::operator grpc_event_engine::experimental::EventEngine::Duration()
222     const {
223   return std::chrono::milliseconds(
224       Clamp(millis_, std::numeric_limits<int64_t>::min() / GPR_NS_PER_MS,
225             std::numeric_limits<int64_t>::max() / GPR_NS_PER_MS));
226 }
227 
TestOnlySetProcessEpoch(gpr_timespec epoch)228 void TestOnlySetProcessEpoch(gpr_timespec epoch) {
229   g_process_epoch_seconds.store(
230       gpr_convert_clock_type(epoch, GPR_CLOCK_MONOTONIC).tv_sec);
231   g_process_epoch_cycles.store(gpr_get_cycle_counter());
232 }
233 
operator <<(std::ostream & out,Timestamp timestamp)234 std::ostream& operator<<(std::ostream& out, Timestamp timestamp) {
235   return out << timestamp.ToString();
236 }
237 
operator <<(std::ostream & out,Duration duration)238 std::ostream& operator<<(std::ostream& out, Duration duration) {
239   return out << duration.ToString();
240 }
241 
242 }  // namespace grpc_core
243