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

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: Address fadi's comment 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 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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