• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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