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