1 # Copyright 2014 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 from telemetry
.page
import page
as page_module
5 from telemetry
.page
import shared_page_state
6 from telemetry
import story
9 class ToughSchedulingCasesPage(page_module
.Page
):
11 def __init__(self
, url
, page_set
):
12 super(ToughSchedulingCasesPage
, self
).__init
__(
13 url
=url
, page_set
=page_set
, credentials_path
='data/credentials.json',
14 shared_page_state_class
=shared_page_state
.SharedMobilePageState
)
15 self
.archive_data_file
= 'data/tough_scheduling_cases.json'
17 def RunPageInteractions(self
, action_runner
):
18 with action_runner
.CreateGestureInteraction('ScrollAction'):
19 action_runner
.ScrollPage()
22 class Page1(ToughSchedulingCasesPage
):
24 """Why: Simulate oversubscribed main thread."""
26 def __init__(self
, page_set
):
27 super(Page1
, self
).__init
__(
28 url
='file://tough_scheduling_cases/simple_text_page.html?main_busy',
31 self
.synthetic_delays
= {'cc.BeginMainFrame': {'target_duration': 0.008}}
34 class Page2(ToughSchedulingCasesPage
):
36 """Why: Simulate oversubscribed main thread."""
38 def __init__(self
, page_set
):
39 super(Page2
, self
).__init
__(
40 # pylint: disable=C0301
41 url
='file://tough_scheduling_cases/simple_text_page.html?main_very_busy',
44 self
.synthetic_delays
= {'cc.BeginMainFrame': {'target_duration': 0.024}}
47 class Page3(ToughSchedulingCasesPage
):
49 """Why: Simulate a page with a a few graphics layers."""
51 def __init__(self
, page_set
):
52 super(Page3
, self
).__init
__(
53 # pylint: disable=C0301
54 url
='file://tough_scheduling_cases/simple_text_page.html?medium_layers',
57 self
.synthetic_delays
= {
58 'cc.DrawAndSwap': {'target_duration': 0.004},
59 'gpu.PresentingFrame': {'target_duration': 0.004},
60 'cc.BeginMainFrame': {'target_duration': 0.004}
64 class Page4(ToughSchedulingCasesPage
):
66 """Why: Simulate a page with many graphics layers."""
68 def __init__(self
, page_set
):
69 super(Page4
, self
).__init
__(
70 # pylint: disable=C0301
71 url
='file://tough_scheduling_cases/simple_text_page.html?many_layers',
74 self
.synthetic_delays
= {
75 'cc.DrawAndSwap': {'target_duration': 0.012},
76 'gpu.PresentingFrame': {'target_duration': 0.012},
77 'cc.BeginMainFrame': {'target_duration': 0.012}
81 class Page5(ToughSchedulingCasesPage
):
83 """Why: Simulate a page with expensive recording and rasterization."""
85 def __init__(self
, page_set
):
86 super(Page5
, self
).__init
__(
87 # pylint: disable=C0301
88 url
='file://tough_scheduling_cases/simple_text_page.html?medium_raster',
91 self
.synthetic_delays
= {
92 'cc.RasterRequiredForActivation': {'target_duration': 0.004},
93 'cc.BeginMainFrame': {'target_duration': 0.004},
94 'gpu.AsyncTexImage': {'target_duration': 0.004}
98 class Page6(ToughSchedulingCasesPage
):
100 """Why: Simulate a page with expensive recording and rasterization."""
102 def __init__(self
, page_set
):
103 super(Page6
, self
).__init
__(
104 # pylint: disable=C0301
105 url
='file://tough_scheduling_cases/simple_text_page.html?heavy_raster',
108 self
.synthetic_delays
= {
109 'cc.RasterRequiredForActivation': {'target_duration': 0.024},
110 'cc.BeginMainFrame': {'target_duration': 0.024},
111 'gpu.AsyncTexImage': {'target_duration': 0.024}
115 class Page7(ToughSchedulingCasesPage
):
117 """Why: Medium cost touch handler."""
119 def __init__(self
, page_set
):
120 super(Page7
, self
).__init
__(
121 # pylint: disable=C0301
122 url
='file://tough_scheduling_cases/touch_handler_scrolling.html?medium_handler',
125 self
.synthetic_delays
= {'blink.HandleInputEvent':
126 {'target_duration': 0.008}}
129 class Page8(ToughSchedulingCasesPage
):
131 """Why: Slow touch handler."""
133 def __init__(self
, page_set
):
134 super(Page8
, self
).__init
__(
135 # pylint: disable=C0301
136 url
='file://tough_scheduling_cases/touch_handler_scrolling.html?slow_handler',
139 self
.synthetic_delays
= {'blink.HandleInputEvent':
140 {'target_duration': 0.024}}
143 class Page9(ToughSchedulingCasesPage
):
145 """Why: Touch handler that often takes a long time."""
147 def __init__(self
, page_set
):
148 super(Page9
, self
).__init
__(
149 # pylint: disable=C0301
150 url
='file://tough_scheduling_cases/touch_handler_scrolling.html?janky_handler',
153 self
.synthetic_delays
= {'blink.HandleInputEvent':
154 {'target_duration': 0.024, 'mode': 'alternating'}
158 class Page10(ToughSchedulingCasesPage
):
160 """Why: Touch handler that occasionally takes a long time."""
162 def __init__(self
, page_set
):
163 super(Page10
, self
).__init
__(
164 # pylint: disable=C0301
165 url
='file://tough_scheduling_cases/touch_handler_scrolling.html?occasionally_janky_handler',
168 self
.synthetic_delays
= {'blink.HandleInputEvent':
169 {'target_duration': 0.024, 'mode': 'oneshot'}}
172 class Page11(ToughSchedulingCasesPage
):
174 """Why: Super expensive touch handler causes browser to scroll after a
177 def __init__(self
, page_set
):
178 super(Page11
, self
).__init
__(
179 # pylint: disable=C0301
180 url
='file://tough_scheduling_cases/touch_handler_scrolling.html?super_slow_handler',
183 self
.synthetic_delays
= {'blink.HandleInputEvent':
184 {'target_duration': 0.2}}
187 class Page12(ToughSchedulingCasesPage
):
189 """Why: Super expensive touch handler that only occupies a part of the page.
192 def __init__(self
, page_set
):
193 super(Page12
, self
).__init
__(
194 url
='file://tough_scheduling_cases/div_touch_handler.html',
197 self
.synthetic_delays
= {'blink.HandleInputEvent': {'target_duration': 0.2}}
200 class Page13(ToughSchedulingCasesPage
):
202 """Why: Test a moderately heavy requestAnimationFrame handler."""
204 def __init__(self
, page_set
):
205 super(Page13
, self
).__init
__(
206 url
='file://tough_scheduling_cases/raf.html?medium_handler',
209 self
.synthetic_delays
= {
210 'cc.RasterRequiredForActivation': {'target_duration': 0.004},
211 'cc.BeginMainFrame': {'target_duration': 0.004},
212 'gpu.AsyncTexImage': {'target_duration': 0.004}
216 class Page14(ToughSchedulingCasesPage
):
218 """Why: Test a moderately heavy requestAnimationFrame handler."""
220 def __init__(self
, page_set
):
221 super(Page14
, self
).__init
__(
222 url
='file://tough_scheduling_cases/raf.html?heavy_handler',
225 self
.synthetic_delays
= {
226 'cc.RasterRequiredForActivation': {'target_duration': 0.024},
227 'cc.BeginMainFrame': {'target_duration': 0.024},
228 'gpu.AsyncTexImage': {'target_duration': 0.024}
232 class Page15(ToughSchedulingCasesPage
):
234 """Why: Simulate a heavily GPU bound page."""
236 def __init__(self
, page_set
):
237 super(Page15
, self
).__init
__(
238 url
='file://tough_scheduling_cases/raf.html?gpu_bound',
241 self
.synthetic_delays
= {'gpu.PresentingFrame': {'target_duration': 0.1}}
244 class Page16(ToughSchedulingCasesPage
):
246 """Why: Test a requestAnimationFrame handler with a heavy first frame."""
248 def __init__(self
, page_set
):
249 super(Page16
, self
).__init
__(
250 url
='file://tough_scheduling_cases/raf.html?heavy_first_frame',
253 self
.synthetic_delays
= {'cc.BeginMainFrame': {'target_duration': 0.15,
257 class Page17(ToughSchedulingCasesPage
):
259 """Why: Medium stress test for the scheduler."""
261 def __init__(self
, page_set
):
262 super(Page17
, self
).__init
__(
263 url
='file://tough_scheduling_cases/raf_touch_animation.html?medium',
266 self
.synthetic_delays
= {
267 'cc.DrawAndSwap': {'target_duration': 0.004},
268 'cc.BeginMainFrame': {'target_duration': 0.004}
272 class Page18(ToughSchedulingCasesPage
):
274 """Why: Heavy stress test for the scheduler."""
276 def __init__(self
, page_set
):
277 super(Page18
, self
).__init
__(
278 url
='file://tough_scheduling_cases/raf_touch_animation.html?heavy',
281 self
.synthetic_delays
= {
282 'cc.DrawAndSwap': {'target_duration': 0.012},
283 'cc.BeginMainFrame': {'target_duration': 0.012}
287 class Page19(ToughSchedulingCasesPage
):
289 """Why: Both main and impl thread animating concurrently."""
291 def __init__(self
, page_set
):
292 super(Page19
, self
).__init
__(
293 url
='file://tough_scheduling_cases/split_animation.html',
296 def RunPageInteractions(self
, action_runner
):
297 with action_runner
.CreateInteraction('SplitAnimation'):
298 action_runner
.Wait(3)
301 class Page20(ToughSchedulingCasesPage
):
303 """Why: Simple JS touch dragging."""
305 def __init__(self
, page_set
):
306 super(Page20
, self
).__init
__(
307 url
='file://tough_scheduling_cases/simple_touch_drag.html',
310 def RunPageInteractions(self
, action_runner
):
311 with action_runner
.CreateGestureInteraction('ScrollAction'):
312 action_runner
.ScrollElement(
316 speed_in_pixels_per_second
=150,
320 class EmptyTouchHandlerPage(ToughSchedulingCasesPage
):
322 """Why: Scrolling on a page with a touch handler that consumes no events but
325 def __init__(self
, name
, desktop
, slow_handler
, bounce
, page_set
):
326 super(EmptyTouchHandlerPage
, self
).__init
__(
327 url
='file://tough_scheduling_cases/empty_touch_handler' +
328 ('_desktop' if desktop
else '') + '.html?' + name
,
332 self
.synthetic_delays
= {
333 'blink.HandleInputEvent': {'target_duration': 0.2}
338 def RunPageInteractions(self
, action_runner
):
340 with action_runner
.CreateGestureInteraction('ScrollBounceAction'):
341 action_runner
.ScrollBouncePage()
343 with action_runner
.CreateGestureInteraction('ScrollAction'):
344 # Speed and distance are tuned to run exactly as long as a scroll
346 action_runner
.ScrollPage(use_touch
=True, speed_in_pixels_per_second
=400,
350 class SynchronizedScrollOffsetPage(ToughSchedulingCasesPage
):
352 """Why: For measuring the latency of scroll-synchronized effects."""
354 def __init__(self
, page_set
):
355 super(SynchronizedScrollOffsetPage
, self
).__init
__(
356 url
='file://tough_scheduling_cases/sync_scroll_offset.html',
359 def RunPageInteractions(self
, action_runner
):
360 with action_runner
.CreateGestureInteraction('ScrollBounceAction'):
361 action_runner
.ScrollBouncePage()
364 class SecondBatchJsPage(ToughSchedulingCasesPage
):
366 """Why: For testing dynamically loading a large batch of Javascript and
367 running a part of it in response to user input.
370 def __init__(self
, page_set
, variant
='medium'):
371 super(SecondBatchJsPage
, self
).__init
__(
372 url
='file://tough_scheduling_cases/second_batch_js.html?%s' % variant
,
375 def RunPageInteractions(self
, action_runner
):
376 # Do a dummy tap to warm up the synthetic tap code path.
377 action_runner
.TapElement(selector
='div[id="spinner"]')
378 # Begin the action immediately because we want the page to update smoothly
379 # even while resources are being loaded.
380 action_runner
.WaitForJavaScriptCondition('window.__ready !== undefined')
382 with action_runner
.CreateGestureInteraction('LoadAction'):
383 action_runner
.ExecuteJavaScript('kickOffLoading()')
384 action_runner
.WaitForJavaScriptCondition('window.__ready')
385 # Click one second after the resources have finished loading.
386 action_runner
.Wait(1)
387 action_runner
.TapElement(selector
='input[id="run"]')
388 # Wait for the test to complete.
389 action_runner
.WaitForJavaScriptCondition('window.__finished')
392 class ToughSchedulingCasesPageSet(story
.StorySet
):
394 """Tough scheduler latency test cases."""
397 super(ToughSchedulingCasesPageSet
, self
).__init
__(
398 archive_data_file
='data/tough_scheduling_cases.json',
399 cloud_storage_bucket
=story
.INTERNAL_BUCKET
)
401 # Why: Simple scrolling baseline
402 self
.AddStory(ToughSchedulingCasesPage(
403 'file://tough_scheduling_cases/simple_text_page.html',
405 self
.AddStory(Page1(self
))
406 self
.AddStory(Page2(self
))
407 self
.AddStory(Page3(self
))
408 self
.AddStory(Page4(self
))
409 # Disabled until crbug.com/413829 is fixed.
410 # self.AddStory(Page5(self))
411 # Disabled because of crbug.com/413829 and flakiness crbug.com/368532
412 # self.AddStory(Page6(self))
413 # Why: Touch handler scrolling baseline
414 self
.AddStory(ToughSchedulingCasesPage(
415 'file://tough_scheduling_cases/touch_handler_scrolling.html',
417 self
.AddStory(Page7(self
))
418 self
.AddStory(Page8(self
))
419 self
.AddStory(Page9(self
))
420 self
.AddStory(Page10(self
))
421 self
.AddStory(Page11(self
))
422 self
.AddStory(Page12(self
))
423 # Why: requestAnimationFrame scrolling baseline
424 self
.AddStory(ToughSchedulingCasesPage(
425 'file://tough_scheduling_cases/raf.html',
427 # Why: Test canvas blocking behavior
428 self
.AddStory(ToughSchedulingCasesPage(
429 'file://tough_scheduling_cases/raf_canvas.html',
431 # Disabled until crbug.com/413829 is fixed.
432 # self.AddStory(Page13(self))
433 # Disabled because of crbug.com/413829 and flakiness crbug.com/368532
434 # self.AddStory(Page14(self))
435 self
.AddStory(Page15(self
))
436 self
.AddStory(Page16(self
))
437 # Why: Test a requestAnimationFrame handler with concurrent CSS animation
438 self
.AddStory(ToughSchedulingCasesPage(
439 'file://tough_scheduling_cases/raf_animation.html',
441 # Why: Stress test for the scheduler
442 self
.AddStory(ToughSchedulingCasesPage(
443 'file://tough_scheduling_cases/raf_touch_animation.html',
445 self
.AddStory(Page17(self
))
446 self
.AddStory(Page18(self
))
447 self
.AddStory(Page19(self
))
448 self
.AddStory(Page20(self
))
449 # Why: Baseline for scrolling in the presence of a no-op touch handler
450 self
.AddStory(EmptyTouchHandlerPage(
456 # Why: Slow handler blocks scroll start
457 self
.AddStory(EmptyTouchHandlerPage(
463 # Why: Slow handler blocks scroll start until touch ACK timeout
464 self
.AddStory(EmptyTouchHandlerPage(
465 name
='desktop_slow_handler',
470 # Why: Scroll bounce showing repeated transitions between scrolling and
471 # sending synchronous touchmove events. Should be nearly as fast as
473 self
.AddStory(EmptyTouchHandlerPage(
479 # Why: Scroll bounce with slow handler, repeated blocking.
480 self
.AddStory(EmptyTouchHandlerPage(
481 name
='bounce_slow_handler',
486 # Why: Scroll bounce with slow handler on desktop, blocks only once until
488 self
.AddStory(EmptyTouchHandlerPage(
489 name
='bounce_desktop_slow_handler',
494 # Why: For measuring the latency of scroll-synchronized effects.
495 self
.AddStory(SynchronizedScrollOffsetPage(page_set
=self
))
496 # Why: Test loading a large amount of Javascript.
497 self
.AddStory(SecondBatchJsPage(page_set
=self
, variant
='light'))
498 self
.AddStory(SecondBatchJsPage(page_set
=self
, variant
='medium'))
499 self
.AddStory(SecondBatchJsPage(page_set
=self
, variant
='heavy'))