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 |