Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/base/platform/time.h" | 5 #include "src/base/platform/time.h" |
| 6 | 6 |
| 7 #if V8_OS_POSIX | 7 #if V8_OS_POSIX |
| 8 #include <fcntl.h> // for O_RDONLY | 8 #include <fcntl.h> // for O_RDONLY |
| 9 #include <sys/time.h> | 9 #include <sys/time.h> |
| 10 #include <unistd.h> | 10 #include <unistd.h> |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 60 return 0; | 60 return 0; |
| 61 } | 61 } |
| 62 v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec); | 62 v8::base::internal::CheckedNumeric<int64_t> result(ts.tv_sec); |
| 63 result *= v8::base::Time::kMicrosecondsPerSecond; | 63 result *= v8::base::Time::kMicrosecondsPerSecond; |
| 64 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond); | 64 result += (ts.tv_nsec / v8::base::Time::kNanosecondsPerMicrosecond); |
| 65 return result.ValueOrDie(); | 65 return result.ValueOrDie(); |
| 66 #else // Monotonic clock not supported. | 66 #else // Monotonic clock not supported. |
| 67 return 0; | 67 return 0; |
| 68 #endif | 68 #endif |
| 69 } | 69 } |
| 70 #elif V8_OS_WIN | |
| 71 bool IsBuggyAthlon(const v8::base::CPU& cpu) { | |
| 72 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | |
| 73 return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15; | |
|
noordhuis
2016/05/15 09:06:46
I commented on this in the other CL but I think it
lpy
2016/05/24 22:21:46
I will leave this as it is for now, since we are u
| |
| 74 } | |
| 75 | |
| 76 // Returns the current value of the performance counter. | |
| 77 uint64_t QPCNowRaw() { | |
|
fmeawad
2016/05/14 01:04:07
If I am reading the correctly, we do not use QPC f
lpy
2016/05/24 22:21:46
It depends. V8 may fall back to low resolution tim
| |
| 78 LARGE_INTEGER perf_counter_now = {}; | |
| 79 // According to the MSDN documentation for QueryPerformanceCounter(), this | |
| 80 // will never fail on systems that run XP or later. | |
| 81 // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx | |
| 82 ::QueryPerformanceCounter(&perf_counter_now); | |
| 83 return perf_counter_now.QuadPart; | |
| 84 } | |
| 70 #endif // V8_OS_MACOSX | 85 #endif // V8_OS_MACOSX |
| 71 | 86 |
| 72 | 87 |
| 73 } // namespace | 88 } // namespace |
| 74 | 89 |
| 75 namespace v8 { | 90 namespace v8 { |
| 76 namespace base { | 91 namespace base { |
| 77 | 92 |
| 78 TimeDelta TimeDelta::FromDays(int days) { | 93 TimeDelta TimeDelta::FromDays(int days) { |
| 79 return TimeDelta(days * Time::kMicrosecondsPerDay); | 94 return TimeDelta(days * Time::kMicrosecondsPerDay); |
| (...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 #endif | 629 #endif |
| 615 } | 630 } |
| 616 | 631 |
| 617 | 632 |
| 618 ThreadTicks ThreadTicks::Now() { | 633 ThreadTicks ThreadTicks::Now() { |
| 619 #if V8_OS_MACOSX | 634 #if V8_OS_MACOSX |
| 620 return ThreadTicks(ComputeThreadTicks()); | 635 return ThreadTicks(ComputeThreadTicks()); |
| 621 #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ | 636 #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ |
| 622 defined(V8_OS_ANDROID) | 637 defined(V8_OS_ANDROID) |
| 623 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); | 638 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); |
| 639 #elif V8_OS_WIN | |
| 640 return ThreadTicks::GetForThread(::GetCurrentThread()); | |
| 624 #else | 641 #else |
| 625 UNREACHABLE(); | 642 UNREACHABLE(); |
| 626 return ThreadTicks(); | 643 return ThreadTicks(); |
| 627 #endif | 644 #endif |
| 628 } | 645 } |
| 629 | 646 |
| 647 | |
| 648 #if V8_OS_WIN | |
| 649 ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) { | |
| 650 DCHECK(IsSupported()); | |
| 651 | |
| 652 // Get the number of TSC ticks used by the current thread. | |
| 653 ULONG64 thread_cycle_time = 0; | |
| 654 ::QueryThreadCycleTime(thread_handle, &thread_cycle_time); | |
| 655 | |
| 656 // Get the frequency of the TSC. | |
| 657 double tsc_ticks_per_second = TSCTicksPerSecond(); | |
| 658 if (tsc_ticks_per_second == 0) | |
| 659 return ThreadTicks(); | |
| 660 | |
| 661 // Return the CPU time of the current thread. | |
| 662 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; | |
| 663 return ThreadTicks( | |
| 664 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond)); | |
| 665 } | |
| 666 | |
| 667 // static | |
| 668 bool ThreadTicks::IsSupportedWin() { | |
| 669 static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() && | |
| 670 !IsBuggyAthlon(base::CPU()); | |
| 671 return is_supported; | |
| 672 } | |
| 673 | |
| 674 // static | |
| 675 void ThreadTicks::WaitUntilInitializedWin() { | |
| 676 while (TSCTicksPerSecond() == 0) | |
| 677 ::Sleep(10); | |
| 678 } | |
| 679 | |
| 680 double ThreadTicks::TSCTicksPerSecond() { | |
| 681 DCHECK(IsSupported()); | |
| 682 | |
| 683 // The value returned by QueryPerformanceFrequency() cannot be used as the TSC | |
| 684 // frequency, because there is no guarantee that the TSC frequency is equal to | |
| 685 // the performance counter frequency. | |
| 686 | |
| 687 // The TSC frequency is cached in a static variable because it takes some time | |
| 688 // to compute it. | |
| 689 static double tsc_ticks_per_second = 0; | |
| 690 if (tsc_ticks_per_second != 0) | |
| 691 return tsc_ticks_per_second; | |
| 692 | |
| 693 // Increase the thread priority to reduces the chances of having a context | |
| 694 // switch during a reading of the TSC and the performance counter. | |
| 695 int previous_priority = ::GetThreadPriority(::GetCurrentThread()); | |
| 696 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); | |
| 697 | |
| 698 // The first time that this function is called, make an initial reading of the | |
| 699 // TSC and the performance counter. | |
| 700 static const uint64_t tsc_initial = __rdtsc(); | |
| 701 static const uint64_t perf_counter_initial = QPCNowRaw(); | |
| 702 | |
| 703 // Make a another reading of the TSC and the performance counter every time | |
| 704 // that this function is called. | |
| 705 uint64_t tsc_now = __rdtsc(); | |
| 706 uint64_t perf_counter_now = QPCNowRaw(); | |
| 707 | |
| 708 // Reset the thread priority. | |
| 709 ::SetThreadPriority(::GetCurrentThread(), previous_priority); | |
| 710 | |
| 711 // Make sure that at least 50 ms elapsed between the 2 readings. The first | |
| 712 // time that this function is called, we don't expect this to be the case. | |
| 713 // Note: The longer the elapsed time between the 2 readings is, the more | |
| 714 // accurate the computed TSC frequency will be. The 50 ms value was | |
| 715 // chosen because local benchmarks show that it allows us to get a | |
| 716 // stddev of less than 1 tick/us between multiple runs. | |
| 717 // Note: According to the MSDN documentation for QueryPerformanceFrequency(), | |
| 718 // this will never fail on systems that run XP or later. | |
| 719 // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx | |
| 720 LARGE_INTEGER perf_counter_frequency = {}; | |
| 721 ::QueryPerformanceFrequency(&perf_counter_frequency); | |
| 722 DCHECK_GE(perf_counter_now, perf_counter_initial); | |
| 723 uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial; | |
| 724 double elapsed_time_seconds = | |
| 725 perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart); | |
| 726 | |
| 727 const double kMinimumEvaluationPeriodSeconds = 0.05; | |
| 728 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds) | |
| 729 return 0; | |
| 730 | |
| 731 // Compute the frequency of the TSC. | |
| 732 DCHECK_GE(tsc_now, tsc_initial); | |
| 733 uint64_t tsc_ticks = tsc_now - tsc_initial; | |
| 734 tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds; | |
| 735 | |
| 736 return tsc_ticks_per_second; | |
| 737 } | |
| 738 #endif // V8_OS_WIN | |
| 739 | |
| 630 } // namespace base | 740 } // namespace base |
| 631 } // namespace v8 | 741 } // namespace v8 |
| OLD | NEW |