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