You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.1 KiB
282 lines
8.1 KiB
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <time.h>
|
|
|
|
namespace cuttlefish {
|
|
namespace time {
|
|
|
|
static const int64_t kNanosecondsPerSecond = 1000000000;
|
|
|
|
class TimeDifference {
|
|
public:
|
|
TimeDifference(time_t seconds, long nanoseconds, int64_t scale) :
|
|
scale_(scale), truncated_(false) {
|
|
ts_.tv_sec = seconds;
|
|
ts_.tv_nsec = nanoseconds;
|
|
if (scale_ == kNanosecondsPerSecond) {
|
|
truncated_ = true;
|
|
truncated_ns_ = 0;
|
|
}
|
|
}
|
|
|
|
TimeDifference(const TimeDifference& in, int64_t scale) :
|
|
scale_(scale), truncated_(false) {
|
|
ts_ = in.GetTS();
|
|
if (scale_ == kNanosecondsPerSecond) {
|
|
truncated_ = true;
|
|
truncated_ns_ = 0;
|
|
} else if ((in.scale_ % scale_) == 0) {
|
|
truncated_ = true;
|
|
truncated_ns_ = ts_.tv_nsec;
|
|
}
|
|
}
|
|
|
|
TimeDifference(const struct timespec& in, int64_t scale) :
|
|
ts_(in), scale_(scale), truncated_(false) { }
|
|
|
|
TimeDifference operator*(const uint32_t factor) {
|
|
TimeDifference rval = *this;
|
|
rval.ts_.tv_sec = ts_.tv_sec * factor;
|
|
// Create temporary variable to hold the multiplied
|
|
// nanoseconds so that no overflow is possible.
|
|
// Nanoseconds must be in [0, 10^9) and so all are less
|
|
// then 2^30. Even multiplied by the largest uint32
|
|
// this will fit in a 64-bit int without overflow.
|
|
int64_t tv_nsec = static_cast<int64_t>(ts_.tv_nsec) * factor;
|
|
rval.ts_.tv_sec += (tv_nsec / kNanosecondsPerSecond);
|
|
rval.ts_.tv_nsec = tv_nsec % kNanosecondsPerSecond;
|
|
return rval;
|
|
}
|
|
|
|
TimeDifference operator+(const TimeDifference& other) const {
|
|
struct timespec ret = ts_;
|
|
ret.tv_nsec = (ts_.tv_nsec + other.ts_.tv_nsec) % 1000000000;
|
|
ret.tv_sec = (ts_.tv_sec + other.ts_.tv_sec) +
|
|
(ts_.tv_nsec + other.ts_.tv_nsec) / 1000000000;
|
|
return TimeDifference(ret, scale_ < other.scale_ ? scale_: other.scale_);
|
|
}
|
|
|
|
TimeDifference operator-(const TimeDifference& other) const {
|
|
struct timespec ret = ts_;
|
|
// Keeps nanoseconds positive and allow negative numbers only on
|
|
// seconds.
|
|
ret.tv_nsec = (1000000000 + ts_.tv_nsec - other.ts_.tv_nsec) % 1000000000;
|
|
ret.tv_sec = (ts_.tv_sec - other.ts_.tv_sec) -
|
|
(ts_.tv_nsec < other.ts_.tv_nsec ? 1 : 0);
|
|
return TimeDifference(ret, scale_ < other.scale_ ? scale_: other.scale_);
|
|
}
|
|
|
|
bool operator<(const TimeDifference& other) const {
|
|
return ts_.tv_sec < other.ts_.tv_sec ||
|
|
(ts_.tv_sec == other.ts_.tv_sec && ts_.tv_nsec < other.ts_.tv_nsec);
|
|
}
|
|
|
|
int64_t count() const {
|
|
return ts_.tv_sec * (kNanosecondsPerSecond / scale_) + ts_.tv_nsec / scale_;
|
|
}
|
|
|
|
time_t seconds() const {
|
|
return ts_.tv_sec;
|
|
}
|
|
|
|
long subseconds_in_ns() const {
|
|
if (!truncated_) {
|
|
truncated_ns_ = (ts_.tv_nsec / scale_) * scale_;
|
|
truncated_ = true;
|
|
}
|
|
return truncated_ns_;
|
|
}
|
|
|
|
struct timespec GetTS() const {
|
|
// We can't assume C++11, so avoid extended initializer lists.
|
|
struct timespec rval = { ts_.tv_sec, subseconds_in_ns()};
|
|
return rval;
|
|
}
|
|
|
|
protected:
|
|
struct timespec ts_;
|
|
int64_t scale_;
|
|
mutable bool truncated_;
|
|
mutable long truncated_ns_;
|
|
};
|
|
|
|
class MonotonicTimePoint {
|
|
public:
|
|
static MonotonicTimePoint Now() {
|
|
struct timespec ts;
|
|
#ifdef CLOCK_MONOTONIC_RAW
|
|
// WARNING:
|
|
// While we do have CLOCK_MONOTONIC_RAW, we can't depend on it until:
|
|
// - ALL places relying on MonotonicTimePoint are fixed,
|
|
// - pthread supports pthread_timewait_monotonic.
|
|
//
|
|
// This is currently observable as a LEGITIMATE problem while running
|
|
// pthread_test. DO NOT revert this to CLOCK_MONOTONIC_RAW until test
|
|
// passes.
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
#else
|
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
|
#endif
|
|
return MonotonicTimePoint(ts);
|
|
}
|
|
|
|
MonotonicTimePoint() {
|
|
ts_.tv_sec = 0;
|
|
ts_.tv_nsec = 0;
|
|
}
|
|
|
|
explicit MonotonicTimePoint(const struct timespec& ts) {
|
|
ts_ = ts;
|
|
}
|
|
|
|
TimeDifference SinceEpoch() const {
|
|
return TimeDifference(ts_, 1);
|
|
}
|
|
|
|
TimeDifference operator-(const MonotonicTimePoint& other) const {
|
|
struct timespec rval;
|
|
rval.tv_sec = ts_.tv_sec - other.ts_.tv_sec;
|
|
rval.tv_nsec = ts_.tv_nsec - other.ts_.tv_nsec;
|
|
if (rval.tv_nsec < 0) {
|
|
--rval.tv_sec;
|
|
rval.tv_nsec += kNanosecondsPerSecond;
|
|
}
|
|
return TimeDifference(rval, 1);
|
|
}
|
|
|
|
MonotonicTimePoint operator+(const TimeDifference& other) const {
|
|
MonotonicTimePoint rval = *this;
|
|
rval.ts_.tv_sec += other.seconds();
|
|
rval.ts_.tv_nsec += other.subseconds_in_ns();
|
|
if (rval.ts_.tv_nsec >= kNanosecondsPerSecond) {
|
|
++rval.ts_.tv_sec;
|
|
rval.ts_.tv_nsec -= kNanosecondsPerSecond;
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
bool operator==(const MonotonicTimePoint& other) const {
|
|
return (ts_.tv_sec == other.ts_.tv_sec) &&
|
|
(ts_.tv_nsec == other.ts_.tv_nsec);
|
|
}
|
|
|
|
bool operator!=(const MonotonicTimePoint& other) const {
|
|
return !(*this == other);
|
|
}
|
|
|
|
bool operator<(const MonotonicTimePoint& other) const {
|
|
return ((ts_.tv_sec - other.ts_.tv_sec) < 0) ||
|
|
((ts_.tv_sec == other.ts_.tv_sec) &&
|
|
(ts_.tv_nsec < other.ts_.tv_nsec));
|
|
}
|
|
|
|
bool operator>(const MonotonicTimePoint& other) const {
|
|
return other < *this;
|
|
}
|
|
|
|
bool operator<=(const MonotonicTimePoint& other) const {
|
|
return !(*this > other);
|
|
}
|
|
|
|
bool operator>=(const MonotonicTimePoint& other) const {
|
|
return !(*this < other);
|
|
}
|
|
|
|
MonotonicTimePoint& operator+=(const TimeDifference& other) {
|
|
ts_.tv_sec += other.seconds();
|
|
ts_.tv_nsec += other.subseconds_in_ns();
|
|
if (ts_.tv_nsec >= kNanosecondsPerSecond) {
|
|
++ts_.tv_sec;
|
|
ts_.tv_nsec -= kNanosecondsPerSecond;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
MonotonicTimePoint& operator-=(const TimeDifference& other) {
|
|
ts_.tv_sec -= other.seconds();
|
|
ts_.tv_nsec -= other.subseconds_in_ns();
|
|
if (ts_.tv_nsec < 0) {
|
|
--ts_.tv_sec;
|
|
ts_.tv_nsec += kNanosecondsPerSecond;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
void ToTimespec(struct timespec* dest) const {
|
|
*dest = ts_;
|
|
}
|
|
|
|
protected:
|
|
struct timespec ts_;
|
|
};
|
|
|
|
class Seconds : public TimeDifference {
|
|
public:
|
|
explicit Seconds(const TimeDifference& difference) :
|
|
TimeDifference(difference, kNanosecondsPerSecond) { }
|
|
|
|
Seconds(int64_t seconds) :
|
|
TimeDifference(seconds, 0, kNanosecondsPerSecond) { }
|
|
};
|
|
|
|
class Milliseconds : public TimeDifference {
|
|
public:
|
|
explicit Milliseconds(const TimeDifference& difference) :
|
|
TimeDifference(difference, kScale) { }
|
|
|
|
Milliseconds(int64_t ms) : TimeDifference(
|
|
ms / 1000, (ms % 1000) * kScale, kScale) { }
|
|
|
|
protected:
|
|
static const int kScale = kNanosecondsPerSecond / 1000;
|
|
};
|
|
|
|
class Microseconds : public TimeDifference {
|
|
public:
|
|
explicit Microseconds(const TimeDifference& difference) :
|
|
TimeDifference(difference, kScale) { }
|
|
|
|
Microseconds(int64_t micros) : TimeDifference(
|
|
micros / 1000000, (micros % 1000000) * kScale, kScale) { }
|
|
|
|
protected:
|
|
static const int kScale = kNanosecondsPerSecond / 1000000;
|
|
};
|
|
|
|
class Nanoseconds : public TimeDifference {
|
|
public:
|
|
explicit Nanoseconds(const TimeDifference& difference) :
|
|
TimeDifference(difference, 1) { }
|
|
Nanoseconds(int64_t ns) : TimeDifference(ns / kNanosecondsPerSecond,
|
|
ns % kNanosecondsPerSecond, 1) { }
|
|
};
|
|
|
|
} // namespace time
|
|
} // namespace cuttlefish
|
|
|
|
/**
|
|
* Legacy support for microseconds. Use MonotonicTimePoint in new code.
|
|
*/
|
|
static const int64_t kSecsToUsecs = static_cast<int64_t>(1000) * 1000;
|
|
|
|
static inline int64_t get_monotonic_usecs() {
|
|
return cuttlefish::time::Microseconds(
|
|
cuttlefish::time::MonotonicTimePoint::Now().SinceEpoch()).count();
|
|
}
|