Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / test / gpu / gpu_tests / context_lost.py
blob89eabfba0eabf9c771926738c19f54f9c9358a4b
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 import os
5 import time
7 import context_lost_expectations
9 from telemetry import benchmark as benchmark_module
10 from telemetry.core import exceptions
11 from telemetry.core import util
12 from telemetry.page import page
13 from telemetry.page import page_set
14 from telemetry.page import page_test
16 data_path = os.path.join(
17 util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')
19 wait_timeout = 20 # seconds
21 harness_script = r"""
22 var domAutomationController = {};
24 domAutomationController._loaded = false;
25 domAutomationController._succeeded = false;
26 domAutomationController._finished = false;
28 domAutomationController.setAutomationId = function(id) {}
30 domAutomationController.send = function(msg) {
31 msg = msg.toLowerCase()
32 if (msg == "loaded") {
33 domAutomationController._loaded = true;
34 } else if (msg == "success") {
35 domAutomationController._succeeded = true;
36 domAutomationController._finished = true;
37 } else {
38 domAutomationController._succeeded = false;
39 domAutomationController._finished = true;
43 domAutomationController.reset = function() {
44 domAutomationController._succeeded = false;
45 domAutomationController._finished = false;
48 window.domAutomationController = domAutomationController;
49 console.log("Harness injected.");
50 """
52 class _ContextLostValidator(page_test.PageTest):
53 def __init__(self):
54 # Strictly speaking this test doesn't yet need a browser restart
55 # after each run, but if more tests are added which crash the GPU
56 # process, then it will.
57 super(_ContextLostValidator, self).__init__(
58 needs_browser_restart_after_each_page=True)
60 def CustomizeBrowserOptions(self, options):
61 options.AppendExtraBrowserArgs(
62 '--disable-domain-blocking-for-3d-apis')
63 options.AppendExtraBrowserArgs(
64 '--disable-gpu-process-crash-limit')
65 # Required for about:gpucrash handling from Telemetry.
66 options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')
68 def ValidateAndMeasurePage(self, page, tab, results):
69 if page.kill_gpu_process:
70 # Doing the GPU process kill operation cooperatively -- in the
71 # same page's context -- is much more stressful than restarting
72 # the browser every time.
73 for x in range(page.number_of_gpu_process_kills):
74 if not tab.browser.supports_tab_control:
75 raise page_test.Failure('Browser must support tab control')
77 expected_kills = x + 1
79 # Reset the test's state.
80 tab.EvaluateJavaScript(
81 'window.domAutomationController.reset()');
83 # If we're running the GPU process crash test, we need the
84 # test to have fully reset before crashing the GPU process.
85 if page.check_crash_count:
86 util.WaitFor(lambda: tab.EvaluateJavaScript(
87 'window.domAutomationController._finished'), wait_timeout)
89 # Crash the GPU process.
90 gpucrash_tab = tab.browser.tabs.New()
91 # To access these debug URLs from Telemetry, they have to be
92 # written using the chrome:// scheme.
93 # The try/except is a workaround for crbug.com/368107.
94 try:
95 gpucrash_tab.Navigate('chrome://gpucrash')
96 except (exceptions.TabCrashException, Exception):
97 print 'Tab crashed while navigating to chrome://gpucrash'
98 # Activate the original tab and wait for completion.
99 tab.Activate()
100 completed = False
101 try:
102 util.WaitFor(lambda: tab.EvaluateJavaScript(
103 'window.domAutomationController._finished'), wait_timeout)
104 completed = True
105 except util.TimeoutException:
106 pass
108 if page.check_crash_count:
109 if not tab.browser.supports_system_info:
110 raise page_test.Failure('Browser must support system info')
112 if not tab.EvaluateJavaScript(
113 'window.domAutomationController._succeeded'):
114 raise page_test.Failure(
115 'Test failed (didn\'t render content properly?)')
117 number_of_crashes = -1
118 # To allow time for a gpucrash to complete, wait up to 20s,
119 # polling repeatedly.
120 start_time = time.time()
121 current_time = time.time()
122 while current_time - start_time < 20:
123 system_info = tab.browser.GetSystemInfo()
124 number_of_crashes = \
125 system_info.gpu.aux_attributes[u'process_crash_count']
126 if number_of_crashes >= expected_kills:
127 break
128 time.sleep(1)
129 current_time = time.time()
131 # Wait 5 more seconds and re-read process_crash_count, in
132 # attempt to catch latent process crashes.
133 time.sleep(5)
134 system_info = tab.browser.GetSystemInfo()
135 number_of_crashes = \
136 system_info.gpu.aux_attributes[u'process_crash_count']
138 if number_of_crashes < expected_kills:
139 raise page_test.Failure(
140 'Timed out waiting for a gpu process crash')
141 elif number_of_crashes != expected_kills:
142 raise page_test.Failure(
143 'Expected %d gpu process crashes; got: %d' %
144 (expected_kills, number_of_crashes))
146 # The try/except is a workaround for crbug.com/368107.
147 try:
148 gpucrash_tab.Close()
149 except (exceptions.TabCrashException, Exception):
150 print 'Tab crashed while closing chrome://gpucrash'
151 if not completed:
152 raise page_test.Failure(
153 'Test didn\'t complete (no context lost event?)')
154 if not tab.EvaluateJavaScript(
155 'window.domAutomationController._succeeded'):
156 raise page_test.Failure(
157 'Test failed (context not restored properly?)')
158 elif page.force_garbage_collection:
159 # Try to corce GC to clean up any contexts not attached to the page.
160 # This method seem unreliable, so the page will also attempt to force
161 # GC through excessive allocations.
162 tab.CollectGarbage()
163 completed = False
164 try:
165 print "Waiting for page to finish."
166 util.WaitFor(lambda: tab.EvaluateJavaScript(
167 'window.domAutomationController._finished'), wait_timeout)
168 completed = True
169 except util.TimeoutException:
170 pass
172 if not completed:
173 raise page_test.Failure(
174 'Test didn\'t complete (no context restored event?)')
175 if not tab.EvaluateJavaScript(
176 'window.domAutomationController._succeeded'):
177 raise page_test.Failure(
178 'Test failed (context not restored properly?)')
179 else:
180 completed = False
181 try:
182 print "Waiting for page to finish."
183 util.WaitFor(lambda: tab.EvaluateJavaScript(
184 'window.domAutomationController._finished'), wait_timeout)
185 completed = True
186 except util.TimeoutException:
187 pass
189 if not completed:
190 raise page_test.Failure('Test didn\'t complete')
191 if not tab.EvaluateJavaScript(
192 'window.domAutomationController._succeeded'):
193 raise page_test.Failure('Test failed')
195 # Test that navigating to chrome://gpucrash causes the GPU process to crash
196 # exactly one time per navigation.
197 class GPUProcessCrashesExactlyOnce(page.Page):
198 def __init__(self, page_set, base_dir):
199 super(GPUProcessCrashesExactlyOnce, self).__init__(
200 url='file://gpu_process_crash.html',
201 page_set=page_set,
202 base_dir=base_dir,
203 name='GpuCrash.GPUProcessCrashesExactlyOnce')
204 self.script_to_evaluate_on_commit = harness_script
205 self.kill_gpu_process = True
206 self.number_of_gpu_process_kills = 2
207 self.check_crash_count = True
208 self.force_garbage_collection = False
210 def RunNavigateSteps(self, action_runner):
211 action_runner.NavigateToPage(self)
212 action_runner.WaitForJavaScriptCondition(
213 'window.domAutomationController._loaded')
215 class WebGLContextLostFromGPUProcessExitPage(page.Page):
216 def __init__(self, page_set, base_dir):
217 super(WebGLContextLostFromGPUProcessExitPage, self).__init__(
218 url='file://webgl.html?query=kill_after_notification',
219 page_set=page_set,
220 base_dir=base_dir,
221 name='ContextLost.WebGLContextLostFromGPUProcessExit')
222 self.script_to_evaluate_on_commit = harness_script
223 self.kill_gpu_process = True
224 self.check_crash_count = False
225 self.number_of_gpu_process_kills = 1
226 self.force_garbage_collection = False
228 def RunNavigateSteps(self, action_runner):
229 action_runner.NavigateToPage(self)
230 action_runner.WaitForJavaScriptCondition(
231 'window.domAutomationController._loaded')
234 class WebGLContextLostFromLoseContextExtensionPage(page.Page):
235 def __init__(self, page_set, base_dir):
236 super(WebGLContextLostFromLoseContextExtensionPage, self).__init__(
237 url='file://webgl.html?query=WEBGL_lose_context',
238 page_set=page_set,
239 base_dir=base_dir,
240 name='ContextLost.WebGLContextLostFromLoseContextExtension')
241 self.script_to_evaluate_on_commit = harness_script
242 self.kill_gpu_process = False
243 self.check_crash_count = False
244 self.force_garbage_collection = False
246 def RunNavigateSteps(self, action_runner):
247 action_runner.NavigateToPage(self)
248 action_runner.WaitForJavaScriptCondition(
249 'window.domAutomationController._finished')
251 class WebGLContextLostFromQuantityPage(page.Page):
252 def __init__(self, page_set, base_dir):
253 super(WebGLContextLostFromQuantityPage, self).__init__(
254 url='file://webgl.html?query=forced_quantity_loss',
255 page_set=page_set,
256 base_dir=base_dir,
257 name='ContextLost.WebGLContextLostFromQuantity')
258 self.script_to_evaluate_on_commit = harness_script
259 self.kill_gpu_process = False
260 self.check_crash_count = False
261 self.force_garbage_collection = True
263 def RunNavigateSteps(self, action_runner):
264 action_runner.NavigateToPage(self)
265 action_runner.WaitForJavaScriptCondition(
266 'window.domAutomationController._loaded')
268 class WebGLContextLostFromSelectElementPage(page.Page):
269 def __init__(self, page_set, base_dir):
270 super(WebGLContextLostFromSelectElementPage, self).__init__(
271 url='file://webgl_with_select_element.html',
272 page_set=page_set,
273 base_dir=base_dir,
274 name='ContextLost.WebGLContextLostFromSelectElement')
275 self.script_to_evaluate_on_commit = harness_script
276 self.kill_gpu_process = False
277 self.check_crash_count = False
278 self.force_garbage_collection = False
280 def RunNavigateSteps(self, action_runner):
281 action_runner.NavigateToPage(self)
282 action_runner.WaitForJavaScriptCondition(
283 'window.domAutomationController._loaded')
285 class ContextLost(benchmark_module.Benchmark):
286 enabled = True
287 test = _ContextLostValidator
289 def CreateExpectations(self, page_set):
290 return context_lost_expectations.ContextLostExpectations()
292 # For the record, this would have been another way to get the pages
293 # to repeat. pageset_repeat would be another option.
294 # options = {'page_repeat': 5}
295 def CreatePageSet(self, options):
296 ps = page_set.PageSet(
297 file_path=data_path,
298 user_agent_type='desktop',
299 serving_dirs=set(['']))
300 ps.AddPage(GPUProcessCrashesExactlyOnce(ps, ps.base_dir))
301 ps.AddPage(WebGLContextLostFromGPUProcessExitPage(ps, ps.base_dir))
302 ps.AddPage(WebGLContextLostFromLoseContextExtensionPage(ps, ps.base_dir))
303 ps.AddPage(WebGLContextLostFromQuantityPage(ps, ps.base_dir))
304 ps.AddPage(WebGLContextLostFromSelectElementPage(ps, ps.base_dir))
305 return ps