• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <stdint.h>
19 #include <time.h>
20 
21 namespace cuttlefish {
22 namespace time {
23 
24 static const int64_t kNanosecondsPerSecond = 1000000000;
25 
26 class TimeDifference {
27  public:
TimeDifference(time_t seconds,long nanoseconds,int64_t scale)28   TimeDifference(time_t seconds, long nanoseconds, int64_t scale) :
29       scale_(scale), truncated_(false) {
30     ts_.tv_sec = seconds;
31     ts_.tv_nsec = nanoseconds;
32     if (scale_ == kNanosecondsPerSecond) {
33       truncated_ = true;
34       truncated_ns_ = 0;
35     }
36   }
37 
TimeDifference(const TimeDifference & in,int64_t scale)38   TimeDifference(const TimeDifference& in, int64_t scale) :
39       scale_(scale), truncated_(false) {
40     ts_ = in.GetTS();
41     if (scale_ == kNanosecondsPerSecond) {
42       truncated_ = true;
43       truncated_ns_ = 0;
44     } else if ((in.scale_ % scale_) == 0) {
45       truncated_ = true;
46       truncated_ns_ = ts_.tv_nsec;
47     }
48   }
49 
TimeDifference(const struct timespec & in,int64_t scale)50   TimeDifference(const struct timespec& in, int64_t scale) :
51       ts_(in), scale_(scale), truncated_(false) { }
52 
53   TimeDifference operator*(const uint32_t factor) {
54     TimeDifference rval = *this;
55     rval.ts_.tv_sec = ts_.tv_sec * factor;
56     // Create temporary variable to hold the multiplied
57     // nanoseconds so that no overflow is possible.
58     // Nanoseconds must be in [0, 10^9) and so all are less
59     // then 2^30. Even multiplied by the largest uint32
60     // this will fit in a 64-bit int without overflow.
61     int64_t tv_nsec = static_cast<int64_t>(ts_.tv_nsec) * factor;
62     rval.ts_.tv_sec += (tv_nsec / kNanosecondsPerSecond);
63     rval.ts_.tv_nsec = tv_nsec % kNanosecondsPerSecond;
64     return rval;
65   }
66 
67   TimeDifference operator+(const TimeDifference& other) const {
68     struct timespec ret = ts_;
69     ret.tv_nsec = (ts_.tv_nsec + other.ts_.tv_nsec) % 1000000000;
70     ret.tv_sec = (ts_.tv_sec + other.ts_.tv_sec) +
71                   (ts_.tv_nsec + other.ts_.tv_nsec) / 1000000000;
72     return TimeDifference(ret, scale_ < other.scale_ ? scale_: other.scale_);
73   }
74 
75   TimeDifference operator-(const TimeDifference& other) const {
76     struct timespec ret = ts_;
77     // Keeps nanoseconds positive and allow negative numbers only on
78     // seconds.
79     ret.tv_nsec = (1000000000 + ts_.tv_nsec - other.ts_.tv_nsec) % 1000000000;
80     ret.tv_sec = (ts_.tv_sec - other.ts_.tv_sec) -
81                   (ts_.tv_nsec < other.ts_.tv_nsec ? 1 : 0);
82     return TimeDifference(ret, scale_ < other.scale_ ? scale_: other.scale_);
83   }
84 
85   bool operator<(const TimeDifference& other) const {
86     return ts_.tv_sec < other.ts_.tv_sec ||
87            (ts_.tv_sec == other.ts_.tv_sec && ts_.tv_nsec < other.ts_.tv_nsec);
88   }
89 
count()90   int64_t count() const {
91     return ts_.tv_sec * (kNanosecondsPerSecond / scale_) + ts_.tv_nsec / scale_;
92   }
93 
seconds()94   time_t seconds() const {
95     return ts_.tv_sec;
96   }
97 
subseconds_in_ns()98   long subseconds_in_ns() const {
99     if (!truncated_) {
100       truncated_ns_ = (ts_.tv_nsec / scale_) * scale_;
101       truncated_ = true;
102     }
103     return truncated_ns_;
104   }
105 
GetTS()106   struct timespec GetTS() const {
107     // We can't assume C++11, so avoid extended initializer lists.
108     struct timespec rval = { ts_.tv_sec, subseconds_in_ns()};
109     return rval;
110   }
111 
112  protected:
113   struct timespec ts_;
114   int64_t scale_;
115   mutable bool truncated_;
116   mutable long truncated_ns_;
117 };
118 
119 class MonotonicTimePoint {
120  public:
Now()121   static MonotonicTimePoint Now() {
122     struct timespec ts;
123 #ifdef CLOCK_MONOTONIC_RAW
124     // WARNING:
125     // While we do have CLOCK_MONOTONIC_RAW, we can't depend on it until:
126     // - ALL places relying on MonotonicTimePoint are fixed,
127     // - pthread supports pthread_timewait_monotonic.
128     //
129     // This is currently observable as a LEGITIMATE problem while running
130     // pthread_test. DO NOT revert this to CLOCK_MONOTONIC_RAW until test
131     // passes.
132     clock_gettime(CLOCK_MONOTONIC, &ts);
133 #else
134     clock_gettime(CLOCK_MONOTONIC, &ts);
135 #endif
136     return MonotonicTimePoint(ts);
137   }
138 
MonotonicTimePoint()139   MonotonicTimePoint() {
140     ts_.tv_sec = 0;
141     ts_.tv_nsec = 0;
142   }
143 
MonotonicTimePoint(const struct timespec & ts)144   explicit MonotonicTimePoint(const struct timespec& ts) {
145     ts_ = ts;
146   }
147 
SinceEpoch()148   TimeDifference SinceEpoch() const {
149     return TimeDifference(ts_, 1);
150   }
151 
152   TimeDifference operator-(const MonotonicTimePoint& other) const {
153     struct timespec rval;
154     rval.tv_sec = ts_.tv_sec - other.ts_.tv_sec;
155     rval.tv_nsec = ts_.tv_nsec - other.ts_.tv_nsec;
156     if (rval.tv_nsec < 0) {
157       --rval.tv_sec;
158       rval.tv_nsec += kNanosecondsPerSecond;
159     }
160     return TimeDifference(rval, 1);
161   }
162 
163   MonotonicTimePoint operator+(const TimeDifference& other) const {
164     MonotonicTimePoint rval = *this;
165     rval.ts_.tv_sec += other.seconds();
166     rval.ts_.tv_nsec += other.subseconds_in_ns();
167     if (rval.ts_.tv_nsec >= kNanosecondsPerSecond) {
168       ++rval.ts_.tv_sec;
169       rval.ts_.tv_nsec -= kNanosecondsPerSecond;
170     }
171     return rval;
172   }
173 
174   bool operator==(const MonotonicTimePoint& other) const {
175     return (ts_.tv_sec == other.ts_.tv_sec) &&
176         (ts_.tv_nsec == other.ts_.tv_nsec);
177   }
178 
179   bool operator!=(const MonotonicTimePoint& other) const {
180     return !(*this == other);
181   }
182 
183   bool operator<(const MonotonicTimePoint& other) const {
184     return ((ts_.tv_sec - other.ts_.tv_sec) < 0) ||
185         ((ts_.tv_sec == other.ts_.tv_sec) &&
186          (ts_.tv_nsec < other.ts_.tv_nsec));
187   }
188 
189   bool operator>(const MonotonicTimePoint& other) const {
190     return other < *this;
191   }
192 
193   bool operator<=(const MonotonicTimePoint& other) const {
194     return !(*this > other);
195   }
196 
197   bool operator>=(const MonotonicTimePoint& other) const {
198     return !(*this < other);
199   }
200 
201   MonotonicTimePoint& operator+=(const TimeDifference& other) {
202     ts_.tv_sec += other.seconds();
203     ts_.tv_nsec += other.subseconds_in_ns();
204     if (ts_.tv_nsec >= kNanosecondsPerSecond) {
205       ++ts_.tv_sec;
206       ts_.tv_nsec -= kNanosecondsPerSecond;
207     }
208     return *this;
209   }
210 
211   MonotonicTimePoint& operator-=(const TimeDifference& other) {
212     ts_.tv_sec -= other.seconds();
213     ts_.tv_nsec -= other.subseconds_in_ns();
214     if (ts_.tv_nsec < 0) {
215       --ts_.tv_sec;
216       ts_.tv_nsec += kNanosecondsPerSecond;
217     }
218     return *this;
219   }
220 
ToTimespec(struct timespec * dest)221   void ToTimespec(struct timespec* dest) const {
222     *dest = ts_;
223   }
224 
225  protected:
226   struct timespec ts_;
227 };
228 
229 class Seconds : public TimeDifference {
230  public:
Seconds(const TimeDifference & difference)231   explicit Seconds(const TimeDifference& difference) :
232       TimeDifference(difference, kNanosecondsPerSecond) { }
233 
Seconds(int64_t seconds)234   Seconds(int64_t seconds) :
235       TimeDifference(seconds, 0, kNanosecondsPerSecond) { }
236 };
237 
238 class Milliseconds : public TimeDifference {
239  public:
Milliseconds(const TimeDifference & difference)240   explicit Milliseconds(const TimeDifference& difference) :
241       TimeDifference(difference, kScale) { }
242 
Milliseconds(int64_t ms)243   Milliseconds(int64_t ms) : TimeDifference(
244       ms / 1000, (ms % 1000) * kScale, kScale) { }
245 
246  protected:
247   static const int kScale = kNanosecondsPerSecond / 1000;
248 };
249 
250 class Microseconds : public TimeDifference {
251  public:
Microseconds(const TimeDifference & difference)252   explicit Microseconds(const TimeDifference& difference) :
253       TimeDifference(difference, kScale) { }
254 
Microseconds(int64_t micros)255   Microseconds(int64_t micros) : TimeDifference(
256       micros / 1000000, (micros % 1000000) * kScale, kScale) { }
257 
258  protected:
259   static const int kScale = kNanosecondsPerSecond / 1000000;
260 };
261 
262 class Nanoseconds : public TimeDifference {
263  public:
Nanoseconds(const TimeDifference & difference)264   explicit Nanoseconds(const TimeDifference& difference) :
265       TimeDifference(difference, 1) { }
Nanoseconds(int64_t ns)266   Nanoseconds(int64_t ns) : TimeDifference(ns / kNanosecondsPerSecond,
267                                            ns % kNanosecondsPerSecond, 1) { }
268 };
269 
270 }  // namespace time
271 }  // namespace cuttlefish
272 
273 /**
274  * Legacy support for microseconds. Use MonotonicTimePoint in new code.
275  */
276 static const int64_t kSecsToUsecs = static_cast<int64_t>(1000) * 1000;
277 
get_monotonic_usecs()278 static inline int64_t get_monotonic_usecs() {
279   return cuttlefish::time::Microseconds(
280       cuttlefish::time::MonotonicTimePoint::Now().SinceEpoch()).count();
281 }
282