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