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 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 |