| Index: src/base/platform/time.cc
 | 
| diff --git a/src/base/platform/time.cc b/src/base/platform/time.cc
 | 
| index b2355a33bde275695d13fe49ceb619ddf12911d5..27e8e968ddf9f3be387e2479de61f331d69cc1fd 100644
 | 
| --- a/src/base/platform/time.cc
 | 
| +++ b/src/base/platform/time.cc
 | 
| @@ -51,7 +51,7 @@ int64_t ComputeThreadTicks() {
 | 
|  // microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
 | 
|  // on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
 | 
|  // _POSIX_MONOTONIC_CLOCK to -1.
 | 
| -inline int64_t ClockNow(clockid_t clk_id) {
 | 
| +V8_INLINE int64_t ClockNow(clockid_t clk_id) {
 | 
|  #if (defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
 | 
|    defined(V8_OS_BSD) || defined(V8_OS_ANDROID)
 | 
|    struct timespec ts;
 | 
| @@ -67,6 +67,24 @@ inline int64_t ClockNow(clockid_t clk_id) {
 | 
|    return 0;
 | 
|  #endif
 | 
|  }
 | 
| +#elif V8_OS_WIN
 | 
| +V8_INLINE bool IsQPCReliable() {
 | 
| +  v8::base::CPU cpu;
 | 
| +  // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable.
 | 
| +  return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15;
 | 
| +}
 | 
| +
 | 
| +// Returns the current value of the performance counter.
 | 
| +V8_INLINE uint64_t QPCNowRaw() {
 | 
| +  LARGE_INTEGER perf_counter_now = {};
 | 
| +  // According to the MSDN documentation for QueryPerformanceCounter(), this
 | 
| +  // will never fail on systems that run XP or later.
 | 
| +  // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
 | 
| +  BOOL result = ::QueryPerformanceCounter(&perf_counter_now);
 | 
| +  DCHECK(result);
 | 
| +  USE(result);
 | 
| +  return perf_counter_now.QuadPart;
 | 
| +}
 | 
|  #endif  // V8_OS_MACOSX
 | 
|  
 | 
|  
 | 
| @@ -456,15 +474,12 @@ class HighResolutionTickClock final : public TickClock {
 | 
|    virtual ~HighResolutionTickClock() {}
 | 
|  
 | 
|    int64_t Now() override {
 | 
| -    LARGE_INTEGER now;
 | 
| -    BOOL result = QueryPerformanceCounter(&now);
 | 
| -    DCHECK(result);
 | 
| -    USE(result);
 | 
| +    uint64_t now = QPCNowRaw();
 | 
|  
 | 
|      // Intentionally calculate microseconds in a round about manner to avoid
 | 
|      // overflow and precision issues. Think twice before simplifying!
 | 
| -    int64_t whole_seconds = now.QuadPart / ticks_per_second_;
 | 
| -    int64_t leftover_ticks = now.QuadPart % ticks_per_second_;
 | 
| +    int64_t whole_seconds = now / ticks_per_second_;
 | 
| +    int64_t leftover_ticks = now % ticks_per_second_;
 | 
|      int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) +
 | 
|          ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_);
 | 
|  
 | 
| @@ -529,10 +544,8 @@ struct CreateHighResTickClockTrait {
 | 
|        return tick_clock.Pointer();
 | 
|      }
 | 
|  
 | 
| -    // On Athlon X2 CPUs (e.g. model 15) the QueryPerformanceCounter
 | 
| -    // is unreliable, fallback to the low-resolution tick clock.
 | 
| -    CPU cpu;
 | 
| -    if (strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15) {
 | 
| +    // If QPC not reliable, fallback to low-resolution tick clock.
 | 
| +    if (IsQPCReliable()) {
 | 
|        return tick_clock.Pointer();
 | 
|      }
 | 
|  
 | 
| @@ -621,11 +634,106 @@ ThreadTicks ThreadTicks::Now() {
 | 
|  #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
 | 
|    defined(V8_OS_ANDROID)
 | 
|    return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
 | 
| +#elif V8_OS_WIN
 | 
| +  return ThreadTicks::GetForThread(::GetCurrentThread());
 | 
|  #else
 | 
|    UNREACHABLE();
 | 
|    return ThreadTicks();
 | 
|  #endif
 | 
|  }
 | 
|  
 | 
| +
 | 
| +#if V8_OS_WIN
 | 
| +ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) {
 | 
| +  DCHECK(IsSupported());
 | 
| +
 | 
| +  // Get the number of TSC ticks used by the current thread.
 | 
| +  ULONG64 thread_cycle_time = 0;
 | 
| +  ::QueryThreadCycleTime(thread_handle, &thread_cycle_time);
 | 
| +
 | 
| +  // Get the frequency of the TSC.
 | 
| +  double tsc_ticks_per_second = TSCTicksPerSecond();
 | 
| +  if (tsc_ticks_per_second == 0)
 | 
| +    return ThreadTicks();
 | 
| +
 | 
| +  // Return the CPU time of the current thread.
 | 
| +  double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
 | 
| +  return ThreadTicks(
 | 
| +      static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +bool ThreadTicks::IsSupportedWin() {
 | 
| +  static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() &&
 | 
| +                             !IsQPCReliable();
 | 
| +  return is_supported;
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +void ThreadTicks::WaitUntilInitializedWin() {
 | 
| +  while (TSCTicksPerSecond() == 0)
 | 
| +    ::Sleep(10);
 | 
| +}
 | 
| +
 | 
| +double ThreadTicks::TSCTicksPerSecond() {
 | 
| +  DCHECK(IsSupported());
 | 
| +
 | 
| +  // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
 | 
| +  // frequency, because there is no guarantee that the TSC frequency is equal to
 | 
| +  // the performance counter frequency.
 | 
| +
 | 
| +  // The TSC frequency is cached in a static variable because it takes some time
 | 
| +  // to compute it.
 | 
| +  static double tsc_ticks_per_second = 0;
 | 
| +  if (tsc_ticks_per_second != 0)
 | 
| +    return tsc_ticks_per_second;
 | 
| +
 | 
| +  // Increase the thread priority to reduces the chances of having a context
 | 
| +  // switch during a reading of the TSC and the performance counter.
 | 
| +  int previous_priority = ::GetThreadPriority(::GetCurrentThread());
 | 
| +  ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
 | 
| +
 | 
| +  // The first time that this function is called, make an initial reading of the
 | 
| +  // TSC and the performance counter.
 | 
| +  static const uint64_t tsc_initial = __rdtsc();
 | 
| +  static const uint64_t perf_counter_initial = QPCNowRaw();
 | 
| +
 | 
| +  // Make a another reading of the TSC and the performance counter every time
 | 
| +  // that this function is called.
 | 
| +  uint64_t tsc_now = __rdtsc();
 | 
| +  uint64_t perf_counter_now = QPCNowRaw();
 | 
| +
 | 
| +  // Reset the thread priority.
 | 
| +  ::SetThreadPriority(::GetCurrentThread(), previous_priority);
 | 
| +
 | 
| +  // Make sure that at least 50 ms elapsed between the 2 readings. The first
 | 
| +  // time that this function is called, we don't expect this to be the case.
 | 
| +  // Note: The longer the elapsed time between the 2 readings is, the more
 | 
| +  //   accurate the computed TSC frequency will be. The 50 ms value was
 | 
| +  //   chosen because local benchmarks show that it allows us to get a
 | 
| +  //   stddev of less than 1 tick/us between multiple runs.
 | 
| +  // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
 | 
| +  //   this will never fail on systems that run XP or later.
 | 
| +  //   https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
 | 
| +  LARGE_INTEGER perf_counter_frequency = {};
 | 
| +  ::QueryPerformanceFrequency(&perf_counter_frequency);
 | 
| +  DCHECK_GE(perf_counter_now, perf_counter_initial);
 | 
| +  uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
 | 
| +  double elapsed_time_seconds =
 | 
| +      perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
 | 
| +
 | 
| +  const double kMinimumEvaluationPeriodSeconds = 0.05;
 | 
| +  if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
 | 
| +    return 0;
 | 
| +
 | 
| +  // Compute the frequency of the TSC.
 | 
| +  DCHECK_GE(tsc_now, tsc_initial);
 | 
| +  uint64_t tsc_ticks = tsc_now - tsc_initial;
 | 
| +  tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
 | 
| +
 | 
| +  return tsc_ticks_per_second;
 | 
| +}
 | 
| +#endif  // V8_OS_WIN
 | 
| +
 | 
|  }  // namespace base
 | 
|  }  // namespace v8
 | 
| 
 |