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 #ifndef GRPC_SRC_CORE_UTIL_TIME_H
16 #define GRPC_SRC_CORE_UTIL_TIME_H
17
18 #include <grpc/event_engine/event_engine.h>
19 #include <grpc/support/port_platform.h>
20 #include <grpc/support/time.h>
21 #include <stdint.h>
22
23 #include <limits>
24 #include <ostream>
25 #include <string>
26
27 #include "absl/types/optional.h"
28 #include "src/core/util/time_precise.h"
29 #include "src/core/util/useful.h"
30
31 #define GRPC_LOG_EVERY_N_SEC_DELAYED_DEBUG(n, format, ...) \
32 do { \
33 static std::atomic<uint64_t> prev{0}; \
34 uint64_t now = grpc_core::Timestamp::FromTimespecRoundDown( \
35 gpr_now(GPR_CLOCK_MONOTONIC)) \
36 .milliseconds_after_process_epoch(); \
37 if (prev == 0) prev = now; \
38 if (now - prev > (n) * 1000) { \
39 prev = now; \
40 VLOG(2) << absl::StrFormat(format, __VA_ARGS__); \
41 } \
42 } while (0)
43
44 namespace grpc_core {
45
46 namespace time_detail {
47
MillisAdd(int64_t a,int64_t b)48 inline int64_t MillisAdd(int64_t a, int64_t b) {
49 if (a == std::numeric_limits<int64_t>::max() ||
50 b == std::numeric_limits<int64_t>::max()) {
51 return std::numeric_limits<int64_t>::max();
52 }
53 if (a == std::numeric_limits<int64_t>::min() ||
54 b == std::numeric_limits<int64_t>::min()) {
55 return std::numeric_limits<int64_t>::min();
56 }
57 return SaturatingAdd(a, b);
58 }
59
MillisMul(int64_t millis,int64_t mul)60 constexpr inline int64_t MillisMul(int64_t millis, int64_t mul) {
61 return millis >= std::numeric_limits<int64_t>::max() / mul
62 ? std::numeric_limits<int64_t>::max()
63 : millis <= std::numeric_limits<int64_t>::min() / mul
64 ? std::numeric_limits<int64_t>::min()
65 : millis * mul;
66 }
67
68 } // namespace time_detail
69
70 class Duration;
71
72 // Timestamp represents a discrete point in time.
73 class Timestamp {
74 public:
75 // Base interface for time providers.
76 class Source {
77 public:
78 // Return the current time.
79 virtual Timestamp Now() = 0;
InvalidateCache()80 virtual void InvalidateCache() {}
81
82 protected:
83 // We don't delete through this interface, so non-virtual dtor is fine.
84 ~Source() = default;
85 };
86
87 class ScopedSource : public Source {
88 public:
ScopedSource()89 ScopedSource() : previous_(thread_local_time_source_) {
90 thread_local_time_source_ = this;
91 }
92 ScopedSource(const ScopedSource&) = delete;
93 ScopedSource& operator=(const ScopedSource&) = delete;
InvalidateCache()94 void InvalidateCache() override { previous_->InvalidateCache(); }
95
96 protected:
~ScopedSource()97 ~ScopedSource() { thread_local_time_source_ = previous_; }
previous()98 Source* previous() const { return previous_; }
99
100 private:
101 Source* const previous_;
102 };
103
104 constexpr Timestamp() = default;
105 // Constructs a Timestamp from a gpr_timespec.
106 static Timestamp FromTimespecRoundDown(gpr_timespec t);
107 static Timestamp FromTimespecRoundUp(gpr_timespec t);
108
109 // Construct a Timestamp from a gpr_cycle_counter.
110 static Timestamp FromCycleCounterRoundUp(gpr_cycle_counter c);
111 static Timestamp FromCycleCounterRoundDown(gpr_cycle_counter c);
112
Now()113 static Timestamp Now() { return thread_local_time_source_->Now(); }
114
FromMillisecondsAfterProcessEpoch(int64_t millis)115 static constexpr Timestamp FromMillisecondsAfterProcessEpoch(int64_t millis) {
116 return Timestamp(millis);
117 }
118
ProcessEpoch()119 static constexpr Timestamp ProcessEpoch() { return Timestamp(0); }
120
InfFuture()121 static constexpr Timestamp InfFuture() {
122 return Timestamp(std::numeric_limits<int64_t>::max());
123 }
124
InfPast()125 static constexpr Timestamp InfPast() {
126 return Timestamp(std::numeric_limits<int64_t>::min());
127 }
128
129 constexpr bool operator==(Timestamp other) const {
130 return millis_ == other.millis_;
131 }
132 constexpr bool operator!=(Timestamp other) const {
133 return millis_ != other.millis_;
134 }
135 constexpr bool operator<(Timestamp other) const {
136 return millis_ < other.millis_;
137 }
138 constexpr bool operator<=(Timestamp other) const {
139 return millis_ <= other.millis_;
140 }
141 constexpr bool operator>(Timestamp other) const {
142 return millis_ > other.millis_;
143 }
144 constexpr bool operator>=(Timestamp other) const {
145 return millis_ >= other.millis_;
146 }
147 Timestamp& operator+=(Duration duration);
148
is_process_epoch()149 bool is_process_epoch() const { return millis_ == 0; }
150
milliseconds_after_process_epoch()151 uint64_t milliseconds_after_process_epoch() const { return millis_; }
152
153 gpr_timespec as_timespec(gpr_clock_type type) const;
154
155 std::string ToString() const;
156
157 template <typename Sink>
AbslStringify(Sink & sink,const Timestamp & t)158 friend void AbslStringify(Sink& sink, const Timestamp& t) {
159 sink.Append(t.ToString());
160 }
161
162 private:
Timestamp(int64_t millis)163 explicit constexpr Timestamp(int64_t millis) : millis_(millis) {}
164
165 int64_t millis_ = 0;
166 static thread_local Timestamp::Source* thread_local_time_source_;
167 };
168
169 class ScopedTimeCache final : public Timestamp::ScopedSource {
170 public:
171 Timestamp Now() override;
172
InvalidateCache()173 void InvalidateCache() override {
174 cached_time_ = absl::nullopt;
175 Timestamp::ScopedSource::InvalidateCache();
176 }
TestOnlySetNow(Timestamp now)177 void TestOnlySetNow(Timestamp now) { cached_time_ = now; }
178
179 private:
180 absl::optional<Timestamp> cached_time_;
181 };
182
183 // Duration represents a span of time.
184 class Duration {
185 public:
Duration()186 constexpr Duration() noexcept : millis_(0) {}
187
188 static Duration FromTimespec(gpr_timespec t);
189 static Duration FromSecondsAndNanoseconds(int64_t seconds, int32_t nanos);
190 static Duration FromSecondsAsDouble(double seconds);
191
Zero()192 static constexpr Duration Zero() { return Duration(0); }
193
194 // Smallest representatable positive duration.
Epsilon()195 static constexpr Duration Epsilon() { return Duration(1); }
196
NegativeInfinity()197 static constexpr Duration NegativeInfinity() {
198 return Duration(std::numeric_limits<int64_t>::min());
199 }
200
Infinity()201 static constexpr Duration Infinity() {
202 return Duration(std::numeric_limits<int64_t>::max());
203 }
204
Hours(int64_t hours)205 static constexpr Duration Hours(int64_t hours) {
206 return Minutes(time_detail::MillisMul(hours, 60));
207 }
208
Minutes(int64_t minutes)209 static constexpr Duration Minutes(int64_t minutes) {
210 return Seconds(time_detail::MillisMul(minutes, 60));
211 }
212
Seconds(int64_t seconds)213 static constexpr Duration Seconds(int64_t seconds) {
214 return Milliseconds(time_detail::MillisMul(seconds, GPR_MS_PER_SEC));
215 }
216
Milliseconds(int64_t millis)217 static constexpr Duration Milliseconds(int64_t millis) {
218 return Duration(millis);
219 }
220
MicrosecondsRoundDown(int64_t micros)221 static constexpr Duration MicrosecondsRoundDown(int64_t micros) {
222 return Duration(micros / GPR_US_PER_MS);
223 }
224
NanosecondsRoundDown(int64_t nanos)225 static constexpr Duration NanosecondsRoundDown(int64_t nanos) {
226 return Duration(nanos / GPR_NS_PER_MS);
227 }
228
MicrosecondsRoundUp(int64_t micros)229 static constexpr Duration MicrosecondsRoundUp(int64_t micros) {
230 return Duration((micros / GPR_US_PER_MS) + (micros % GPR_US_PER_MS != 0));
231 }
232
NanosecondsRoundUp(int64_t nanos)233 static constexpr Duration NanosecondsRoundUp(int64_t nanos) {
234 return Duration((nanos / GPR_NS_PER_MS) + (nanos % GPR_NS_PER_MS != 0));
235 }
236
237 constexpr bool operator==(Duration other) const {
238 return millis_ == other.millis_;
239 }
240 constexpr bool operator!=(Duration other) const {
241 return millis_ != other.millis_;
242 }
243 constexpr bool operator<(Duration other) const {
244 return millis_ < other.millis_;
245 }
246 constexpr bool operator<=(Duration other) const {
247 return millis_ <= other.millis_;
248 }
249 constexpr bool operator>(Duration other) const {
250 return millis_ > other.millis_;
251 }
252 constexpr bool operator>=(Duration other) const {
253 return millis_ >= other.millis_;
254 }
255 Duration& operator/=(int64_t divisor) {
256 if (millis_ == std::numeric_limits<int64_t>::max()) {
257 *this = divisor < 0 ? NegativeInfinity() : Infinity();
258 } else if (millis_ == std::numeric_limits<int64_t>::min()) {
259 *this = divisor < 0 ? Infinity() : NegativeInfinity();
260 } else {
261 millis_ /= divisor;
262 }
263 return *this;
264 }
265 Duration& operator*=(double multiplier);
266 Duration& operator+=(Duration other) {
267 millis_ += other.millis_;
268 return *this;
269 }
270
millis()271 constexpr int64_t millis() const { return millis_; }
seconds()272 double seconds() const { return static_cast<double>(millis_) / 1000.0; }
273
274 // NOLINTNEXTLINE: google-explicit-constructor
275 operator grpc_event_engine::experimental::EventEngine::Duration() const;
276
277 gpr_timespec as_timespec() const;
278
279 std::string ToString() const;
280
281 // Returns the duration in the JSON form corresponding to a
282 // google.protobuf.Duration proto, as defined here:
283 // https://developers.google.com/protocol-buffers/docs/proto3#json
284 std::string ToJsonString() const;
285
286 template <typename Sink>
AbslStringify(Sink & sink,const Duration & t)287 friend void AbslStringify(Sink& sink, const Duration& t) {
288 sink.Append(t.ToString());
289 }
290
291 private:
Duration(int64_t millis)292 explicit constexpr Duration(int64_t millis) : millis_(millis) {}
293
294 int64_t millis_;
295 };
296
297 inline std::ostream& operator<<(std::ostream& out, const Duration& d) {
298 return out << d.ToString();
299 }
300
301 inline std::ostream& operator<<(std::ostream& out, const Timestamp& d) {
302 return out << d.ToString();
303 }
304
305 inline Duration operator+(Duration lhs, Duration rhs) {
306 return Duration::Milliseconds(
307 time_detail::MillisAdd(lhs.millis(), rhs.millis()));
308 }
309
310 inline Duration operator-(Duration lhs, Duration rhs) {
311 return Duration::Milliseconds(
312 time_detail::MillisAdd(lhs.millis(), -rhs.millis()));
313 }
314
315 inline Timestamp operator+(Timestamp lhs, Duration rhs) {
316 return Timestamp::FromMillisecondsAfterProcessEpoch(time_detail::MillisAdd(
317 lhs.milliseconds_after_process_epoch(), rhs.millis()));
318 }
319
320 inline Timestamp operator-(Timestamp lhs, Duration rhs) {
321 return Timestamp::FromMillisecondsAfterProcessEpoch(time_detail::MillisAdd(
322 lhs.milliseconds_after_process_epoch(), -rhs.millis()));
323 }
324
325 inline Timestamp operator+(Duration lhs, Timestamp rhs) { return rhs + lhs; }
326
327 inline Duration operator-(Timestamp lhs, Timestamp rhs) {
328 if (rhs == Timestamp::InfPast() && lhs != Timestamp::InfPast()) {
329 return Duration::Infinity();
330 }
331 if (rhs == Timestamp::InfFuture() && lhs != Timestamp::InfFuture()) {
332 return Duration::NegativeInfinity();
333 }
334 return Duration::Milliseconds(
335 time_detail::MillisAdd(lhs.milliseconds_after_process_epoch(),
336 -rhs.milliseconds_after_process_epoch()));
337 }
338
339 inline Duration operator*(Duration lhs, double rhs) {
340 if (lhs == Duration::Infinity()) {
341 return rhs < 0 ? Duration::NegativeInfinity() : Duration::Infinity();
342 }
343 if (lhs == Duration::NegativeInfinity()) {
344 return rhs < 0 ? Duration::Infinity() : Duration::NegativeInfinity();
345 }
346 return Duration::FromSecondsAsDouble(lhs.millis() * rhs / 1000.0);
347 }
348
349 inline Duration operator*(double lhs, Duration rhs) { return rhs * lhs; }
350
351 inline Duration operator/(Duration lhs, int64_t rhs) {
352 lhs /= rhs;
353 return lhs;
354 }
355
FromSecondsAndNanoseconds(int64_t seconds,int32_t nanos)356 inline Duration Duration::FromSecondsAndNanoseconds(int64_t seconds,
357 int32_t nanos) {
358 return Seconds(seconds) + NanosecondsRoundDown(nanos);
359 }
360
FromSecondsAsDouble(double seconds)361 inline Duration Duration::FromSecondsAsDouble(double seconds) {
362 double millis = seconds * 1000.0;
363 if (millis >= static_cast<double>(std::numeric_limits<int64_t>::max())) {
364 return Infinity();
365 }
366 if (millis <= static_cast<double>(std::numeric_limits<int64_t>::min())) {
367 return NegativeInfinity();
368 }
369 return Milliseconds(static_cast<int64_t>(millis));
370 }
371
372 inline Duration& Duration::operator*=(double multiplier) {
373 *this = *this * multiplier;
374 return *this;
375 }
376
377 inline Timestamp& Timestamp::operator+=(Duration duration) {
378 return *this = (*this + duration);
379 }
380
381 void TestOnlySetProcessEpoch(gpr_timespec epoch);
382
383 } // namespace grpc_core
384
385 #endif // GRPC_SRC_CORE_UTIL_TIME_H
386