summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvmiura@chromium.org <vmiura@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-29 08:01:43 +0000
committervmiura@chromium.org <vmiura@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-29 08:01:43 +0000
commit47752987c8a9be45d303e29abd463bee159df34f (patch)
tree4d5ced0c95008391b5f8ebcb80026d3060eb31da
parente93b006bd6523f0f36caf0d3e4fbfdf9d415a3db (diff)
downloadchromium_src-47752987c8a9be45d303e29abd463bee159df34f.zip
chromium_src-47752987c8a9be45d303e29abd463bee159df34f.tar.gz
chromium_src-47752987c8a9be45d303e29abd463bee159df34f.tar.bz2
Prevent duplicate navigation to debug URLs from Telemetry.
Previously Telemetry enabled navigation to Debug URLs by adding a custom URL handler. However, URL handlers can be called multiple times per Navigation, and Debug URL actions must happen only once. This CL enables Telemetry URL handling to be done by the normal NavigationControllerImpl::LoadURLWithParams() to HandleDebugURL() path. This also removes the prior workaround added in crrev.com/277113002 . BUG=395326 Review URL: https://codereview.chromium.org/418733002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@286117 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/browser_url_handler_impl.cc13
-rw-r--r--content/browser/frame_host/debug_urls.cc28
-rw-r--r--content/browser/frame_host/debug_urls.h5
-rw-r--r--content/browser/frame_host/navigation_controller_impl.cc23
-rw-r--r--content/browser/gpu/gpu_data_manager_impl_private.cc1
-rw-r--r--content/browser/gpu/gpu_internals_ui.cc4
-rw-r--r--content/browser/gpu/gpu_process_host.cc134
-rw-r--r--content/browser/gpu/gpu_process_host.h12
-rw-r--r--content/common/gpu/gpu_messages.h1
-rw-r--r--content/test/data/gpu/gpu_process_crash.html52
-rw-r--r--content/test/gpu/gpu_tests/context_lost.py90
-rw-r--r--gpu/config/gpu_info.cc5
-rw-r--r--gpu/config/gpu_info.h3
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/system_info_backend.py2
-rw-r--r--tools/telemetry/telemetry/core/browser_unittest.py11
15 files changed, 264 insertions, 120 deletions
diff --git a/content/browser/browser_url_handler_impl.cc b/content/browser/browser_url_handler_impl.cc
index 1b7050f..71e3599 100644
--- a/content/browser/browser_url_handler_impl.cc
+++ b/content/browser/browser_url_handler_impl.cc
@@ -4,9 +4,7 @@
#include "content/browser/browser_url_handler_impl.h"
-#include "base/command_line.h"
#include "base/strings/string_util.h"
-#include "cc/base/switches.h"
#include "content/browser/frame_host/debug_urls.h"
#include "content/browser/webui/web_ui_impl.h"
#include "content/public/browser/content_browser_client.h"
@@ -74,17 +72,6 @@ static bool ReverseViewSource(GURL* url, BrowserContext* browser_context) {
}
static bool DebugURLHandler(GURL* url, BrowserContext* browser_context) {
- // If running inside the Telemetry test harness, allow automated
- // navigations to access browser-side debug URLs. They must use the
- // chrome:// scheme, since the about: scheme won't be rewritten in
- // this code path.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- cc::switches::kEnableGpuBenchmarking)) {
- if (HandleDebugURL(*url, PAGE_TRANSITION_FROM_ADDRESS_BAR)) {
- return true;
- }
- }
-
// Circumvent processing URLs that the renderer process will handle.
return IsRendererDebugURL(*url);
}
diff --git a/content/browser/frame_host/debug_urls.cc b/content/browser/frame_host/debug_urls.cc
index ae454ae..b384098 100644
--- a/content/browser/frame_host/debug_urls.cc
+++ b/content/browser/frame_host/debug_urls.cc
@@ -6,9 +6,11 @@
#include <vector>
+#include "base/command_line.h"
#include "base/debug/asan_invalid_access.h"
#include "base/debug/profiler.h"
#include "base/strings/utf_string_conversions.h"
+#include "cc/base/switches.h"
#include "content/browser/gpu/gpu_process_host_ui_shim.h"
#include "content/browser/ppapi_plugin_process_host.h"
#include "content/public/browser/browser_thread.h"
@@ -106,13 +108,16 @@ bool HandleAsanDebugURL(const GURL& url) {
} // namespace
bool HandleDebugURL(const GURL& url, PageTransition transition) {
- // Ensure that the user explicitly navigated to this URL.
- if (!(transition & PAGE_TRANSITION_FROM_ADDRESS_BAR))
+ // Ensure that the user explicitly navigated to this URL, unless
+ // kEnableGpuBenchmarking is enabled by Telemetry.
+ bool is_telemetry_navigation = CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kEnableGpuBenchmarking) &&
+ (transition & PAGE_TRANSITION_TYPED);
+
+ if (!(transition & PAGE_TRANSITION_FROM_ADDRESS_BAR) &&
+ !is_telemetry_navigation)
return false;
- // NOTE: when you add handling of any URLs to this function, also
- // update IsDebugURL, below.
-
if (IsAsanDebugURL(url))
return HandleAsanDebugURL(url);
@@ -153,19 +158,6 @@ bool HandleDebugURL(const GURL& url, PageTransition transition) {
return false;
}
-bool IsDebugURL(const GURL& url) {
- // NOTE: when you add any URLs to this list, also update
- // HandleDebugURL, above.
- return IsRendererDebugURL(url) || IsAsanDebugURL(url) ||
- (url.is_valid() &&
- (url.host() == kChromeUIBrowserCrashHost ||
- url == GURL(kChromeUIGpuCleanURL) ||
- url == GURL(kChromeUIGpuCrashURL) ||
- url == GURL(kChromeUIGpuHangURL) ||
- url == GURL(kChromeUIPpapiFlashCrashURL) ||
- url == GURL(kChromeUIPpapiFlashHangURL)));
-}
-
bool IsRendererDebugURL(const GURL& url) {
if (!url.is_valid())
return false;
diff --git a/content/browser/frame_host/debug_urls.h b/content/browser/frame_host/debug_urls.h
index 2c87194..01530b4 100644
--- a/content/browser/frame_host/debug_urls.h
+++ b/content/browser/frame_host/debug_urls.h
@@ -15,11 +15,6 @@ namespace content {
// handles it and returns true.
bool HandleDebugURL(const GURL& url, PageTransition transition);
-// Returns whether this given url is a debugging url. It is a superset
-// of IsRendererDebugURL, below, and debugging urls that are handled
-// in the browser process.
-bool IsDebugURL(const GURL& url);
-
// Returns whether the given url is either a debugging url handled in the
// renderer process, such as one that crashes or hangs the renderer, or a
// javascript: URL that operates on the current page in the renderer. Such URLs
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index a25aeba..a602741 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -652,8 +652,13 @@ void NavigationControllerImpl::LoadURL(
void NavigationControllerImpl::LoadURLWithParams(const LoadURLParams& params) {
TRACE_EVENT0("browser", "NavigationControllerImpl::LoadURLWithParams");
- if (HandleDebugURL(params.url, params.transition_type))
- return;
+ if (HandleDebugURL(params.url, params.transition_type)) {
+ // If Telemetry is running, allow the URL load to proceed as if it's
+ // unhandled, otherwise Telemetry can't tell if Navigation completed.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kEnableGpuBenchmarking))
+ return;
+ }
// Any renderer-side debug URLs or javascript: URLs should be ignored if the
// renderer process is not live, unless it is the initial navigation of the
@@ -1035,18 +1040,8 @@ void NavigationControllerImpl::RendererDidNavigateToNewPage(
// update the virtual URL when replaceState is called after a pushState.
GURL url = params.url;
bool needs_update = false;
- // We call RewriteURLIfNecessary twice: once when page navigation
- // begins in CreateNavigationEntry, and once here when it commits.
- // With the kEnableGpuBenchmarking flag, the rewriting includes
- // handling debug URLs which cause an action to occur, and thus we
- // should not rewrite them a second time.
- bool skip_rewrite =
- IsDebugURL(url) && base::CommandLine::ForCurrentProcess()->HasSwitch(
- cc::switches::kEnableGpuBenchmarking);
- if (!skip_rewrite) {
- BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
- &url, browser_context_, &needs_update);
- }
+ BrowserURLHandlerImpl::GetInstance()->RewriteURLIfNecessary(
+ &url, browser_context_, &needs_update);
new_entry->set_update_virtual_url_with_url(needs_update);
// When navigating to a new page, give the browser URL handler a chance to
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 95e0c47..68cda80 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -757,6 +757,7 @@ void GpuDataManagerImplPrivate::ProcessCrashed(
return;
}
{
+ gpu_info_.process_crash_count = GpuProcessHost::gpu_crash_count();
GpuDataManagerImpl::UnlockedSession session(owner_);
observer_list_->Notify(
&GpuDataManagerObserver::OnGpuProcessCrashed, exit_code);
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index 9979116..88e4b05 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -166,6 +166,10 @@ base::DictionaryValue* GpuInfoAsDictionaryValue() {
basic_info->Append(NewDescriptionValuePair(
"Reset notification strategy", reset_strategy));
+ basic_info->Append(NewDescriptionValuePair(
+ "GPU process crash count",
+ new base::FundamentalValue(gpu_info.process_crash_count)));
+
base::DictionaryValue* info = new base::DictionaryValue();
info->Set("basic_info", basic_info);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index f123add..27496f5 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -68,6 +68,10 @@ namespace content {
bool GpuProcessHost::gpu_enabled_ = true;
bool GpuProcessHost::hardware_gpu_enabled_ = true;
+int GpuProcessHost::gpu_crash_count_ = 0;
+int GpuProcessHost::gpu_recent_crash_count_ = 0;
+bool GpuProcessHost::crashed_before_ = false;
+int GpuProcessHost::swiftshader_crash_count_ = 0;
namespace {
@@ -331,6 +335,7 @@ GpuProcessHost::GpuProcessHost(int host_id, GpuProcessKind kind)
kind_(kind),
process_launched_(false),
initialized_(false),
+ gpu_crash_recorded_(false),
uma_memory_stats_received_(false) {
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kSingleProcess) ||
CommandLine::ForCurrentProcess()->HasSwitch(switches::kInProcessGPU)) {
@@ -361,67 +366,7 @@ GpuProcessHost::~GpuProcessHost() {
SendOutstandingReplies();
- // Maximum number of times the gpu process is allowed to crash in a session.
- // Once this limit is reached, any request to launch the gpu process will
- // fail.
- const int kGpuMaxCrashCount = 3;
-
- // Number of times the gpu process has crashed in the current browser session.
- static int gpu_crash_count = 0;
- static int gpu_recent_crash_count = 0;
- static base::Time last_gpu_crash_time;
- static bool crashed_before = false;
- static int swiftshader_crash_count = 0;
-
- bool disable_crash_limit = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableGpuProcessCrashLimit);
-
- // Ending only acts as a failure if the GPU process was actually started and
- // was intended for actual rendering (and not just checking caps or other
- // options).
- if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) {
- if (swiftshader_rendering_) {
- UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents",
- DIED_FIRST_TIME + swiftshader_crash_count,
- GPU_PROCESS_LIFETIME_EVENT_MAX);
-
- if (++swiftshader_crash_count >= kGpuMaxCrashCount &&
- !disable_crash_limit) {
- // SwiftShader is too unstable to use. Disable it for current session.
- gpu_enabled_ = false;
- }
- } else {
- ++gpu_crash_count;
- UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
- std::min(DIED_FIRST_TIME + gpu_crash_count,
- GPU_PROCESS_LIFETIME_EVENT_MAX - 1),
- GPU_PROCESS_LIFETIME_EVENT_MAX);
-
- // Allow about 1 GPU crash per hour to be removed from the crash count,
- // so very occasional crashes won't eventually add up and prevent the
- // GPU process from launching.
- ++gpu_recent_crash_count;
- base::Time current_time = base::Time::Now();
- if (crashed_before) {
- int hours_different = (current_time - last_gpu_crash_time).InHours();
- gpu_recent_crash_count =
- std::max(0, gpu_recent_crash_count - hours_different);
- }
-
- crashed_before = true;
- last_gpu_crash_time = current_time;
-
- if ((gpu_recent_crash_count >= kGpuMaxCrashCount && !disable_crash_limit)
- || !initialized_) {
-#if !defined(OS_CHROMEOS)
- // The gpu process is too unstable to use. Disable it for current
- // session.
- hardware_gpu_enabled_ = false;
- GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration();
-#endif
- }
- }
- }
+ RecordProcessCrash();
// In case we never started, clean up.
while (!queued_messages_.empty()) {
@@ -861,6 +806,7 @@ void GpuProcessHost::OnProcessLaunched() {
void GpuProcessHost::OnProcessCrashed(int exit_code) {
SendOutstandingReplies();
+ RecordProcessCrash();
GpuDataManagerImpl::GetInstance()->ProcessCrashed(
process_->GetTerminationStatus(true /* known_dead */, NULL));
}
@@ -1023,6 +969,72 @@ void GpuProcessHost::BlockLiveOffscreenContexts() {
}
}
+void GpuProcessHost::RecordProcessCrash() {
+ // Skip if a GPU process crash was already counted.
+ if (gpu_crash_recorded_)
+ return;
+
+ // Maximum number of times the gpu process is allowed to crash in a session.
+ // Once this limit is reached, any request to launch the gpu process will
+ // fail.
+ const int kGpuMaxCrashCount = 3;
+
+ // Last time the GPU process crashed.
+ static base::Time last_gpu_crash_time;
+
+ bool disable_crash_limit = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuProcessCrashLimit);
+
+ // Ending only acts as a failure if the GPU process was actually started and
+ // was intended for actual rendering (and not just checking caps or other
+ // options).
+ if (process_launched_ && kind_ == GPU_PROCESS_KIND_SANDBOXED) {
+ gpu_crash_recorded_ = true;
+ if (swiftshader_rendering_) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.SwiftShaderLifetimeEvents",
+ DIED_FIRST_TIME + swiftshader_crash_count_,
+ GPU_PROCESS_LIFETIME_EVENT_MAX);
+
+ if (++swiftshader_crash_count_ >= kGpuMaxCrashCount &&
+ !disable_crash_limit) {
+ // SwiftShader is too unstable to use. Disable it for current session.
+ gpu_enabled_ = false;
+ }
+ } else {
+ ++gpu_crash_count_;
+ UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
+ std::min(DIED_FIRST_TIME + gpu_crash_count_,
+ GPU_PROCESS_LIFETIME_EVENT_MAX - 1),
+ GPU_PROCESS_LIFETIME_EVENT_MAX);
+
+ // Allow about 1 GPU crash per hour to be removed from the crash count,
+ // so very occasional crashes won't eventually add up and prevent the
+ // GPU process from launching.
+ ++gpu_recent_crash_count_;
+ base::Time current_time = base::Time::Now();
+ if (crashed_before_) {
+ int hours_different = (current_time - last_gpu_crash_time).InHours();
+ gpu_recent_crash_count_ =
+ std::max(0, gpu_recent_crash_count_ - hours_different);
+ }
+
+ crashed_before_ = true;
+ last_gpu_crash_time = current_time;
+
+ if ((gpu_recent_crash_count_ >= kGpuMaxCrashCount &&
+ !disable_crash_limit) ||
+ !initialized_) {
+#if !defined(OS_CHROMEOS)
+ // The gpu process is too unstable to use. Disable it for current
+ // session.
+ hardware_gpu_enabled_ = false;
+ GpuDataManagerImpl::GetInstance()->DisableHardwareAcceleration();
+#endif
+ }
+ }
+ }
+}
+
std::string GpuProcessHost::GetShaderPrefixKey() {
if (shader_prefix_key_.empty()) {
gpu::GPUInfo info = GpuDataManagerImpl::GetInstance()->GetGPUInfo();
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 76de960..f4c9acb 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -68,6 +68,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
CreateGpuMemoryBufferCallback;
static bool gpu_enabled() { return gpu_enabled_; }
+ static int gpu_crash_count() { return gpu_crash_count_; }
// Creates a new GpuProcessHost or gets an existing one, resulting in the
// launching of a GPU process if required. Returns null on failure. It
@@ -187,6 +188,9 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
void BlockLiveOffscreenContexts();
+ // Update GPU crash counters. Disable GPU if crash limit is reached.
+ void RecordProcessCrash();
+
std::string GetShaderPrefixKey();
// The serial number of the GpuProcessHost / GpuProcessHostUIShim pair.
@@ -226,6 +230,9 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
// Time Init started. Used to log total GPU process startup time to UMA.
base::TimeTicks init_start_time_;
+ // Whether this host recorded a GPU crash or not.
+ bool gpu_crash_recorded_;
+
// Master switch for enabling/disabling GPU acceleration for the current
// browser session. It does not change the acceleration settings for
// existing tabs, just the future ones.
@@ -233,6 +240,11 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
static bool hardware_gpu_enabled_;
+ static int gpu_crash_count_;
+ static int gpu_recent_crash_count_;
+ static bool crashed_before_;
+ static int swiftshader_crash_count_;
+
scoped_ptr<BrowserChildProcessHostImpl> process_;
// Track the URLs of the pages which have live offscreen contexts,
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index f23d46c..164052e 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -183,6 +183,7 @@ IPC_STRUCT_TRAITS_BEGIN(gpu::GPUInfo)
IPC_STRUCT_TRAITS_MEMBER(software_rendering)
IPC_STRUCT_TRAITS_MEMBER(direct_rendering)
IPC_STRUCT_TRAITS_MEMBER(sandboxed)
+ IPC_STRUCT_TRAITS_MEMBER(process_crash_count)
#if defined(OS_WIN)
IPC_STRUCT_TRAITS_MEMBER(dx_diagnostics)
#endif
diff --git a/content/test/data/gpu/gpu_process_crash.html b/content/test/data/gpu/gpu_process_crash.html
new file mode 100644
index 0000000..a53e55c
--- /dev/null
+++ b/content/test/data/gpu/gpu_process_crash.html
@@ -0,0 +1,52 @@
+<html>
+<head>
+<script type="text/javascript">
+function onLoad() {
+ window.domAutomationController.reset = function() {
+ window.domAutomationController._loaded = false;
+ window.domAutomationController._succeeded = false;
+ window.domAutomationController._finished = false;
+ window.requestAnimationFrame(draw);
+ };
+ window.domAutomationController.send("LOADED");
+}
+
+function draw() {
+ // Render some WebGL into a fresh canvas to ensure the GPU process
+ // was created.
+ var canvas = document.createElement("canvas");
+ canvas.width = 32;
+ canvas.height = 32;
+ gl = canvas.getContext("webgl");
+ if (!gl) {
+ console.log("Failed to fetch WebGL context");
+ window.domAutomationController.send("FAILED");
+ return;
+ }
+
+ gl.clearColor(1, 0, 0, 1);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+ var pixels = new Uint8Array(4);
+ gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+ var tolerance = 1;
+ if (Math.abs(pixels[0] - 255) > tolerance ||
+ Math.abs(pixels[1] - 0) > tolerance ||
+ Math.abs(pixels[2] - 0) > tolerance ||
+ Math.abs(pixels[3] - 255) > tolerance) {
+ console.log("Expected (255, 0, 0, 255), got (" +
+ pixels[0] + ", " +
+ pixels[1] + ", " +
+ pixels[2] + ", " +
+ pixels[3] + ")");
+ window.domAutomationController.send("FAILED");
+ return;
+ }
+
+ window.domAutomationController.send("SUCCESS");
+}
+</script>
+</head>
+<body onload="onLoad()">
+GPU process crash test running.
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/context_lost.py b/content/test/gpu/gpu_tests/context_lost.py
index 731fffb..b691e8f 100644
--- a/content/test/gpu/gpu_tests/context_lost.py
+++ b/content/test/gpu/gpu_tests/context_lost.py
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
+import time
from telemetry import benchmark as benchmark_module
from telemetry.core import exceptions
@@ -37,6 +38,11 @@ harness_script = r"""
}
}
+ domAutomationController.reset = function() {
+ domAutomationController._succeeded = false;
+ domAutomationController._finished = false;
+ }
+
window.domAutomationController = domAutomationController;
console.log("Harness injected.");
"""
@@ -65,18 +71,26 @@ class _ContextLostValidator(page_test.PageTest):
for x in range(page.number_of_gpu_process_kills):
if not tab.browser.supports_tab_control:
raise page_test.Failure('Browser must support tab control')
+
+ expected_kills = x + 1
+
# Reset the test's state.
tab.EvaluateJavaScript(
- 'window.domAutomationController._succeeded = false');
- tab.EvaluateJavaScript(
- 'window.domAutomationController._finished = false');
+ 'window.domAutomationController.reset()');
+
+ # If we're running the GPU process crash test, we need the
+ # test to have fully reset before crashing the GPU process.
+ if page.check_crash_count:
+ util.WaitFor(lambda: tab.EvaluateJavaScript(
+ 'window.domAutomationController._finished'), wait_timeout)
+
# Crash the GPU process.
- new_tab = tab.browser.tabs.New()
+ gpucrash_tab = tab.browser.tabs.New()
# To access these debug URLs from Telemetry, they have to be
# written using the chrome:// scheme.
# The try/except is a workaround for crbug.com/368107.
try:
- new_tab.Navigate('chrome://gpucrash')
+ gpucrash_tab.Navigate('chrome://gpucrash')
except (exceptions.TabCrashException, Exception):
print 'Tab crashed while navigating to chrome://gpucrash'
# Activate the original tab and wait for completion.
@@ -88,9 +102,48 @@ class _ContextLostValidator(page_test.PageTest):
completed = True
except util.TimeoutException:
pass
+
+ if page.check_crash_count:
+ if not tab.browser.supports_system_info:
+ raise page_test.Failure('Browser must support system info')
+
+ if not tab.EvaluateJavaScript(
+ 'window.domAutomationController._succeeded'):
+ raise page_test.Failure(
+ 'Test failed (didn\'t render content properly?)')
+
+ number_of_crashes = -1
+ # To allow time for a gpucrash to complete, wait up to 20s,
+ # polling repeatedly.
+ start_time = time.time()
+ current_time = time.time()
+ while current_time - start_time < 20:
+ system_info = tab.browser.GetSystemInfo()
+ number_of_crashes = \
+ system_info.gpu.aux_attributes[u'process_crash_count']
+ if number_of_crashes >= expected_kills:
+ break
+ time.sleep(1)
+ current_time = time.time()
+
+ # Wait 5 more seconds and re-read process_crash_count, in
+ # attempt to catch latent process crashes.
+ time.sleep(5)
+ system_info = tab.browser.GetSystemInfo()
+ number_of_crashes = \
+ system_info.gpu.aux_attributes[u'process_crash_count']
+
+ if number_of_crashes < expected_kills:
+ raise page_test.Failure(
+ 'Timed out waiting for a gpu process crash')
+ elif number_of_crashes != expected_kills:
+ raise page_test.Failure(
+ 'Expected %d gpu process crashes; got: %d' %
+ (expected_kills, number_of_crashes))
+
# The try/except is a workaround for crbug.com/368107.
try:
- new_tab.Close()
+ gpucrash_tab.Close()
except (exceptions.TabCrashException, Exception):
print 'Tab crashed while closing chrome://gpucrash'
if not completed:
@@ -137,6 +190,26 @@ class _ContextLostValidator(page_test.PageTest):
'window.domAutomationController._succeeded'):
raise page_test.Failure('Test failed')
+# Test that navigating to chrome://gpucrash causes the GPU process to crash
+# exactly one time per navigation.
+class GPUProcessCrashesExactlyOnce(page.Page):
+ def __init__(self, page_set, base_dir):
+ super(GPUProcessCrashesExactlyOnce, self).__init__(
+ url='file://gpu_process_crash.html',
+ page_set=page_set,
+ base_dir=base_dir,
+ name='GpuCrash.GPUProcessCrashesExactlyOnce')
+ self.script_to_evaluate_on_commit = harness_script
+ self.kill_gpu_process = True
+ self.number_of_gpu_process_kills = 2
+ self.check_crash_count = True
+ self.force_garbage_collection = False
+
+ def RunNavigateSteps(self, action_runner):
+ action_runner.NavigateToPage(self)
+ action_runner.WaitForJavaScriptCondition(
+ 'window.domAutomationController._loaded')
+
class WebGLContextLostFromGPUProcessExitPage(page.Page):
def __init__(self, page_set, base_dir):
super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
@@ -146,6 +219,7 @@ class WebGLContextLostFromGPUProcessExitPage(page.Page):
name='ContextLost.WebGLContextLostFromGPUProcessExit')
self.script_to_evaluate_on_commit = harness_script
self.kill_gpu_process = True
+ self.check_crash_count = False
self.number_of_gpu_process_kills = 1
self.force_garbage_collection = False
@@ -164,6 +238,7 @@ class WebGLContextLostFromLoseContextExtensionPage(page.Page):
name='ContextLost.WebGLContextLostFromLoseContextExtension')
self.script_to_evaluate_on_commit = harness_script
self.kill_gpu_process = False
+ self.check_crash_count = False
self.force_garbage_collection = False
def RunNavigateSteps(self, action_runner):
@@ -180,6 +255,7 @@ class WebGLContextLostFromQuantityPage(page.Page):
name='ContextLost.WebGLContextLostFromQuantity')
self.script_to_evaluate_on_commit = harness_script
self.kill_gpu_process = False
+ self.check_crash_count = False
self.force_garbage_collection = True
def RunNavigateSteps(self, action_runner):
@@ -196,6 +272,7 @@ class WebGLContextLostFromSelectElementPage(page.Page):
name='ContextLost.WebGLContextLostFromSelectElement')
self.script_to_evaluate_on_commit = harness_script
self.kill_gpu_process = False
+ self.check_crash_count = False
self.force_garbage_collection = False
def RunNavigateSteps(self, action_runner):
@@ -214,6 +291,7 @@ class ContextLost(benchmark_module.Benchmark):
file_path=data_path,
user_agent_type='desktop',
serving_dirs=set(['']))
+ ps.AddPage(GPUProcessCrashesExactlyOnce(ps, ps.base_dir))
ps.AddPage(WebGLContextLostFromGPUProcessExitPage(ps, ps.base_dir))
ps.AddPage(WebGLContextLostFromLoseContextExtensionPage(ps, ps.base_dir))
ps.AddPage(WebGLContextLostFromQuantityPage(ps, ps.base_dir))
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index 2c7e67b..fd3d8a3 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -39,7 +39,8 @@ GPUInfo::GPUInfo()
can_lose_context(false),
software_rendering(false),
direct_rendering(true),
- sandboxed(false) {
+ sandboxed(false),
+ process_crash_count(0) {
}
GPUInfo::~GPUInfo() { }
@@ -75,6 +76,7 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
bool software_rendering;
bool direct_rendering;
bool sandboxed;
+ int process_crash_count;
#if defined(OS_WIN)
DxDiagNode dx_diagnostics;
#endif
@@ -127,6 +129,7 @@ void GPUInfo::EnumerateFields(Enumerator* enumerator) const {
enumerator->AddBool("softwareRendering", software_rendering);
enumerator->AddBool("directRendering", direct_rendering);
enumerator->AddBool("sandboxed", sandboxed);
+ enumerator->AddInt("processCrashCount", process_crash_count);
// TODO(kbr): add dx_diagnostics on Windows.
enumerator->EndAuxAttributes();
}
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 40630b3..d092c3a 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -153,6 +153,9 @@ struct GPU_EXPORT GPUInfo {
// Whether the gpu process is running in a sandbox.
bool sandboxed;
+ // Number of GPU process crashes recorded.
+ int process_crash_count;
+
#if defined(OS_WIN)
// The information returned by the DirectX Diagnostics Tool.
DxDiagNode dx_diagnostics;
diff --git a/tools/telemetry/telemetry/core/backends/chrome/system_info_backend.py b/tools/telemetry/telemetry/core/backends/chrome/system_info_backend.py
index 3a8a08c..00a78a7 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/system_info_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/system_info_backend.py
@@ -2,7 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-from telemetry import decorators
from telemetry.core import camel_case
from telemetry.core import system_info
from telemetry.core.backends.chrome import inspector_websocket
@@ -12,7 +11,6 @@ class SystemInfoBackend(object):
def __init__(self, devtools_port):
self._port = devtools_port
- @decorators.Cache
def GetSystemInfo(self, timeout=10):
req = {'method': 'SystemInfo.getInfo'}
websocket = inspector_websocket.InspectorWebsocket()
diff --git a/tools/telemetry/telemetry/core/browser_unittest.py b/tools/telemetry/telemetry/core/browser_unittest.py
index eeb3d8d..9a44089 100644
--- a/tools/telemetry/telemetry/core/browser_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_unittest.py
@@ -157,6 +157,17 @@ class BrowserTest(unittest.TestCase):
for g in info.gpu.devices:
self.assertTrue(isinstance(g, gpu_device.GPUDevice))
+ def testGetSystemInfoNotCachedObject(self):
+ b = self.CreateBrowser()
+ if not b.supports_system_info:
+ logging.warning(
+ 'Browser does not support getting system info, skipping test.')
+ return
+
+ info_a = b.GetSystemInfo()
+ info_b = b.GetSystemInfo()
+ self.assertFalse(info_a is info_b)
+
def testGetSystemTotalMemory(self):
b = self.CreateBrowser()
self.assertTrue(b.memory_stats['SystemTotalPhysicalMemory'] > 0)