| // Copyright 2013 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_BASE_PLATFORM_TIME_H_ |
| #define V8_BASE_PLATFORM_TIME_H_ |
| |
| #include <stdint.h> |
| |
| #include <ctime> |
| #include <iosfwd> |
| #include <limits> |
| |
| #include "src/base/base-export.h" |
| #include "src/base/bits.h" |
| #include "src/base/macros.h" |
| #include "src/base/safe_conversions.h" |
| #if V8_OS_WIN |
| #include "src/base/win32-headers.h" |
| #endif |
| |
| // Forward declarations. |
| extern "C" { |
| struct _FILETIME; |
| struct mach_timespec; |
| struct timespec; |
| struct timeval; |
| } |
| |
| namespace v8 { |
| namespace base { |
| |
| class Time; |
| class TimeDelta; |
| class TimeTicks; |
| |
| namespace time_internal { |
| template<class TimeClass> |
| class TimeBase; |
| } // namespace time_internal |
| |
| class TimeConstants { |
| public: |
| static constexpr int64_t kHoursPerDay = 24; |
| static constexpr int64_t kMillisecondsPerSecond = 1000; |
| static constexpr int64_t kMillisecondsPerDay = |
| kMillisecondsPerSecond * 60 * 60 * kHoursPerDay; |
| static constexpr int64_t kMicrosecondsPerMillisecond = 1000; |
| static constexpr int64_t kMicrosecondsPerSecond = |
| kMicrosecondsPerMillisecond * kMillisecondsPerSecond; |
| static constexpr int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60; |
| static constexpr int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60; |
| static constexpr int64_t kMicrosecondsPerDay = |
| kMicrosecondsPerHour * kHoursPerDay; |
| static constexpr int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7; |
| static constexpr int64_t kNanosecondsPerMicrosecond = 1000; |
| static constexpr int64_t kNanosecondsPerSecond = |
| kNanosecondsPerMicrosecond * kMicrosecondsPerSecond; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| // TimeDelta |
| // |
| // This class represents a duration of time, internally represented in |
| // microseonds. |
| |
| class V8_BASE_EXPORT TimeDelta final { |
| public: |
| constexpr TimeDelta() : delta_(0) {} |
| |
| // Converts units of time to TimeDeltas. |
| static constexpr TimeDelta FromDays(int days) { |
| return TimeDelta(days * TimeConstants::kMicrosecondsPerDay); |
| } |
| static constexpr TimeDelta FromHours(int hours) { |
| return TimeDelta(hours * TimeConstants::kMicrosecondsPerHour); |
| } |
| static constexpr TimeDelta FromMinutes(int minutes) { |
| return TimeDelta(minutes * TimeConstants::kMicrosecondsPerMinute); |
| } |
| static constexpr TimeDelta FromSeconds(int64_t seconds) { |
| return TimeDelta(seconds * TimeConstants::kMicrosecondsPerSecond); |
| } |
| static constexpr TimeDelta FromMilliseconds(int64_t milliseconds) { |
| return TimeDelta(milliseconds * TimeConstants::kMicrosecondsPerMillisecond); |
| } |
| static constexpr TimeDelta FromMicroseconds(int64_t microseconds) { |
| return TimeDelta(microseconds); |
| } |
| static constexpr TimeDelta FromNanoseconds(int64_t nanoseconds) { |
| return TimeDelta(nanoseconds / TimeConstants::kNanosecondsPerMicrosecond); |
| } |
| |
| static TimeDelta FromSecondsD(double seconds) { |
| return FromDouble(seconds * TimeConstants::kMicrosecondsPerSecond); |
| } |
| static TimeDelta FromMillisecondsD(double milliseconds) { |
| return FromDouble(milliseconds * |
| TimeConstants::kMicrosecondsPerMillisecond); |
| } |
| |
| // Returns the maximum time delta, which should be greater than any reasonable |
| // time delta we might compare it to. Adding or subtracting the maximum time |
| // delta to a time or another time delta has an undefined result. |
| static constexpr TimeDelta Max(); |
| |
| // Returns the minimum time delta, which should be less than than any |
| // reasonable time delta we might compare it to. Adding or subtracting the |
| // minimum time delta to a time or another time delta has an undefined result. |
| static constexpr TimeDelta Min(); |
| |
| // Returns true if the time delta is zero. |
| constexpr bool IsZero() const { return delta_ == 0; } |
| |
| // Returns true if the time delta is the maximum/minimum time delta. |
| constexpr bool IsMax() const { |
| return delta_ == std::numeric_limits<int64_t>::max(); |
| } |
| constexpr bool IsMin() const { |
| return delta_ == std::numeric_limits<int64_t>::min(); |
| } |
| |
| // Returns the time delta in some unit. The F versions return a floating |
| // point value, the "regular" versions return a rounded-down value. |
| // |
| // InMillisecondsRoundedUp() instead returns an integer that is rounded up |
| // to the next full millisecond. |
| int InDays() const; |
| int InHours() const; |
| int InMinutes() const; |
| double InSecondsF() const; |
| int64_t InSeconds() const; |
| double InMillisecondsF() const; |
| int64_t InMilliseconds() const; |
| int64_t InMillisecondsRoundedUp() const; |
| int64_t InMicroseconds() const; |
| int64_t InNanoseconds() const; |
| |
| // Converts to/from Mach time specs. |
| static TimeDelta FromMachTimespec(struct mach_timespec ts); |
| struct mach_timespec ToMachTimespec() const; |
| |
| // Converts to/from POSIX time specs. |
| static TimeDelta FromTimespec(struct timespec ts); |
| struct timespec ToTimespec() const; |
| |
| // Computations with other deltas. |
| TimeDelta operator+(const TimeDelta& other) const { |
| return TimeDelta(delta_ + other.delta_); |
| } |
| TimeDelta operator-(const TimeDelta& other) const { |
| return TimeDelta(delta_ - other.delta_); |
| } |
| |
| TimeDelta& operator+=(const TimeDelta& other) { |
| delta_ += other.delta_; |
| return *this; |
| } |
| TimeDelta& operator-=(const TimeDelta& other) { |
| delta_ -= other.delta_; |
| return *this; |
| } |
| constexpr TimeDelta operator-() const { return TimeDelta(-delta_); } |
| |
| double TimesOf(const TimeDelta& other) const { |
| return static_cast<double>(delta_) / static_cast<double>(other.delta_); |
| } |
| double PercentOf(const TimeDelta& other) const { |
| return TimesOf(other) * 100.0; |
| } |
| |
| // Computations with ints, note that we only allow multiplicative operations |
| // with ints, and additive operations with other deltas. |
| TimeDelta operator*(int64_t a) const { |
| return TimeDelta(delta_ * a); |
| } |
| TimeDelta operator/(int64_t a) const { |
| return TimeDelta(delta_ / a); |
| } |
| TimeDelta& operator*=(int64_t a) { |
| delta_ *= a; |
| return *this; |
| } |
| TimeDelta& operator/=(int64_t a) { |
| delta_ /= a; |
| return *this; |
| } |
| int64_t operator/(const TimeDelta& other) const { |
| return delta_ / other.delta_; |
| } |
| |
| // Comparison operators. |
| constexpr bool operator==(const TimeDelta& other) const { |
| return delta_ == other.delta_; |
| } |
| constexpr bool operator!=(const TimeDelta& other) const { |
| return delta_ != other.delta_; |
| } |
| constexpr bool operator<(const TimeDelta& other) const { |
| return delta_ < other.delta_; |
| } |
| constexpr bool operator<=(const TimeDelta& other) const { |
| return delta_ <= other.delta_; |
| } |
| constexpr bool operator>(const TimeDelta& other) const { |
| return delta_ > other.delta_; |
| } |
| constexpr bool operator>=(const TimeDelta& other) const { |
| return delta_ >= other.delta_; |
| } |
| |
| private: |
| // TODO(v8:10620): constexpr requires constexpr saturated_cast. |
| static inline TimeDelta FromDouble(double value); |
| |
| template<class TimeClass> friend class time_internal::TimeBase; |
| // Constructs a delta given the duration in microseconds. This is private |
| // to avoid confusion by callers with an integer constructor. Use |
| // FromSeconds, FromMilliseconds, etc. instead. |
| explicit constexpr TimeDelta(int64_t delta) : delta_(delta) {} |
| |
| // Delta in microseconds. |
| int64_t delta_; |
| }; |
| |
| // static |
| TimeDelta TimeDelta::FromDouble(double value) { |
| return TimeDelta(saturated_cast<int64_t>(value)); |
| } |
| |
| // static |
| constexpr TimeDelta TimeDelta::Max() { |
| return TimeDelta(std::numeric_limits<int64_t>::max()); |
| } |
| |
| // static |
| constexpr TimeDelta TimeDelta::Min() { |
| return TimeDelta(std::numeric_limits<int64_t>::min()); |
| } |
| |
| namespace time_internal { |
| |
| // TimeBase-------------------------------------------------------------------- |
| |
| // Provides value storage and comparison/math operations common to all time |
| // classes. Each subclass provides for strong type-checking to ensure |
| // semantically meaningful comparison/math of time values from the same clock |
| // source or timeline. |
| template <class TimeClass> |
| class TimeBase : public TimeConstants { |
| public: |
| #if V8_OS_WIN |
| // To avoid overflow in QPC to Microseconds calculations, since we multiply |
| // by kMicrosecondsPerSecond, then the QPC value should not exceed |
| // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply. |
| static constexpr int64_t kQPCOverflowThreshold = INT64_C(0x8637BD05AF7); |
| #endif |
| |
| // Returns true if this object has not been initialized. |
| // |
| // Warning: Be careful when writing code that performs math on time values, |
| // since it's possible to produce a valid "zero" result that should not be |
| // interpreted as a "null" value. |
| constexpr bool IsNull() const { return us_ == 0; } |
| |
| // Returns the maximum/minimum times, which should be greater/less than any |
| // reasonable time with which we might compare it. |
| static TimeClass Max() { |
| return TimeClass(std::numeric_limits<int64_t>::max()); |
| } |
| static TimeClass Min() { |
| return TimeClass(std::numeric_limits<int64_t>::min()); |
| } |
| |
| // Returns true if this object represents the maximum/minimum time. |
| constexpr bool IsMax() const { |
| return us_ == std::numeric_limits<int64_t>::max(); |
| } |
| constexpr bool IsMin() const { |
| return us_ == std::numeric_limits<int64_t>::min(); |
| } |
| |
| // For serializing only. Use FromInternalValue() to reconstitute. Please don't |
| // use this and do arithmetic on it, as it is more error prone than using the |
| // provided operators. |
| int64_t ToInternalValue() const { return us_; } |
| |
| // The amount of time since the origin (or "zero") point. This is a syntactic |
| // convenience to aid in code readability, mainly for debugging/testing use |
| // cases. |
| // |
| // Warning: While the Time subclass has a fixed origin point, the origin for |
| // the other subclasses can vary each time the application is restarted. |
| constexpr TimeDelta since_origin() const { |
| return TimeDelta::FromMicroseconds(us_); |
| } |
| |
| TimeClass& operator=(TimeClass other) { |
| us_ = other.us_; |
| return *(static_cast<TimeClass*>(this)); |
| } |
| |
| // Compute the difference between two times. |
| TimeDelta operator-(TimeClass other) const { |
| return TimeDelta::FromMicroseconds(us_ - other.us_); |
| } |
| |
| // Return a new time modified by some delta. |
| TimeClass operator+(TimeDelta delta) const { |
| return TimeClass(bits::SignedSaturatedAdd64(delta.delta_, us_)); |
| } |
| TimeClass operator-(TimeDelta delta) const { |
| return TimeClass(-bits::SignedSaturatedSub64(delta.delta_, us_)); |
| } |
| |
| // Modify by some time delta. |
| TimeClass& operator+=(TimeDelta delta) { |
| return static_cast<TimeClass&>(*this = (*this + delta)); |
| } |
| TimeClass& operator-=(TimeDelta delta) { |
| return static_cast<TimeClass&>(*this = (*this - delta)); |
| } |
| |
| // Comparison operators |
| bool operator==(TimeClass other) const { |
| return us_ == other.us_; |
| } |
| bool operator!=(TimeClass other) const { |
| return us_ != other.us_; |
| } |
| bool operator<(TimeClass other) const { |
| return us_ < other.us_; |
| } |
| bool operator<=(TimeClass other) const { |
| return us_ <= other.us_; |
| } |
| bool operator>(TimeClass other) const { |
| return us_ > other.us_; |
| } |
| bool operator>=(TimeClass other) const { |
| return us_ >= other.us_; |
| } |
| |
| // Converts an integer value representing TimeClass to a class. This is used |
| // when deserializing a |TimeClass| structure, using a value known to be |
| // compatible. It is not provided as a constructor because the integer type |
| // may be unclear from the perspective of a caller. |
| static TimeClass FromInternalValue(int64_t us) { return TimeClass(us); } |
| |
| protected: |
| explicit constexpr TimeBase(int64_t us) : us_(us) {} |
| |
| // Time value in a microsecond timebase. |
| int64_t us_; |
| }; |
| |
| } // namespace time_internal |
| |
| |
| // ----------------------------------------------------------------------------- |
| // Time |
| // |
| // This class represents an absolute point in time, internally represented as |
| // microseconds (s/1,000,000) since 00:00:00 UTC, January 1, 1970. |
| |
| class V8_BASE_EXPORT Time final : public time_internal::TimeBase<Time> { |
| public: |
| // Contains the nullptr time. Use Time::Now() to get the current time. |
| constexpr Time() : TimeBase(0) {} |
| |
| // Returns the current time. Watch out, the system might adjust its clock |
| // in which case time will actually go backwards. We don't guarantee that |
| // times are increasing, or that two calls to Now() won't be the same. |
| static Time Now(); |
| |
| // Returns the current time. Same as Now() except that this function always |
| // uses system time so that there are no discrepancies between the returned |
| // time and system time even on virtual environments including our test bot. |
| // For timing sensitive unittests, this function should be used. |
| static Time NowFromSystemTime(); |
| |
| // Returns the time for epoch in Unix-like system (Jan 1, 1970). |
| static Time UnixEpoch() { return Time(0); } |
| |
| // Converts to/from POSIX time specs. |
| static Time FromTimespec(struct timespec ts); |
| struct timespec ToTimespec() const; |
| |
| // Converts to/from POSIX time values. |
| static Time FromTimeval(struct timeval tv); |
| struct timeval ToTimeval() const; |
| |
| // Converts to/from Windows file times. |
| static Time FromFiletime(struct _FILETIME ft); |
| struct _FILETIME ToFiletime() const; |
| |
| // Converts to/from the Javascript convention for times, a number of |
| // milliseconds since the epoch: |
| static Time FromJsTime(double ms_since_epoch); |
| double ToJsTime() const; |
| |
| private: |
| friend class time_internal::TimeBase<Time>; |
| explicit constexpr Time(int64_t us) : TimeBase(us) {} |
| }; |
| |
| V8_BASE_EXPORT std::ostream& operator<<(std::ostream&, const Time&); |
| |
| inline Time operator+(const TimeDelta& delta, const Time& time) { |
| return time + delta; |
| } |
| |
| |
| // ----------------------------------------------------------------------------- |
| // TimeTicks |
| // |
| // This class represents an abstract time that is most of the time incrementing |
| // for use in measuring time durations. It is internally represented in |
| // microseconds. It can not be converted to a human-readable time, but is |
| // guaranteed not to decrease (if the user changes the computer clock, |
| // Time::Now() may actually decrease or jump). But note that TimeTicks may |
| // "stand still", for example if the computer suspended. |
| |
| class V8_BASE_EXPORT TimeTicks final |
| : public time_internal::TimeBase<TimeTicks> { |
| public: |
| constexpr TimeTicks() : TimeBase(0) {} |
| |
| // Platform-dependent tick count representing "right now." When |
| // IsHighResolution() returns false, the resolution of the clock could be as |
| // coarse as ~15.6ms. Otherwise, the resolution should be no worse than one |
| // microsecond. |
| // This method never returns a null TimeTicks. |
| static TimeTicks Now(); |
| |
| // This is equivalent to Now() but DCHECKs that IsHighResolution(). Useful for |
| // test frameworks that rely on high resolution clocks (in practice all |
| // platforms but low-end Windows devices have high resolution clocks). |
| static TimeTicks HighResolutionNow(); |
| |
| // Returns true if the high-resolution clock is working on this system. |
| static bool IsHighResolution(); |
| |
| private: |
| friend class time_internal::TimeBase<TimeTicks>; |
| |
| // Please use Now() to create a new object. This is for internal use |
| // and testing. Ticks are in microseconds. |
| explicit constexpr TimeTicks(int64_t ticks) : TimeBase(ticks) {} |
| }; |
| |
| inline TimeTicks operator+(const TimeDelta& delta, const TimeTicks& ticks) { |
| return ticks + delta; |
| } |
| |
| |
| // ThreadTicks ---------------------------------------------------------------- |
| |
| // Represents a clock, specific to a particular thread, than runs only while the |
| // thread is running. |
| class V8_BASE_EXPORT ThreadTicks final |
| : public time_internal::TimeBase<ThreadTicks> { |
| public: |
| constexpr ThreadTicks() : TimeBase(0) {} |
| |
| // Returns true if ThreadTicks::Now() is supported on this system. |
| static bool IsSupported(); |
| |
| // Waits until the initialization is completed. Needs to be guarded with a |
| // call to IsSupported(). |
| static void WaitUntilInitialized() { |
| #if V8_OS_WIN |
| WaitUntilInitializedWin(); |
| #endif |
| } |
| |
| // Returns thread-specific CPU-time on systems that support this feature. |
| // Needs to be guarded with a call to IsSupported(). Use this timer |
| // to (approximately) measure how much time the calling thread spent doing |
| // actual work vs. being de-scheduled. May return bogus results if the thread |
| // migrates to another CPU between two calls. Returns an empty ThreadTicks |
| // object until the initialization is completed. If a clock reading is |
| // absolutely needed, call WaitUntilInitialized() before this method. |
| static ThreadTicks Now(); |
| |
| #if V8_OS_WIN |
| // Similar to Now() above except this returns thread-specific CPU time for an |
| // arbitrary thread. All comments for Now() method above apply apply to this |
| // method as well. |
| static ThreadTicks GetForThread(const HANDLE& thread_handle); |
| #endif |
| |
| private: |
| template <class TimeClass> |
| friend class time_internal::TimeBase; |
| |
| // Please use Now() or GetForThread() to create a new object. This is for |
| // internal use and testing. Ticks are in microseconds. |
| explicit constexpr ThreadTicks(int64_t ticks) : TimeBase(ticks) {} |
| |
| #if V8_OS_WIN |
| // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't |
| // been measured yet. Needs to be guarded with a call to IsSupported(). |
| static double TSCTicksPerSecond(); |
| static bool IsSupportedWin(); |
| static void WaitUntilInitializedWin(); |
| #endif |
| }; |
| |
| } // namespace base |
| } // namespace v8 |
| |
| #endif // V8_BASE_PLATFORM_TIME_H_ |