summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorsimonjam@chromium.org <simonjam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-10 23:36:08 +0000
committersimonjam@chromium.org <simonjam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-10 23:36:08 +0000
commitc8e8cb94373c68f39a82e920c469c25f65b9cf5b (patch)
treec5daf2c91ebf056ff98cb506e47df6c4b1a656a1 /base
parent61fa77f89e6835141b114528821b214496c2501e (diff)
downloadchromium_src-c8e8cb94373c68f39a82e920c469c25f65b9cf5b.zip
chromium_src-c8e8cb94373c68f39a82e920c469c25f65b9cf5b.tar.gz
chromium_src-c8e8cb94373c68f39a82e920c469c25f65b9cf5b.tar.bz2
Enable high resolution time for TimeTicks::Now on Windows Canary
This should be unnoticeable, except for improved resolution in places such as window.performance.now(). The feature is enabled if the user is running Canary channel or has manually specified the --enable-high-resolution-time flag. This will only work if the CPU has a non-stop TSC and isn't a broken Athlon processor. UMA data show this is a safe combination. The flag is propagated to renderer processes so that they know to enable it too. BUG=158234 Review URL: https://chromiumcodereview.appspot.com/23147002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@222396 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/profiler/tracked_time.cc3
-rw-r--r--base/test/test_suite.cc1
-rw-r--r--base/threading/platform_thread_win.cc7
-rw-r--r--base/time/time.h11
-rw-r--r--base/time/time_win.cc48
5 files changed, 63 insertions, 7 deletions
diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc
index 27d3358..7791c3a 100644
--- a/base/profiler/tracked_time.cc
+++ b/base/profiler/tracked_time.cc
@@ -55,8 +55,7 @@ TrackedTime TrackedTime::Now() {
// Use lock-free accessor to 32 bit time.
// Note that TimeTicks::Now() is built on this, so we have "compatible"
// times when we down-convert a TimeTicks sample.
- // TODO(jar): Surface this interface via something in base/time/time.h.
- return TrackedTime(static_cast<int32>(timeGetTime()));
+ return TrackedTime(base::TimeTicks::UnprotectedNow());
#else
// Posix has nice cheap 64 bit times, so we just down-convert it.
return TrackedTime(base::TimeTicks::Now());
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index ef3ee99..9d7c158 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -99,6 +99,7 @@ void TestSuite::PreInitialize(int argc, char** argv,
bool create_at_exit_manager) {
#if defined(OS_WIN)
testing::GTEST_FLAG(catch_exceptions) = false;
+ base::TimeTicks::SetNowIsHighResNowIfSupported();
#endif
base::EnableTerminationOnHeapCorruption();
initialized_command_line_ = CommandLine::Init(argc, argv);
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index cf1e0f6..e9752ba 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -135,7 +135,12 @@ void PlatformThread::YieldCurrentThread() {
// static
void PlatformThread::Sleep(TimeDelta duration) {
- ::Sleep(duration.InMillisecondsRoundedUp());
+ // When measured with a high resolution clock, Sleep() sometimes returns much
+ // too early. We may need to call it repeatedly to get the desired duration.
+ TimeTicks end = TimeTicks::Now() + duration;
+ TimeTicks now;
+ while ((now = TimeTicks::Now()) < end)
+ ::Sleep((end - now).InMillisecondsRoundedUp());
}
// static
diff --git a/base/time/time.h b/base/time/time.h
index eba6145..5d7033a 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -572,6 +572,17 @@ class BASE_EXPORT TimeTicks {
// Returns true if the high resolution clock is working on this system.
// This is only for testing.
static bool IsHighResClockWorking();
+
+ // Enable high resolution time for TimeTicks::Now(). This function will
+ // test for the availability of a working implementation of
+ // QueryPerformanceCounter(). If one is not available, this function does
+ // nothing and the resolution of Now() remains 1ms. Otherwise, all future
+ // calls to TimeTicks::Now() will have the higher resolution provided by QPC.
+ // Returns true if high resolution time was successfully enabled.
+ static bool SetNowIsHighResNowIfSupported();
+
+ // Returns a time value that is NOT rollover protected.
+ static TimeTicks UnprotectedNow();
#endif
// Returns true if this object has not been initialized.
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index 3680ee2a..f35f735 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -322,6 +322,12 @@ TimeDelta RolloverProtectedNow() {
return TimeDelta::FromMilliseconds(now + rollover_ms);
}
+bool IsBuggyAthlon(const base::CPU& cpu) {
+ // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
+ // unreliable. Fallback to low-res clock.
+ return cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15;
+}
+
// Overview of time counters:
// (1) CPU cycle counter. (Retrieved via RDTSC)
// The CPU counter provides the highest resolution time stamp and is the least
@@ -398,10 +404,8 @@ class HighResNowSingleton {
skew_(0) {
InitializeClock();
- // On Athlon X2 CPUs (e.g. model 15) QueryPerformanceCounter is
- // unreliable. Fallback to low-res clock.
base::CPU cpu;
- if (cpu.vendor_name() == "AuthenticAMD" && cpu.family() == 15)
+ if (IsBuggyAthlon(cpu))
DisableHighResClock();
}
@@ -433,6 +437,24 @@ class HighResNowSingleton {
friend struct DefaultSingletonTraits<HighResNowSingleton>;
};
+TimeDelta HighResNowWrapper() {
+ return HighResNowSingleton::GetInstance()->Now();
+}
+
+typedef TimeDelta (*NowFunction)(void);
+NowFunction now_function = RolloverProtectedNow;
+
+bool CPUReliablySupportsHighResTime() {
+ base::CPU cpu;
+ if (!cpu.has_non_stop_time_stamp_counter())
+ return false;
+
+ if (IsBuggyAthlon(cpu))
+ return false;
+
+ return true;
+}
+
} // namespace
// static
@@ -447,8 +469,18 @@ TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
}
// static
+bool TimeTicks::SetNowIsHighResNowIfSupported() {
+ if (!CPUReliablySupportsHighResTime()) {
+ return false;
+ }
+
+ now_function = HighResNowWrapper;
+ return true;
+}
+
+// static
TimeTicks TimeTicks::Now() {
- return TimeTicks() + RolloverProtectedNow();
+ return TimeTicks() + now_function();
}
// static
@@ -483,6 +515,14 @@ bool TimeTicks::IsHighResClockWorking() {
return HighResNowSingleton::GetInstance()->IsUsingHighResClock();
}
+TimeTicks TimeTicks::UnprotectedNow() {
+ if (now_function == HighResNowWrapper) {
+ return Now();
+ } else {
+ return TimeTicks() + TimeDelta::FromMilliseconds(timeGetTime());
+ }
+}
+
// TimeDelta ------------------------------------------------------------------
// static