Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: src/base/platform/time.cc

Issue 1977983003: [base] Implement CPU time on Windows. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/base/platform/time.h ('k') | src/base/win32-headers.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/base/platform/time.h ('k') | src/base/win32-headers.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698