Home | History | Annotate | Download | only in time
      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 cvd {
     22 namespace time {
     23 
     24 static const int64_t kNanosecondsPerSecond = 1000000000;
     25 
     26 class TimeDifference {
     27  public:
     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 
     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 
     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 
     90   int64_t count() const {
     91     return ts_.tv_sec * (kNanosecondsPerSecond / scale_) + ts_.tv_nsec / scale_;
     92   }
     93 
     94   time_t seconds() const {
     95     return ts_.tv_sec;
     96   }
     97 
     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 
    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:
    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 
    139   MonotonicTimePoint() {
    140     ts_.tv_sec = 0;
    141     ts_.tv_nsec = 0;
    142   }
    143 
    144   explicit MonotonicTimePoint(const struct timespec& ts) {
    145     ts_ = ts;
    146   }
    147 
    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 
    221   void ToTimespec(struct timespec* dest) const {
    222     *dest = ts_;
    223   }
    224 
    225  protected:
    226   struct timespec ts_;
    227 };
    228 
    229 class MonotonicTimePointFactory {
    230  public:
    231   static MonotonicTimePointFactory* GetInstance();
    232 
    233   virtual ~MonotonicTimePointFactory() { }
    234 
    235   virtual void FetchCurrentTime(MonotonicTimePoint* dest) const {
    236     *dest = MonotonicTimePoint::Now();
    237   }
    238 };
    239 
    240 class Seconds : public TimeDifference {
    241  public:
    242   explicit Seconds(const TimeDifference& difference) :
    243       TimeDifference(difference, kNanosecondsPerSecond) { }
    244 
    245   Seconds(int64_t seconds) :
    246       TimeDifference(seconds, 0, kNanosecondsPerSecond) { }
    247 };
    248 
    249 class Milliseconds : public TimeDifference {
    250  public:
    251   explicit Milliseconds(const TimeDifference& difference) :
    252       TimeDifference(difference, kScale) { }
    253 
    254   Milliseconds(int64_t ms) : TimeDifference(
    255       ms / 1000, (ms % 1000) * kScale, kScale) { }
    256 
    257  protected:
    258   static const int kScale = kNanosecondsPerSecond / 1000;
    259 };
    260 
    261 class Microseconds : public TimeDifference {
    262  public:
    263   explicit Microseconds(const TimeDifference& difference) :
    264       TimeDifference(difference, kScale) { }
    265 
    266   Microseconds(int64_t micros) : TimeDifference(
    267       micros / 1000000, (micros % 1000000) * kScale, kScale) { }
    268 
    269  protected:
    270   static const int kScale = kNanosecondsPerSecond / 1000000;
    271 };
    272 
    273 class Nanoseconds : public TimeDifference {
    274  public:
    275   explicit Nanoseconds(const TimeDifference& difference) :
    276       TimeDifference(difference, 1) { }
    277   Nanoseconds(int64_t ns) : TimeDifference(ns / kNanosecondsPerSecond,
    278                                            ns % kNanosecondsPerSecond, 1) { }
    279 };
    280 
    281 }  // namespace time
    282 }  // namespace cvd
    283 
    284 /**
    285  * Legacy support for microseconds. Use MonotonicTimePoint in new code.
    286  */
    287 static const int64_t kSecsToUsecs = static_cast<int64_t>(1000) * 1000;
    288 
    289 static inline int64_t get_monotonic_usecs() {
    290   return cvd::time::Microseconds(
    291       cvd::time::MonotonicTimePoint::Now().SinceEpoch()).count();
    292 }
    293