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