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