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

Generated by: LCOV version 1.10