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.
4from telemetry.page import page as page_module
5from telemetry.page import page_set as page_set_module
6
7
8class ToughSchedulingCasesPage(page_module.Page):
9
10  def __init__(self, url, page_set):
11    super(ToughSchedulingCasesPage, self).__init__(url=url, page_set=page_set)
12    self.credentials_path = 'data/credentials.json'
13    self.user_agent_type = 'mobile'
14    self.archive_data_file = 'data/tough_scheduling_cases.json'
15
16  def RunSmoothness(self, action_runner):
17    interaction = action_runner.BeginGestureInteraction(
18        'ScrollAction', is_smooth=True)
19    action_runner.ScrollPage()
20    interaction.End()
21
22
23class Page1(ToughSchedulingCasesPage):
24
25  """ Why: Simulate oversubscribed main thread """
26
27  def __init__(self, page_set):
28    super(Page1, self).__init__(
29      url='file://tough_scheduling_cases/simple_text_page.html?main_busy',
30      page_set=page_set)
31
32    self.synthetic_delays = {'cc.BeginMainFrame': {'target_duration': 0.008}}
33
34
35class Page2(ToughSchedulingCasesPage):
36
37  """ Why: Simulate oversubscribed main thread """
38
39  def __init__(self, page_set):
40    super(Page2, self).__init__(
41      # pylint: disable=C0301
42      url='file://tough_scheduling_cases/simple_text_page.html?main_very_busy',
43      page_set=page_set)
44
45    self.synthetic_delays = {'cc.BeginMainFrame': {'target_duration': 0.024}}
46
47
48class Page3(ToughSchedulingCasesPage):
49
50  """ Why: Simulate a page with a a few graphics layers """
51
52  def __init__(self, page_set):
53    super(Page3, self).__init__(
54      # pylint: disable=C0301
55      url='file://tough_scheduling_cases/simple_text_page.html?medium_layers',
56      page_set=page_set)
57
58    self.synthetic_delays = {
59      'cc.DrawAndSwap': {'target_duration': 0.004},
60      'gpu.PresentingFrame': {'target_duration': 0.004},
61      'cc.BeginMainFrame': {'target_duration': 0.004}
62    }
63
64
65class Page4(ToughSchedulingCasesPage):
66
67  """ Why: Simulate a page with many graphics layers """
68
69  def __init__(self, page_set):
70    super(Page4, self).__init__(
71      # pylint: disable=C0301
72      url='file://tough_scheduling_cases/simple_text_page.html?many_layers',
73      page_set=page_set)
74
75    self.synthetic_delays = {
76      'cc.DrawAndSwap': {'target_duration': 0.012},
77      'gpu.PresentingFrame': {'target_duration': 0.012},
78      'cc.BeginMainFrame': {'target_duration': 0.012}
79    }
80
81
82class Page5(ToughSchedulingCasesPage):
83
84  """ Why: Simulate a page with expensive recording and rasterization """
85
86  def __init__(self, page_set):
87    super(Page5, self).__init__(
88      # pylint: disable=C0301
89      url='file://tough_scheduling_cases/simple_text_page.html?medium_raster',
90      page_set=page_set)
91
92    self.synthetic_delays = {
93      'cc.RasterRequiredForActivation': {'target_duration': 0.004},
94      'cc.BeginMainFrame': {'target_duration': 0.004},
95      'gpu.AsyncTexImage': {'target_duration': 0.004}
96    }
97
98
99class Page6(ToughSchedulingCasesPage):
100
101  """ Why: Simulate a page with expensive recording and rasterization """
102
103  def __init__(self, page_set):
104    super(Page6, self).__init__(
105      # pylint: disable=C0301
106      url='file://tough_scheduling_cases/simple_text_page.html?heavy_raster',
107      page_set=page_set)
108
109    self.synthetic_delays = {
110      'cc.RasterRequiredForActivation': {'target_duration': 0.024},
111      'cc.BeginMainFrame': {'target_duration': 0.024},
112      'gpu.AsyncTexImage': {'target_duration': 0.024}
113    }
114
115
116class Page7(ToughSchedulingCasesPage):
117
118  """ Why: Medium cost touch handler """
119
120  def __init__(self, page_set):
121    super(Page7, self).__init__(
122      # pylint: disable=C0301
123      url='file://tough_scheduling_cases/touch_handler_scrolling.html?medium_handler',
124      page_set=page_set)
125
126    self.synthetic_delays = {'blink.HandleInputEvent':
127                             {'target_duration': 0.008}}
128
129
130class Page8(ToughSchedulingCasesPage):
131
132  """ Why: Slow touch handler """
133
134  def __init__(self, page_set):
135    super(Page8, self).__init__(
136      # pylint: disable=C0301
137      url='file://tough_scheduling_cases/touch_handler_scrolling.html?slow_handler',
138      page_set=page_set)
139
140    self.synthetic_delays = {'blink.HandleInputEvent':
141                             {'target_duration': 0.024}}
142
143
144class Page9(ToughSchedulingCasesPage):
145
146  """ Why: Touch handler that often takes a long time """
147
148  def __init__(self, page_set):
149    super(Page9, self).__init__(
150      # pylint: disable=C0301
151      url='file://tough_scheduling_cases/touch_handler_scrolling.html?janky_handler',
152      page_set=page_set)
153
154    self.synthetic_delays = {'blink.HandleInputEvent':
155                             {'target_duration': 0.024, 'mode': 'alternating'}
156                            }
157
158
159class Page10(ToughSchedulingCasesPage):
160
161  """ Why: Touch handler that occasionally takes a long time """
162
163  def __init__(self, page_set):
164    super(Page10, self).__init__(
165      # pylint: disable=C0301
166      url='file://tough_scheduling_cases/touch_handler_scrolling.html?occasionally_janky_handler',
167      page_set=page_set)
168
169    self.synthetic_delays = {'blink.HandleInputEvent':
170                             {'target_duration': 0.024, 'mode': 'oneshot'}}
171
172
173class Page11(ToughSchedulingCasesPage):
174
175  """ Why: Super expensive touch handler causes browser to scroll after a
176  timeout.
177  """
178
179  def __init__(self, page_set):
180    super(Page11, self).__init__(
181      # pylint: disable=C0301
182      url='file://tough_scheduling_cases/touch_handler_scrolling.html?super_slow_handler',
183      page_set=page_set)
184
185    self.synthetic_delays = {'blink.HandleInputEvent':
186                             {'target_duration': 0.2}}
187
188
189class Page12(ToughSchedulingCasesPage):
190
191  """ Why: Super expensive touch handler that only occupies a part of the page.
192  """
193
194  def __init__(self, page_set):
195    super(Page12, self).__init__(
196      url='file://tough_scheduling_cases/div_touch_handler.html',
197      page_set=page_set)
198
199    self.synthetic_delays = {'blink.HandleInputEvent': {'target_duration': 0.2}}
200
201
202class Page13(ToughSchedulingCasesPage):
203
204  """ Why: Test a moderately heavy requestAnimationFrame handler """
205
206  def __init__(self, page_set):
207    super(Page13, self).__init__(
208      url='file://tough_scheduling_cases/raf.html?medium_handler',
209      page_set=page_set)
210
211    self.synthetic_delays = {
212      'cc.RasterRequiredForActivation': {'target_duration': 0.004},
213      'cc.BeginMainFrame': {'target_duration': 0.004},
214      'gpu.AsyncTexImage': {'target_duration': 0.004}
215    }
216
217
218class Page14(ToughSchedulingCasesPage):
219
220  """ Why: Test a moderately heavy requestAnimationFrame handler """
221
222  def __init__(self, page_set):
223    super(Page14, self).__init__(
224      url='file://tough_scheduling_cases/raf.html?heavy_handler',
225      page_set=page_set)
226
227    self.synthetic_delays = {
228      'cc.RasterRequiredForActivation': {'target_duration': 0.024},
229      'cc.BeginMainFrame': {'target_duration': 0.024},
230      'gpu.AsyncTexImage': {'target_duration': 0.024}
231    }
232
233
234class Page15(ToughSchedulingCasesPage):
235
236  """ Why: Simulate a heavily GPU bound page """
237
238  def __init__(self, page_set):
239    super(Page15, self).__init__(
240      url='file://tough_scheduling_cases/raf.html?gpu_bound',
241      page_set=page_set)
242
243    self.synthetic_delays = {'gpu.PresentingFrame': {'target_duration': 0.1}}
244
245
246class Page16(ToughSchedulingCasesPage):
247
248  """ Why: Test a requestAnimationFrame handler with a heavy first frame """
249
250  def __init__(self, page_set):
251    super(Page16, self).__init__(
252      url='file://tough_scheduling_cases/raf.html?heavy_first_frame',
253      page_set=page_set)
254
255    self.synthetic_delays = {'cc.BeginMainFrame': {'target_duration': 0.15,
256                                                   'mode': 'oneshot'}}
257
258
259class Page17(ToughSchedulingCasesPage):
260
261  """ Why: Medium stress test for the scheduler """
262
263  def __init__(self, page_set):
264    super(Page17, self).__init__(
265      url='file://tough_scheduling_cases/raf_touch_animation.html?medium',
266      page_set=page_set)
267
268    self.synthetic_delays = {
269      'cc.DrawAndSwap': {'target_duration': 0.004},
270      'cc.BeginMainFrame': {'target_duration': 0.004}
271    }
272
273
274class Page18(ToughSchedulingCasesPage):
275
276  """ Why: Heavy stress test for the scheduler """
277
278  def __init__(self, page_set):
279    super(Page18, self).__init__(
280      url='file://tough_scheduling_cases/raf_touch_animation.html?heavy',
281      page_set=page_set)
282
283    self.synthetic_delays = {
284      'cc.DrawAndSwap': {'target_duration': 0.012},
285      'cc.BeginMainFrame': {'target_duration': 0.012}
286    }
287
288
289class Page19(ToughSchedulingCasesPage):
290
291  """ Why: Both main and impl thread animating concurrently """
292
293  def __init__(self, page_set):
294    super(Page19, self).__init__(
295      url='file://tough_scheduling_cases/split_animation.html',
296      page_set=page_set)
297
298  def RunSmoothness(self, action_runner):
299    action_runner.Wait(3)
300
301
302class Page20(ToughSchedulingCasesPage):
303
304  """ Why: Simple JS touch dragging """
305
306  def __init__(self, page_set):
307    super(Page20, self).__init__(
308      url='file://tough_scheduling_cases/simple_touch_drag.html',
309      page_set=page_set)
310
311  def RunSmoothness(self, action_runner):
312    interaction = action_runner.BeginGestureInteraction(
313        'ScrollAction', is_smooth=True)
314    action_runner.ScrollElement(
315        selector='#card',
316        use_touch=True,
317        direction='up',
318        speed_in_pixels_per_second=150,
319        distance=400)
320    interaction.End()
321
322
323class EmptyTouchHandlerPage(ToughSchedulingCasesPage):
324
325  """ Why: Scrolling on a page with a touch handler that consumes no events but
326      may be slow """
327
328  def __init__(self, name, desktop, slow_handler, bounce, page_set):
329    super(EmptyTouchHandlerPage, self).__init__(
330      url='file://tough_scheduling_cases/empty_touch_handler' +
331        ('_desktop' if desktop else '') + '.html?' + name,
332      page_set=page_set)
333
334    if slow_handler:
335      self.synthetic_delays = {
336        'blink.HandleInputEvent': {'target_duration': 0.2}
337      }
338
339    self.bounce = bounce
340
341  def RunSmoothness(self, action_runner):
342    if self.bounce:
343      interaction = action_runner.BeginGestureInteraction(
344          'ScrollBounceAction', is_smooth=True)
345      action_runner.ScrollBouncePage()
346      interaction.End()
347    else:
348      interaction = action_runner.BeginGestureInteraction(
349          'ScrollAction', is_smooth=True)
350      # Speed and distance are tuned to run exactly as long as a scroll
351      # bounce.
352      action_runner.ScrollPage(use_touch=True, speed_in_pixels_per_second=400,
353                               distance=2100)
354      interaction.End()
355
356
357class SynchronizedScrollOffsetPage(ToughSchedulingCasesPage):
358
359  """Why: For measuring the latency of scroll-synchronized effects."""
360
361  def __init__(self, page_set):
362    super(SynchronizedScrollOffsetPage, self).__init__(
363      url='file://tough_scheduling_cases/sync_scroll_offset.html',
364      page_set=page_set)
365
366  def RunSmoothness(self, action_runner):
367    interaction = action_runner.BeginGestureInteraction(
368        'ScrollBounceAction', is_smooth=True)
369    action_runner.ScrollBouncePage()
370    interaction.End()
371
372
373class ToughSchedulingCasesPageSet(page_set_module.PageSet):
374
375  """ Tough scheduler latency test cases """
376
377  def __init__(self):
378    super(ToughSchedulingCasesPageSet, self).__init__(
379        credentials_path='data/credentials.json',
380        user_agent_type='mobile',
381        archive_data_file='data/tough_scheduling_cases.json',
382        bucket=page_set_module.INTERNAL_BUCKET)
383
384    # Why: Simple scrolling baseline
385    self.AddPage(ToughSchedulingCasesPage(
386      'file://tough_scheduling_cases/simple_text_page.html',
387      self))
388    self.AddPage(Page1(self))
389    self.AddPage(Page2(self))
390    self.AddPage(Page3(self))
391    self.AddPage(Page4(self))
392    # Disabled until crbug.com/413829 is fixed.
393    # self.AddPage(Page5(self))
394    # Disabled because of crbug.com/413829 and flakiness crbug.com/368532
395    # self.AddPage(Page6(self))
396    # Why: Touch handler scrolling baseline
397    self.AddPage(ToughSchedulingCasesPage(
398      'file://tough_scheduling_cases/touch_handler_scrolling.html',
399      self))
400    self.AddPage(Page7(self))
401    self.AddPage(Page8(self))
402    self.AddPage(Page9(self))
403    self.AddPage(Page10(self))
404    self.AddPage(Page11(self))
405    self.AddPage(Page12(self))
406    # Why: requestAnimationFrame scrolling baseline
407    self.AddPage(ToughSchedulingCasesPage(
408      'file://tough_scheduling_cases/raf.html',
409      self))
410    # Why: Test canvas blocking behavior
411    self.AddPage(ToughSchedulingCasesPage(
412      'file://tough_scheduling_cases/raf_canvas.html',
413      self))
414    # Disabled until crbug.com/413829 is fixed.
415    # self.AddPage(Page13(self))
416    # Disabled because of crbug.com/413829 and flakiness crbug.com/368532
417    # self.AddPage(Page14(self))
418    self.AddPage(Page15(self))
419    self.AddPage(Page16(self))
420    # Why: Test a requestAnimationFrame handler with concurrent CSS animation
421    self.AddPage(ToughSchedulingCasesPage(
422      'file://tough_scheduling_cases/raf_animation.html',
423      self))
424    # Why: Stress test for the scheduler
425    self.AddPage(ToughSchedulingCasesPage(
426      'file://tough_scheduling_cases/raf_touch_animation.html',
427      self))
428    self.AddPage(Page17(self))
429    self.AddPage(Page18(self))
430    self.AddPage(Page19(self))
431    self.AddPage(Page20(self))
432    # Why: Baseline for scrolling in the presence of a no-op touch handler
433    self.AddPage(EmptyTouchHandlerPage(
434      name='baseline',
435      desktop=False,
436      slow_handler=False,
437      bounce=False,
438      page_set=self))
439    # Why: Slow handler blocks scroll start
440    self.AddPage(EmptyTouchHandlerPage(
441      name='slow_handler',
442      desktop=False,
443      slow_handler=True,
444      bounce=False,
445      page_set=self))
446    # Why: Slow handler blocks scroll start until touch ACK timeout
447    self.AddPage(EmptyTouchHandlerPage(
448      name='desktop_slow_handler',
449      desktop=True,
450      slow_handler=True,
451      bounce=False,
452      page_set=self))
453    # Why: Scroll bounce showing repeated transitions between scrolling and
454    # sending synchronous touchmove events.  Should be nearly as fast as
455    # scroll baseline.
456    self.AddPage(EmptyTouchHandlerPage(
457      name='bounce',
458      desktop=False,
459      slow_handler=False,
460      bounce=True,
461      page_set=self))
462    # Why: Scroll bounce with slow handler, repeated blocking.
463    self.AddPage(EmptyTouchHandlerPage(
464      name='bounce_slow_handler',
465      desktop=False,
466      slow_handler=True,
467      bounce=True,
468      page_set=self))
469    # Why: Scroll bounce with slow handler on desktop, blocks only once until
470    # ACK timeout.
471    self.AddPage(EmptyTouchHandlerPage(
472      name='bounce_desktop_slow_handler',
473      desktop=True,
474      slow_handler=True,
475      bounce=True,
476      page_set=self))
477    # Why: For measuring the latency of scroll-synchronized effects.
478    self.AddPage(SynchronizedScrollOffsetPage(page_set=self))
479    # Why: Good examples of poor initial scrolling
480    self.AddPage(ToughSchedulingCasesPage(
481      'http://www.latimes.com',
482      self))
483    self.AddPage(ToughSchedulingCasesPage(
484      'http://m.espn.go.com/nhl/rankings',
485       self))
486