summaryrefslogtreecommitdiffstats
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
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
-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
-rw-r--r--chrome/browser/chrome_browser_main_win.cc16
-rw-r--r--content/app/content_main_runner.cc3
-rw-r--r--content/browser/browser_child_process_host_impl.cc3
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc3
-rw-r--r--content/public/common/content_switches.cc5
-rw-r--r--content/public/common/content_switches.h3
11 files changed, 96 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
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index b9ef210..16a6452 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -30,6 +30,7 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_result_codes.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/chrome_version_info.h"
#include "chrome/common/env_vars.h"
#include "chrome/installer/launcher_support/chrome_launcher_support.h"
#include "chrome/installer/util/browser_distribution.h"
@@ -141,11 +142,26 @@ int DoUninstallTasks(bool chrome_still_running) {
return result;
}
+void MaybeEnableHighResolutionTimeEverywhere() {
+ chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
+ bool user_enabled = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableHighResolutionTime);
+ if (user_enabled || channel == chrome::VersionInfo::CHANNEL_CANARY) {
+ bool is_enabled = base::TimeTicks::SetNowIsHighResNowIfSupported();
+ if (is_enabled && !user_enabled) {
+ // Ensure that all of the renderers will enable it too.
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableHighResolutionTime);
+ }
+ }
+}
+
// ChromeBrowserMainPartsWin ---------------------------------------------------
ChromeBrowserMainPartsWin::ChromeBrowserMainPartsWin(
const content::MainFunctionParams& parameters)
: ChromeBrowserMainParts(parameters) {
+ MaybeEnableHighResolutionTimeEverywhere();
if (base::win::IsMetroProcess()) {
typedef const wchar_t* (*GetMetroSwitches)(void);
GetMetroSwitches metro_switches_proc = reinterpret_cast<GetMetroSwitches>(
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 9fc34c2..7bfc37b 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -686,6 +686,9 @@ class ContentMainRunnerImpl : public ContentMainRunner {
MachBroker::ChildSendTaskPortToParent();
}
#elif defined(OS_WIN)
+ if (command_line.HasSwitch(switches::kEnableHighResolutionTime))
+ base::TimeTicks::SetNowIsHighResNowIfSupported();
+
// This must be done early enough since some helper functions like
// IsTouchEnabled, needed to load resources, may call into the theme dll.
EnableThemeSupportOnAllWindowStations();
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index f4598be..5cc9532 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -153,6 +153,9 @@ void BrowserChildProcessHostImpl::Launch(
#if defined(OS_POSIX)
switches::kChildCleanExit,
#endif
+#if defined(OS_WIN)
+ switches::kEnableHighResolutionTime,
+#endif
};
cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
arraysize(kForwardSwitches));
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 0397f3d..07b6213 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -908,6 +908,9 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableGPUClientLogging,
switches::kEnableGpuClientTracing,
switches::kEnableGpuBenchmarking,
+#if defined(OS_WIN)
+ switches::kEnableHighResolutionTime,
+#endif
switches::kEnableMP3StreamParser,
switches::kEnableMemoryBenchmarking,
switches::kEnableOverlayScrollbars,
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 7044813f..6e4682d 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -413,6 +413,11 @@ const char kEnableGpuClientTracing[] = "enable-gpu-client-tracing";
const char kEnableHighDpiCompositingForFixedPosition[] =
"enable-high-dpi-fixed-position-compositing";
+#if defined(OS_WIN)
+// Use high resolution timers for TimeTicks.
+const char kEnableHighResolutionTime[] = "enable-high-resolution-time";
+#endif
+
// Enable HTML Imports
extern const char kEnableHTMLImports[] = "enable-html-imports";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 381abdd..e0a0977 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -126,6 +126,9 @@ CONTENT_EXPORT extern const char kEnableGestureTapHighlight[];
extern const char kEnableGpuBenchmarking[];
extern const char kEnableGpuClientTracing[];
CONTENT_EXPORT extern const char kEnableHighDpiCompositingForFixedPosition[];
+ #if defined(OS_WIN)
+extern const char kEnableHighResolutionTime[];
+#endif
extern const char kEnableHTMLImports[];
CONTENT_EXPORT extern const char kEnableInbandTextTracks[];
extern const char kEnableInputModeAttribute[];