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 inline bool IsBuggyAthlon(const v8::base::CPU& cpu) { | |
fmeawad
2016/05/24 22:56:59
nit:Rename to IsQPCReliable
lpy
2016/05/24 23:29:16
Done.
| |
72 // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is unreliable. | |
73 return strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15; | |
74 } | |
75 | |
76 // Returns the current value of the performance counter. | |
77 inline uint64_t QPCNowRaw() { | |
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 BOOL result = ::QueryPerformanceCounter(&perf_counter_now); | |
83 DCHECK(result); | |
84 USE(result); | |
85 return perf_counter_now.QuadPart; | |
86 } | |
70 #endif // V8_OS_MACOSX | 87 #endif // V8_OS_MACOSX |
71 | 88 |
72 | 89 |
73 } // namespace | 90 } // namespace |
74 | 91 |
75 namespace v8 { | 92 namespace v8 { |
76 namespace base { | 93 namespace base { |
77 | 94 |
78 TimeDelta TimeDelta::FromDays(int days) { | 95 TimeDelta TimeDelta::FromDays(int days) { |
79 return TimeDelta(days * Time::kMicrosecondsPerDay); | 96 return TimeDelta(days * Time::kMicrosecondsPerDay); |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
449 // retrieve and more reliable. | 466 // retrieve and more reliable. |
450 class HighResolutionTickClock final : public TickClock { | 467 class HighResolutionTickClock final : public TickClock { |
451 public: | 468 public: |
452 explicit HighResolutionTickClock(int64_t ticks_per_second) | 469 explicit HighResolutionTickClock(int64_t ticks_per_second) |
453 : ticks_per_second_(ticks_per_second) { | 470 : ticks_per_second_(ticks_per_second) { |
454 DCHECK_LT(0, ticks_per_second); | 471 DCHECK_LT(0, ticks_per_second); |
455 } | 472 } |
456 virtual ~HighResolutionTickClock() {} | 473 virtual ~HighResolutionTickClock() {} |
457 | 474 |
458 int64_t Now() override { | 475 int64_t Now() override { |
459 LARGE_INTEGER now; | 476 uint64_t now = QPCNowRaw(); |
460 BOOL result = QueryPerformanceCounter(&now); | |
461 DCHECK(result); | |
462 USE(result); | |
463 | 477 |
464 // Intentionally calculate microseconds in a round about manner to avoid | 478 // Intentionally calculate microseconds in a round about manner to avoid |
465 // overflow and precision issues. Think twice before simplifying! | 479 // overflow and precision issues. Think twice before simplifying! |
466 int64_t whole_seconds = now.QuadPart / ticks_per_second_; | 480 int64_t whole_seconds = now / ticks_per_second_; |
467 int64_t leftover_ticks = now.QuadPart % ticks_per_second_; | 481 int64_t leftover_ticks = now % ticks_per_second_; |
468 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + | 482 int64_t ticks = (whole_seconds * Time::kMicrosecondsPerSecond) + |
469 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); | 483 ((leftover_ticks * Time::kMicrosecondsPerSecond) / ticks_per_second_); |
470 | 484 |
471 // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow() | 485 // Make sure we never return 0 here, so that TimeTicks::HighResolutionNow() |
472 // will never return 0. | 486 // will never return 0. |
473 return ticks + 1; | 487 return ticks + 1; |
474 } | 488 } |
475 | 489 |
476 bool IsHighResolution() override { return true; } | 490 bool IsHighResolution() override { return true; } |
477 | 491 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
522 | 536 |
523 struct CreateHighResTickClockTrait { | 537 struct CreateHighResTickClockTrait { |
524 static TickClock* Create() { | 538 static TickClock* Create() { |
525 // Check if the installed hardware supports a high-resolution performance | 539 // Check if the installed hardware supports a high-resolution performance |
526 // counter, and if not fallback to the low-resolution tick clock. | 540 // counter, and if not fallback to the low-resolution tick clock. |
527 LARGE_INTEGER ticks_per_second; | 541 LARGE_INTEGER ticks_per_second; |
528 if (!QueryPerformanceFrequency(&ticks_per_second)) { | 542 if (!QueryPerformanceFrequency(&ticks_per_second)) { |
529 return tick_clock.Pointer(); | 543 return tick_clock.Pointer(); |
530 } | 544 } |
531 | 545 |
532 // On Athlon X2 CPUs (e.g. model 15) the QueryPerformanceCounter | 546 // Fallback to the low-resolution tick clock when on buggy Cpu |
533 // is unreliable, fallback to the low-resolution tick clock. | 547 // where QueryPerformanceCounter is unreliable. |
fmeawad
2016/05/24 22:56:59
Change comment to: If QPC not reliable, fallback t
lpy
2016/05/24 23:29:16
Done.
| |
534 CPU cpu; | 548 CPU cpu; |
fmeawad
2016/05/24 22:56:59
CPU cpu should move inside IsBuggyAthlon since it
lpy
2016/05/24 23:29:16
Done.
| |
535 if (strcmp(cpu.vendor(), "AuthenticAMD") == 0 && cpu.family() == 15) { | 549 if (IsBuggyAthlon(cpu)) { |
536 return tick_clock.Pointer(); | 550 return tick_clock.Pointer(); |
537 } | 551 } |
538 | 552 |
539 return new HighResolutionTickClock(ticks_per_second.QuadPart); | 553 return new HighResolutionTickClock(ticks_per_second.QuadPart); |
540 } | 554 } |
541 }; | 555 }; |
542 | 556 |
543 | 557 |
544 static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait, | 558 static LazyDynamicInstance<TickClock, CreateHighResTickClockTrait, |
545 ThreadSafeInitOnceTrait>::type high_res_tick_clock = | 559 ThreadSafeInitOnceTrait>::type high_res_tick_clock = |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
614 #endif | 628 #endif |
615 } | 629 } |
616 | 630 |
617 | 631 |
618 ThreadTicks ThreadTicks::Now() { | 632 ThreadTicks ThreadTicks::Now() { |
619 #if V8_OS_MACOSX | 633 #if V8_OS_MACOSX |
620 return ThreadTicks(ComputeThreadTicks()); | 634 return ThreadTicks(ComputeThreadTicks()); |
621 #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ | 635 #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ |
622 defined(V8_OS_ANDROID) | 636 defined(V8_OS_ANDROID) |
623 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); | 637 return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID)); |
638 #elif V8_OS_WIN | |
639 return ThreadTicks::GetForThread(::GetCurrentThread()); | |
624 #else | 640 #else |
625 UNREACHABLE(); | 641 UNREACHABLE(); |
626 return ThreadTicks(); | 642 return ThreadTicks(); |
627 #endif | 643 #endif |
628 } | 644 } |
629 | 645 |
646 | |
647 #if V8_OS_WIN | |
648 ThreadTicks ThreadTicks::GetForThread(const HANDLE& thread_handle) { | |
649 DCHECK(IsSupported()); | |
650 | |
651 // Get the number of TSC ticks used by the current thread. | |
652 ULONG64 thread_cycle_time = 0; | |
653 ::QueryThreadCycleTime(thread_handle, &thread_cycle_time); | |
654 | |
655 // Get the frequency of the TSC. | |
656 double tsc_ticks_per_second = TSCTicksPerSecond(); | |
657 if (tsc_ticks_per_second == 0) | |
658 return ThreadTicks(); | |
659 | |
660 // Return the CPU time of the current thread. | |
661 double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second; | |
662 return ThreadTicks( | |
663 static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond)); | |
664 } | |
665 | |
666 // static | |
667 bool ThreadTicks::IsSupportedWin() { | |
668 static bool is_supported = base::CPU().has_non_stop_time_stamp_counter() && | |
669 !IsBuggyAthlon(base::CPU()); | |
670 return is_supported; | |
671 } | |
672 | |
673 // static | |
674 void ThreadTicks::WaitUntilInitializedWin() { | |
675 while (TSCTicksPerSecond() == 0) | |
676 ::Sleep(10); | |
677 } | |
678 | |
679 double ThreadTicks::TSCTicksPerSecond() { | |
680 DCHECK(IsSupported()); | |
681 | |
682 // The value returned by QueryPerformanceFrequency() cannot be used as the TSC | |
683 // frequency, because there is no guarantee that the TSC frequency is equal to | |
684 // the performance counter frequency. | |
685 | |
686 // The TSC frequency is cached in a static variable because it takes some time | |
687 // to compute it. | |
688 static double tsc_ticks_per_second = 0; | |
689 if (tsc_ticks_per_second != 0) | |
690 return tsc_ticks_per_second; | |
691 | |
692 // Increase the thread priority to reduces the chances of having a context | |
693 // switch during a reading of the TSC and the performance counter. | |
694 int previous_priority = ::GetThreadPriority(::GetCurrentThread()); | |
695 ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST); | |
696 | |
697 // The first time that this function is called, make an initial reading of the | |
698 // TSC and the performance counter. | |
699 static const uint64_t tsc_initial = __rdtsc(); | |
700 static const uint64_t perf_counter_initial = QPCNowRaw(); | |
701 | |
702 // Make a another reading of the TSC and the performance counter every time | |
703 // that this function is called. | |
704 uint64_t tsc_now = __rdtsc(); | |
705 uint64_t perf_counter_now = QPCNowRaw(); | |
706 | |
707 // Reset the thread priority. | |
708 ::SetThreadPriority(::GetCurrentThread(), previous_priority); | |
709 | |
710 // Make sure that at least 50 ms elapsed between the 2 readings. The first | |
711 // time that this function is called, we don't expect this to be the case. | |
712 // Note: The longer the elapsed time between the 2 readings is, the more | |
713 // accurate the computed TSC frequency will be. The 50 ms value was | |
714 // chosen because local benchmarks show that it allows us to get a | |
715 // stddev of less than 1 tick/us between multiple runs. | |
716 // Note: According to the MSDN documentation for QueryPerformanceFrequency(), | |
717 // this will never fail on systems that run XP or later. | |
718 // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx | |
719 LARGE_INTEGER perf_counter_frequency = {}; | |
720 ::QueryPerformanceFrequency(&perf_counter_frequency); | |
721 DCHECK_GE(perf_counter_now, perf_counter_initial); | |
722 uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial; | |
723 double elapsed_time_seconds = | |
724 perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart); | |
725 | |
726 const double kMinimumEvaluationPeriodSeconds = 0.05; | |
727 if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds) | |
728 return 0; | |
729 | |
730 // Compute the frequency of the TSC. | |
731 DCHECK_GE(tsc_now, tsc_initial); | |
732 uint64_t tsc_ticks = tsc_now - tsc_initial; | |
733 tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds; | |
734 | |
735 return tsc_ticks_per_second; | |
736 } | |
737 #endif // V8_OS_WIN | |
738 | |
630 } // namespace base | 739 } // namespace base |
631 } // namespace v8 | 740 } // namespace v8 |
OLD | NEW |