• 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_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