LCOV - code coverage report
Current view: top level - src/base/platform - time.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 80 92 87.0 %
Date: 2017-10-20 Functions: 26 30 86.7 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/base/platform/time.h"
       6             : 
       7             : #if V8_OS_POSIX
       8             : #include <fcntl.h>  // for O_RDONLY
       9             : #include <sys/time.h>
      10             : #include <unistd.h>
      11             : #endif
      12             : #if V8_OS_MACOSX
      13             : #include <mach/mach.h>
      14             : #include <mach/mach_time.h>
      15             : #include <pthread.h>
      16             : #endif
      17             : 
      18             : #include <cstring>
      19             : #include <ostream>
      20             : 
      21             : #if V8_OS_WIN
      22             : #include "src/base/atomicops.h"
      23             : #include "src/base/lazy-instance.h"
      24             : #include "src/base/win32-headers.h"
      25             : #endif
      26             : #include "src/base/cpu.h"
      27             : #include "src/base/logging.h"
      28             : #include "src/base/platform/platform.h"
      29             : 
      30             : namespace {
      31             : 
      32             : #if V8_OS_MACOSX
      33             : int64_t ComputeThreadTicks() {
      34             :   mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
      35             :   thread_basic_info_data_t thread_info_data;
      36             :   kern_return_t kr = thread_info(
      37             :       pthread_mach_thread_np(pthread_self()),
      38             :       THREAD_BASIC_INFO,
      39             :       reinterpret_cast<thread_info_t>(&thread_info_data),
      40             :       &thread_info_count);
      41             :   CHECK_EQ(kr, KERN_SUCCESS);
      42             : 
      43             :   v8::base::CheckedNumeric<int64_t> absolute_micros(
      44             :       thread_info_data.user_time.seconds +
      45             :       thread_info_data.system_time.seconds);
      46             :   absolute_micros *= v8::base::Time::kMicrosecondsPerSecond;
      47             :   absolute_micros += (thread_info_data.user_time.microseconds +
      48             :                       thread_info_data.system_time.microseconds);
      49             :   return absolute_micros.ValueOrDie();
      50             : }
      51             : #elif V8_OS_POSIX
      52             : // Helper function to get results from clock_gettime() and convert to a
      53             : // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
      54             : // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
      55             : // _POSIX_MONOTONIC_CLOCK to -1.
      56             : V8_INLINE int64_t ClockNow(clockid_t clk_id) {
      57             : #if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
      58             :   defined(V8_OS_BSD) || defined(V8_OS_ANDROID)
      59             : // On AIX clock_gettime for CLOCK_THREAD_CPUTIME_ID outputs time with
      60             : // resolution of 10ms. thread_cputime API provides the time in ns
      61             : #if defined(V8_OS_AIX)
      62             :   thread_cputime_t tc;
      63             :   if (clk_id == CLOCK_THREAD_CPUTIME_ID) {
      64             :     if (thread_cputime(-1, &tc) != 0) {
      65             :       UNREACHABLE();
      66             :     }
      67             :   }
      68             : #endif
      69             :   struct timespec ts;
      70    28112038 :   if (clock_gettime(clk_id, &ts) != 0) {
      71           0 :     UNREACHABLE();
      72             :   }
      73    28112652 :   v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec);
      74    28112652 :   result *= v8::base::Time::kMicrosecondsPerSecond;
      75             : #if defined(V8_OS_AIX)
      76             :   if (clk_id == CLOCK_THREAD_CPUTIME_ID) {
      77             :     result += (tc.stime / v8::base::Time::kNanosecondsPerMicrosecond);
      78             :   } else {
      79             :     result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
      80             :   }
      81             : #else
      82    28112997 :   result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond);
      83             : #endif
      84    28113004 :   return result.ValueOrDie();
      85             : #else  // Monotonic clock not supported.
      86             :   return 0;
      87             : #endif
      88             : }
      89             : #elif V8_OS_WIN
      90             : V8_INLINE bool IsQPCReliable() {
      91             :   v8::base::CPU cpu;
      92             :   // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
      93             :   return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15;
      94             : }
      95             : 
      96             : // Returns the current value of the performance counter.
      97             : V8_INLINE uint64_t QPCNowRaw() {
      98             :   LARGE_INTEGER perf_counter_now = {};
      99             :   // According to the MSDN documentation for QueryPerformanceCounter(), this
     100             :   // will never fail on systems that run XP or later.
     101             :   // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
     102             :   BOOL result = ::QueryPerformanceCounter(&perf_counter_now);
     103             :   DCHECK(result);
     104             :   USE(result);
     105             :   return perf_counter_now.QuadPart;
     106             : }
     107             : #endif  // V8_OS_MACOSX
     108             : 
     109             : 
     110             : }  // namespace
     111             : 
     112             : namespace v8 {
     113             : namespace base {
     114             : 
     115           2 : TimeDelta TimeDelta::FromDays(int days) {
     116           2 :   return TimeDelta(days * Time::kMicrosecondsPerDay);
     117             : }
     118             : 
     119             : 
     120           3 : TimeDelta TimeDelta::FromHours(int hours) {
     121           3 :   return TimeDelta(hours * Time::kMicrosecondsPerHour);
     122             : }
     123             : 
     124             : 
     125           3 : TimeDelta TimeDelta::FromMinutes(int minutes) {
     126           3 :   return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
     127             : }
     128             : 
     129             : 
     130          12 : TimeDelta TimeDelta::FromSeconds(int64_t seconds) {
     131          12 :   return TimeDelta(seconds * Time::kMicrosecondsPerSecond);
     132             : }
     133             : 
     134             : 
     135      203332 : TimeDelta TimeDelta::FromMilliseconds(int64_t milliseconds) {
     136      203332 :   return TimeDelta(milliseconds * Time::kMicrosecondsPerMillisecond);
     137             : }
     138             : 
     139             : 
     140          36 : TimeDelta TimeDelta::FromNanoseconds(int64_t nanoseconds) {
     141          36 :   return TimeDelta(nanoseconds / Time::kNanosecondsPerMicrosecond);
     142             : }
     143             : 
     144             : 
     145           1 : int TimeDelta::InDays() const {
     146           1 :   return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
     147             : }
     148             : 
     149             : 
     150           1 : int TimeDelta::InHours() const {
     151           1 :   return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
     152             : }
     153             : 
     154             : 
     155           1 : int TimeDelta::InMinutes() const {
     156           1 :   return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
     157             : }
     158             : 
     159             : 
     160           1 : double TimeDelta::InSecondsF() const {
     161           1 :   return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
     162             : }
     163             : 
     164             : 
     165           1 : int64_t TimeDelta::InSeconds() const {
     166           1 :   return delta_ / Time::kMicrosecondsPerSecond;
     167             : }
     168             : 
     169             : 
     170     1328071 : double TimeDelta::InMillisecondsF() const {
     171     1328071 :   return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
     172             : }
     173             : 
     174             : 
     175           1 : int64_t TimeDelta::InMilliseconds() const {
     176           1 :   return delta_ / Time::kMicrosecondsPerMillisecond;
     177             : }
     178             : 
     179             : 
     180           0 : int64_t TimeDelta::InNanoseconds() const {
     181           0 :   return delta_ * Time::kNanosecondsPerMicrosecond;
     182             : }
     183             : 
     184             : 
     185             : #if V8_OS_MACOSX
     186             : 
     187             : TimeDelta TimeDelta::FromMachTimespec(struct mach_timespec ts) {
     188             :   DCHECK_GE(ts.tv_nsec, 0);
     189             :   DCHECK_LT(ts.tv_nsec,
     190             :             static_cast<long>(Time::kNanosecondsPerSecond));  // NOLINT
     191             :   return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
     192             :                    ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
     193             : }
     194             : 
     195             : 
     196             : struct mach_timespec TimeDelta::ToMachTimespec() const {
     197             :   struct mach_timespec ts;
     198             :   DCHECK_GE(delta_, 0);
     199             :   ts.tv_sec = static_cast<unsigned>(delta_ / Time::kMicrosecondsPerSecond);
     200             :   ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
     201             :       Time::kNanosecondsPerMicrosecond;
     202             :   return ts;
     203             : }
     204             : 
     205             : #endif  // V8_OS_MACOSX
     206             : 
     207             : 
     208             : #if V8_OS_POSIX
     209             : 
     210           0 : TimeDelta TimeDelta::FromTimespec(struct timespec ts) {
     211             :   DCHECK_GE(ts.tv_nsec, 0);
     212             :   DCHECK_LT(ts.tv_nsec,
     213             :             static_cast<long>(Time::kNanosecondsPerSecond));  // NOLINT
     214           0 :   return TimeDelta(ts.tv_sec * Time::kMicrosecondsPerSecond +
     215           0 :                    ts.tv_nsec / Time::kNanosecondsPerMicrosecond);
     216             : }
     217             : 
     218             : 
     219           0 : struct timespec TimeDelta::ToTimespec() const {
     220             :   struct timespec ts;
     221           0 :   ts.tv_sec = static_cast<time_t>(delta_ / Time::kMicrosecondsPerSecond);
     222           0 :   ts.tv_nsec = (delta_ % Time::kMicrosecondsPerSecond) *
     223             :       Time::kNanosecondsPerMicrosecond;
     224           0 :   return ts;
     225             : }
     226             : 
     227             : #endif  // V8_OS_POSIX
     228             : 
     229             : 
     230             : #if V8_OS_WIN
     231             : 
     232             : // We implement time using the high-resolution timers so that we can get
     233             : // timeouts which are smaller than 10-15ms. To avoid any drift, we
     234             : // periodically resync the internal clock to the system clock.
     235             : class Clock final {
     236             :  public:
     237             :   Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {}
     238             : 
     239             :   Time Now() {
     240             :     // Time between resampling the un-granular clock for this API (1 minute).
     241             :     const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(1);
     242             : 
     243             :     LockGuard<Mutex> lock_guard(&mutex_);
     244             : 
     245             :     // Determine current time and ticks.
     246             :     TimeTicks ticks = GetSystemTicks();
     247             :     Time time = GetSystemTime();
     248             : 
     249             :     // Check if we need to synchronize with the system clock due to a backwards
     250             :     // time change or the amount of time elapsed.
     251             :     TimeDelta elapsed = ticks - initial_ticks_;
     252             :     if (time < initial_time_ || elapsed > kMaxElapsedTime) {
     253             :       initial_ticks_ = ticks;
     254             :       initial_time_ = time;
     255             :       return time;
     256             :     }
     257             : 
     258             :     return initial_time_ + elapsed;
     259             :   }
     260             : 
     261             :   Time NowFromSystemTime() {
     262             :     LockGuard<Mutex> lock_guard(&mutex_);
     263             :     initial_ticks_ = GetSystemTicks();
     264             :     initial_time_ = GetSystemTime();
     265             :     return initial_time_;
     266             :   }
     267             : 
     268             :  private:
     269             :   static TimeTicks GetSystemTicks() {
     270             :     return TimeTicks::Now();
     271             :   }
     272             : 
     273             :   static Time GetSystemTime() {
     274             :     FILETIME ft;
     275             :     ::GetSystemTimeAsFileTime(&ft);
     276             :     return Time::FromFiletime(ft);
     277             :   }
     278             : 
     279             :   TimeTicks initial_ticks_;
     280             :   Time initial_time_;
     281             :   Mutex mutex_;
     282             : };
     283             : 
     284             : 
     285             : static LazyStaticInstance<Clock, DefaultConstructTrait<Clock>,
     286             :                           ThreadSafeInitOnceTrait>::type clock =
     287             :     LAZY_STATIC_INSTANCE_INITIALIZER;
     288             : 
     289             : 
     290             : Time Time::Now() {
     291             :   return clock.Pointer()->Now();
     292             : }
     293             : 
     294             : 
     295             : Time Time::NowFromSystemTime() {
     296             :   return clock.Pointer()->NowFromSystemTime();
     297             : }
     298             : 
     299             : 
     300             : // Time between windows epoch and standard epoch.
     301             : static const int64_t kTimeToEpochInMicroseconds = V8_INT64_C(11644473600000000);
     302             : 
     303             : 
     304             : Time Time::FromFiletime(FILETIME ft) {
     305             :   if (ft.dwLowDateTime == 0 && ft.dwHighDateTime == 0) {
     306             :     return Time();
     307             :   }
     308             :   if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
     309             :       ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
     310             :     return Max();
     311             :   }
     312             :   int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
     313             :                 (static_cast<uint64_t>(ft.dwHighDateTime) << 32)) / 10;
     314             :   return Time(us - kTimeToEpochInMicroseconds);
     315             : }
     316             : 
     317             : 
     318             : FILETIME Time::ToFiletime() const {
     319             :   DCHECK_GE(us_, 0);
     320             :   FILETIME ft;
     321             :   if (IsNull()) {
     322             :     ft.dwLowDateTime = 0;
     323             :     ft.dwHighDateTime = 0;
     324             :     return ft;
     325             :   }
     326             :   if (IsMax()) {
     327             :     ft.dwLowDateTime = std::numeric_limits<DWORD>::max();
     328             :     ft.dwHighDateTime = std::numeric_limits<DWORD>::max();
     329             :     return ft;
     330             :   }
     331             :   uint64_t us = static_cast<uint64_t>(us_ + kTimeToEpochInMicroseconds) * 10;
     332             :   ft.dwLowDateTime = static_cast<DWORD>(us);
     333             :   ft.dwHighDateTime = static_cast<DWORD>(us >> 32);
     334             :   return ft;
     335             : }
     336             : 
     337             : #elif V8_OS_POSIX
     338             : 
     339      184588 : Time Time::Now() {
     340             :   struct timeval tv;
     341      184588 :   int result = gettimeofday(&tv, nullptr);
     342             :   DCHECK_EQ(0, result);
     343             :   USE(result);
     344      184588 :   return FromTimeval(tv);
     345             : }
     346             : 
     347             : 
     348         214 : Time Time::NowFromSystemTime() {
     349         214 :   return Now();
     350             : }
     351             : 
     352             : 
     353          34 : Time Time::FromTimespec(struct timespec ts) {
     354             :   DCHECK_GE(ts.tv_nsec, 0);
     355             :   DCHECK_LT(ts.tv_nsec, kNanosecondsPerSecond);
     356          34 :   if (ts.tv_nsec == 0 && ts.tv_sec == 0) {
     357           2 :     return Time();
     358             :   }
     359          32 :   if (ts.tv_nsec == static_cast<long>(kNanosecondsPerSecond - 1) &&  // NOLINT
     360             :       ts.tv_sec == std::numeric_limits<time_t>::max()) {
     361             :     return Max();
     362             :   }
     363          31 :   return Time(ts.tv_sec * kMicrosecondsPerSecond +
     364          31 :               ts.tv_nsec / kNanosecondsPerMicrosecond);
     365             : }
     366             : 
     367             : 
     368         246 : struct timespec Time::ToTimespec() const {
     369             :   struct timespec ts;
     370         246 :   if (IsNull()) {
     371             :     ts.tv_sec = 0;
     372             :     ts.tv_nsec = 0;
     373           2 :     return ts;
     374             :   }
     375         244 :   if (IsMax()) {
     376             :     ts.tv_sec = std::numeric_limits<time_t>::max();
     377             :     ts.tv_nsec = static_cast<long>(kNanosecondsPerSecond - 1);  // NOLINT
     378           1 :     return ts;
     379             :   }
     380         243 :   ts.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
     381         243 :   ts.tv_nsec = (us_ % kMicrosecondsPerSecond) * kNanosecondsPerMicrosecond;
     382         243 :   return ts;
     383             : }
     384             : 
     385             : 
     386           5 : Time Time::FromTimeval(struct timeval tv) {
     387             :   DCHECK_GE(tv.tv_usec, 0);
     388             :   DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
     389      184593 :   if (tv.tv_usec == 0 && tv.tv_sec == 0) {
     390           2 :     return Time();
     391             :   }
     392      184591 :   if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - 1) &&
     393             :       tv.tv_sec == std::numeric_limits<time_t>::max()) {
     394             :     return Max();
     395             :   }
     396      184590 :   return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
     397             : }
     398             : 
     399             : 
     400           5 : struct timeval Time::ToTimeval() const {
     401             :   struct timeval tv;
     402           5 :   if (IsNull()) {
     403             :     tv.tv_sec = 0;
     404             :     tv.tv_usec = 0;
     405           2 :     return tv;
     406             :   }
     407           3 :   if (IsMax()) {
     408             :     tv.tv_sec = std::numeric_limits<time_t>::max();
     409             :     tv.tv_usec = static_cast<suseconds_t>(kMicrosecondsPerSecond - 1);
     410           1 :     return tv;
     411             :   }
     412           2 :   tv.tv_sec = static_cast<time_t>(us_ / kMicrosecondsPerSecond);
     413           2 :   tv.tv_usec = us_ % kMicrosecondsPerSecond;
     414           2 :   return tv;
     415             : }
     416             : 
     417             : #endif  // V8_OS_WIN
     418             : 
     419             : 
     420           1 : Time Time::FromJsTime(double ms_since_epoch) {
     421             :   // The epoch is a valid time, so this constructor doesn't interpret
     422             :   // 0 as the null time.
     423           1 :   if (ms_since_epoch == std::numeric_limits<double>::max()) {
     424             :     return Max();
     425             :   }
     426             :   return Time(
     427           1 :       static_cast<int64_t>(ms_since_epoch * kMicrosecondsPerMillisecond));
     428             : }
     429             : 
     430             : 
     431      184369 : double Time::ToJsTime() const {
     432      184369 :   if (IsNull()) {
     433             :     // Preserve 0 so the invalid result doesn't depend on the platform.
     434             :     return 0;
     435             :   }
     436      184369 :   if (IsMax()) {
     437             :     // Preserve max without offset to prevent overflow.
     438             :     return std::numeric_limits<double>::max();
     439             :   }
     440      184369 :   return static_cast<double>(us_) / kMicrosecondsPerMillisecond;
     441             : }
     442             : 
     443             : 
     444           0 : std::ostream& operator<<(std::ostream& os, const Time& time) {
     445           0 :   return os << time.ToJsTime();
     446             : }
     447             : 
     448             : 
     449             : #if V8_OS_WIN
     450             : 
     451             : class TickClock {
     452             :  public:
     453             :   virtual ~TickClock() {}
     454             :   virtual int64_t Now() = 0;
     455             :   virtual bool IsHighResolution() = 0;
     456             : };
     457             : 
     458             : 
     459             : // Overview of time counters:
     460             : // (1) CPU cycle counter. (Retrieved via RDTSC)
     461             : // The CPU counter provides the highest resolution time stamp and is the least
     462             : // expensive to retrieve. However, the CPU counter is unreliable and should not
     463             : // be used in production. Its biggest issue is that it is per processor and it
     464             : // is not synchronized between processors. Also, on some computers, the counters
     465             : // will change frequency due to thermal and power changes, and stop in some
     466             : // states.
     467             : //
     468             : // (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
     469             : // resolution (100 nanoseconds) time stamp but is comparatively more expensive
     470             : // to retrieve. What QueryPerformanceCounter actually does is up to the HAL.
     471             : // (with some help from ACPI).
     472             : // According to http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx
     473             : // in the worst case, it gets the counter from the rollover interrupt on the
     474             : // programmable interrupt timer. In best cases, the HAL may conclude that the
     475             : // RDTSC counter runs at a constant frequency, then it uses that instead. On
     476             : // multiprocessor machines, it will try to verify the values returned from
     477             : // RDTSC on each processor are consistent with each other, and apply a handful
     478             : // of workarounds for known buggy hardware. In other words, QPC is supposed to
     479             : // give consistent result on a multiprocessor computer, but it is unreliable in
     480             : // reality due to bugs in BIOS or HAL on some, especially old computers.
     481             : // With recent updates on HAL and newer BIOS, QPC is getting more reliable but
     482             : // it should be used with caution.
     483             : //
     484             : // (3) System time. The system time provides a low-resolution (typically 10ms
     485             : // to 55 milliseconds) time stamp but is comparatively less expensive to
     486             : // retrieve and more reliable.
     487             : class HighResolutionTickClock final : public TickClock {
     488             :  public:
     489             :   explicit HighResolutionTickClock(int64_t ticks_per_second)
     490             :       : ticks_per_second_(ticks_per_second) {
     491             :     DCHECK_LT(0, ticks_per_second);
     492             :   }
     493             :   virtual ~HighResolutionTickClock() {}
     494             : 
     495             :   int64_t Now() override {
     496             :     uint64_t now = QPCNowRaw();
     497             : 
     498             :     // Intentionally calculate microseconds in a round about manner to avoid
     499             :     // overflow and precision issues. Think twice before simplifying!
     500             :     int64_t whole_seconds = now / ticks_per_second_;
     501             :     int64_t leftover_ticks = now % ticks_per_second_;
     502             :     int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) +
     503             :         ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_);
     504             : 
     505             :     // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow()
     506             :     // will never return 0.
     507             :     return ticks + 1;
     508             :   }
     509             : 
     510             :   bool IsHighResolution() override { return true; }
     511             : 
     512             :  private:
     513             :   int64_t ticks_per_second_;
     514             : };
     515             : 
     516             : 
     517             : class RolloverProtectedTickClock final : public TickClock {
     518             :  public:
     519             :   RolloverProtectedTickClock() : rollover_(0) {}
     520             :   virtual ~RolloverProtectedTickClock() {}
     521             : 
     522             :   int64_t Now() override {
     523             :     // We use timeGetTime() to implement TimeTicks::Now(), which rolls over
     524             :     // every ~49.7 days. We try to track rollover ourselves, which works if
     525             :     // TimeTicks::Now() is called at least every 24 days.
     526             :     // Note that we do not use GetTickCount() here, since timeGetTime() gives
     527             :     // more predictable delta values, as described here:
     528             :     // http://blogs.msdn.com/b/larryosterman/archive/2009/09/02/what-s-the-difference-between-gettickcount-and-timegettime.aspx
     529             :     // timeGetTime() provides 1ms granularity when combined with
     530             :     // timeBeginPeriod(). If the host application for V8 wants fast timers, it
     531             :     // can use timeBeginPeriod() to increase the resolution.
     532             :     // We use a lock-free version because the sampler thread calls it
     533             :     // while having the rest of the world stopped, that could cause a deadlock.
     534             :     base::Atomic32 rollover = base::Acquire_Load(&rollover_);
     535             :     uint32_t now = static_cast<uint32_t>(timeGetTime());
     536             :     if ((now >> 31) != static_cast<uint32_t>(rollover & 1)) {
     537             :       base::Release_CompareAndSwap(&rollover_, rollover, rollover + 1);
     538             :       ++rollover;
     539             :     }
     540             :     uint64_t ms = (static_cast<uint64_t>(rollover) << 31) | now;
     541             :     return static_cast<int64_t>(ms * Time::kMicrosecondsPerMillisecond);
     542             :   }
     543             : 
     544             :   bool IsHighResolution() override { return false; }
     545             : 
     546             :  private:
     547             :   base::Atomic32 rollover_;
     548             : };
     549             : 
     550             : 
     551             : static LazyStaticInstance<RolloverProtectedTickClock,
     552             :                           DefaultConstructTrait<RolloverProtectedTickClock>,
     553             :                           ThreadSafeInitOnceTrait>::type tick_clock =
     554             :     LAZY_STATIC_INSTANCE_INITIALIZER;
     555             : 
     556             : 
     557             : struct CreateHighResTickClockTrait {
     558             :   static TickClock* Create() {
     559             :     // Check if the installed hardware supports a high-resolution performance
     560             :     // counter, and if not fallback to the low-resolution tick clock.
     561             :     LARGE_INTEGER ticks_per_second;
     562             :     if (!QueryPerformanceFrequency(&ticks_per_second)) {
     563             :       return tick_clock.Pointer();
     564             :     }
     565             : 
     566             :     // If QPC not reliable, fallback to low-resolution tick clock.
     567             :     if (IsQPCReliable()) {
     568             :       return tick_clock.Pointer();
     569             :     }
     570             : 
     571             :     return new HighResolutionTickClock(ticks_per_second.QuadPart);
     572             :   }
     573             : };
     574             : 
     575             : 
     576             : static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait,
     577             :                            ThreadSafeInitOnceTrait>::type high_res_tick_clock =
     578             :     LAZY_DYNAMIC_INSTANCE_INITIALIZER;
     579             : 
     580             : 
     581             : TimeTicks TimeTicks::Now() {
     582             :   // Make sure we never return 0 here.
     583             :   TimeTicks ticks(tick_clock.Pointer()->Now());
     584             :   DCHECK(!ticks.IsNull());
     585             :   return ticks;
     586             : }
     587             : 
     588             : 
     589             : TimeTicks TimeTicks::HighResolutionNow() {
     590             :   // Make sure we never return 0 here.
     591             :   TimeTicks ticks(high_res_tick_clock.Pointer()->Now());
     592             :   DCHECK(!ticks.IsNull());
     593             :   return ticks;
     594             : }
     595             : 
     596             : 
     597             : // static
     598             : bool TimeTicks::IsHighResolutionClockWorking() {
     599             :   return high_res_tick_clock.Pointer()->IsHighResolution();
     600             : }
     601             : 
     602             : #else  // V8_OS_WIN
     603             : 
     604      186494 : TimeTicks TimeTicks::Now() {
     605      186494 :   return HighResolutionNow();
     606             : }
     607             : 
     608             : 
     609    28111095 : TimeTicks TimeTicks::HighResolutionNow() {
     610             :   int64_t ticks;
     611             : #if V8_OS_MACOSX
     612             :   static struct mach_timebase_info info;
     613             :   if (info.denom == 0) {
     614             :     kern_return_t result = mach_timebase_info(&info);
     615             :     DCHECK_EQ(KERN_SUCCESS, result);
     616             :     USE(result);
     617             :   }
     618             :   ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
     619             :            info.numer / info.denom);
     620             : #elif V8_OS_SOLARIS
     621             :   ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond);
     622             : #elif V8_OS_POSIX
     623             :   ticks = ClockNow(CLOCK_MONOTONIC);
     624             : #else
     625             : #error platform does not implement TimeTicks::HighResolutionNow.
     626             : #endif  // V8_OS_MACOSX
     627             :   // Make sure we never return 0 here.
     628    28112130 :   return TimeTicks(ticks + 1);
     629             : }
     630             : 
     631             : 
     632             : // static
     633           1 : bool TimeTicks::IsHighResolutionClockWorking() {
     634           1 :   return true;
     635             : }
     636             : 
     637             : #endif  // V8_OS_WIN
     638             : 
     639             : 
     640           1 : bool ThreadTicks::IsSupported() {
     641             : #if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
     642             :     defined(V8_OS_MACOSX) || defined(V8_OS_ANDROID) || defined(V8_OS_SOLARIS)
     643           1 :   return true;
     644             : #elif defined(V8_OS_WIN)
     645             :   return IsSupportedWin();
     646             : #else
     647             :   return false;
     648             : #endif
     649             : }
     650             : 
     651             : 
     652         943 : ThreadTicks ThreadTicks::Now() {
     653             : #if V8_OS_MACOSX
     654             :   return ThreadTicks(ComputeThreadTicks());
     655             : #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
     656             :   defined(V8_OS_ANDROID)
     657         943 :   return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
     658             : #elif V8_OS_SOLARIS
     659             :   return ThreadTicks(gethrvtime() / Time::kNanosecondsPerMicrosecond);
     660             : #elif V8_OS_WIN
     661             :   return ThreadTicks::GetForThread(::GetCurrentThread());
     662             : #else
     663             :   UNREACHABLE();
     664             : #endif
     665             : }
     666             : 
     667             : 
     668             : #if V8_OS_WIN
     669             : ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) {
     670             :   DCHECK(IsSupported());
     671             : 
     672             :   // Get the number of TSC ticks used by the current thread.
     673             :   ULONG64 thread_cycle_time = 0;
     674             :   ::QueryThreadCycleTime(thread_handle, &thread_cycle_time);
     675             : 
     676             :   // Get the frequency of the TSC.
     677             :   double tsc_ticks_per_second = TSCTicksPerSecond();
     678             :   if (tsc_ticks_per_second == 0)
     679             :     return ThreadTicks();
     680             : 
     681             :   // Return the CPU time of the current thread.
     682             :   double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
     683             :   return ThreadTicks(
     684             :       static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
     685             : }
     686             : 
     687             : // static
     688             : bool ThreadTicks::IsSupportedWin() {
     689             :   static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() &&
     690             :                              !IsQPCReliable();
     691             :   return is_supported;
     692             : }
     693             : 
     694             : // static
     695             : void ThreadTicks::WaitUntilInitializedWin() {
     696             :   while (TSCTicksPerSecond() == 0)
     697             :     ::Sleep(10);
     698             : }
     699             : 
     700             : double ThreadTicks::TSCTicksPerSecond() {
     701             :   DCHECK(IsSupported());
     702             : 
     703             :   // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
     704             :   // frequency, because there is no guarantee that the TSC frequency is equal to
     705             :   // the performance counter frequency.
     706             : 
     707             :   // The TSC frequency is cached in a static variable because it takes some time
     708             :   // to compute it.
     709             :   static double tsc_ticks_per_second = 0;
     710             :   if (tsc_ticks_per_second != 0)
     711             :     return tsc_ticks_per_second;
     712             : 
     713             :   // Increase the thread priority to reduces the chances of having a context
     714             :   // switch during a reading of the TSC and the performance counter.
     715             :   int previous_priority = ::GetThreadPriority(::GetCurrentThread());
     716             :   ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
     717             : 
     718             :   // The first time that this function is called, make an initial reading of the
     719             :   // TSC and the performance counter.
     720             :   static const uint64_t tsc_initial = __rdtsc();
     721             :   static const uint64_t perf_counter_initial = QPCNowRaw();
     722             : 
     723             :   // Make a another reading of the TSC and the performance counter every time
     724             :   // that this function is called.
     725             :   uint64_t tsc_now = __rdtsc();
     726             :   uint64_t perf_counter_now = QPCNowRaw();
     727             : 
     728             :   // Reset the thread priority.
     729             :   ::SetThreadPriority(::GetCurrentThread(), previous_priority);
     730             : 
     731             :   // Make sure that at least 50 ms elapsed between the 2 readings. The first
     732             :   // time that this function is called, we don't expect this to be the case.
     733             :   // Note: The longer the elapsed time between the 2 readings is, the more
     734             :   //   accurate the computed TSC frequency will be. The 50 ms value was
     735             :   //   chosen because local benchmarks show that it allows us to get a
     736             :   //   stddev of less than 1 tick/us between multiple runs.
     737             :   // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
     738             :   //   this will never fail on systems that run XP or later.
     739             :   //   https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
     740             :   LARGE_INTEGER perf_counter_frequency = {};
     741             :   ::QueryPerformanceFrequency(&perf_counter_frequency);
     742             :   DCHECK_GE(perf_counter_now, perf_counter_initial);
     743             :   uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
     744             :   double elapsed_time_seconds =
     745             :       perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
     746             : 
     747             :   const double kMinimumEvaluationPeriodSeconds = 0.05;
     748             :   if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
     749             :     return 0;
     750             : 
     751             :   // Compute the frequency of the TSC.
     752             :   DCHECK_GE(tsc_now, tsc_initial);
     753             :   uint64_t tsc_ticks = tsc_now - tsc_initial;
     754             :   tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
     755             : 
     756             :   return tsc_ticks_per_second;
     757             : }
     758             : #endif  // V8_OS_WIN
     759             : 
     760             : }  // namespace base
     761             : }  // namespace v8

Generated by: LCOV version 1.10