blob: ac0de953df9a0bf25402ac8c83233403ea2295ec [file] [log] [blame]
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from telemetry.page import page as page_module
from telemetry.page import shared_page_state
from telemetry import story
class ToughSchedulingCasesPage(page_module.Page):
def __init__(self, url, page_set):
super(ToughSchedulingCasesPage, self).__init__(
url=url, page_set=page_set, credentials_path='data/credentials.json',
shared_page_state_class=shared_page_state.SharedMobilePageState)
self.archive_data_file = 'data/tough_scheduling_cases.json'
def RunPageInteractions(self, action_runner):
with action_runner.CreateGestureInteraction('ScrollAction'):
action_runner.ScrollPage()
class Page1(ToughSchedulingCasesPage):
"""Why: Simulate oversubscribed main thread."""
def __init__(self, page_set):
super(Page1, self).__init__(
url='file://tough_scheduling_cases/simple_text_page.html?main_busy',
page_set=page_set)
self.synthetic_delays = {'cc.BeginMainFrame': {'target_duration': 0.008}}
class Page2(ToughSchedulingCasesPage):
"""Why: Simulate oversubscribed main thread."""
def __init__(self, page_set):
super(Page2, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/simple_text_page.html?main_very_busy',
page_set=page_set)
self.synthetic_delays = {'cc.BeginMainFrame': {'target_duration': 0.024}}
class Page3(ToughSchedulingCasesPage):
"""Why: Simulate a page with a a few graphics layers."""
def __init__(self, page_set):
super(Page3, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/simple_text_page.html?medium_layers',
page_set=page_set)
self.synthetic_delays = {
'cc.DrawAndSwap': {'target_duration': 0.004},
'gpu.PresentingFrame': {'target_duration': 0.004},
'cc.BeginMainFrame': {'target_duration': 0.004}
}
class Page4(ToughSchedulingCasesPage):
"""Why: Simulate a page with many graphics layers."""
def __init__(self, page_set):
super(Page4, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/simple_text_page.html?many_layers',
page_set=page_set)
self.synthetic_delays = {
'cc.DrawAndSwap': {'target_duration': 0.012},
'gpu.PresentingFrame': {'target_duration': 0.012},
'cc.BeginMainFrame': {'target_duration': 0.012}
}
class Page5(ToughSchedulingCasesPage):
"""Why: Simulate a page with expensive recording and rasterization."""
def __init__(self, page_set):
super(Page5, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/simple_text_page.html?medium_raster',
page_set=page_set)
self.synthetic_delays = {
'cc.RasterRequiredForActivation': {'target_duration': 0.004},
'cc.BeginMainFrame': {'target_duration': 0.004},
'gpu.AsyncTexImage': {'target_duration': 0.004}
}
class Page6(ToughSchedulingCasesPage):
"""Why: Simulate a page with expensive recording and rasterization."""
def __init__(self, page_set):
super(Page6, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/simple_text_page.html?heavy_raster',
page_set=page_set)
self.synthetic_delays = {
'cc.RasterRequiredForActivation': {'target_duration': 0.024},
'cc.BeginMainFrame': {'target_duration': 0.024},
'gpu.AsyncTexImage': {'target_duration': 0.024}
}
class Page7(ToughSchedulingCasesPage):
"""Why: Medium cost touch handler."""
def __init__(self, page_set):
super(Page7, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/touch_handler_scrolling.html?medium_handler',
page_set=page_set)
self.synthetic_delays = {'blink.HandleInputEvent':
{'target_duration': 0.008}}
class Page8(ToughSchedulingCasesPage):
"""Why: Slow touch handler."""
def __init__(self, page_set):
super(Page8, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/touch_handler_scrolling.html?slow_handler',
page_set=page_set)
self.synthetic_delays = {'blink.HandleInputEvent':
{'target_duration': 0.024}}
class Page9(ToughSchedulingCasesPage):
"""Why: Touch handler that often takes a long time."""
def __init__(self, page_set):
super(Page9, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/touch_handler_scrolling.html?janky_handler',
page_set=page_set)
self.synthetic_delays = {'blink.HandleInputEvent':
{'target_duration': 0.024, 'mode': 'alternating'}
}
class Page10(ToughSchedulingCasesPage):
"""Why: Touch handler that occasionally takes a long time."""
def __init__(self, page_set):
super(Page10, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/touch_handler_scrolling.html?occasionally_janky_handler',
page_set=page_set)
self.synthetic_delays = {'blink.HandleInputEvent':
{'target_duration': 0.024, 'mode': 'oneshot'}}
class Page11(ToughSchedulingCasesPage):
"""Why: Super expensive touch handler causes browser to scroll after a
timeout."""
def __init__(self, page_set):
super(Page11, self).__init__(
# pylint: disable=line-too-long
url='file://tough_scheduling_cases/touch_handler_scrolling.html?super_slow_handler',
page_set=page_set)
self.synthetic_delays = {'blink.HandleInputEvent':
{'target_duration': 0.2}}
class Page12(ToughSchedulingCasesPage):
"""Why: Super expensive touch handler that only occupies a part of the page.
"""
def __init__(self, page_set):
super(Page12, self).__init__(
url='file://tough_scheduling_cases/div_touch_handler.html',
page_set=page_set)
self.synthetic_delays = {'blink.HandleInputEvent': {'target_duration': 0.2}}
class Page13(ToughSchedulingCasesPage):
"""Why: Test a moderately heavy requestAnimationFrame handler."""
def __init__(self, page_set):
super(Page13, self).__init__(
url='file://tough_scheduling_cases/raf.html?medium_handler',
page_set=page_set)
self.synthetic_delays = {
'cc.RasterRequiredForActivation': {'target_duration': 0.004},
'cc.BeginMainFrame': {'target_duration': 0.004},
'gpu.AsyncTexImage': {'target_duration': 0.004}
}
class Page14(ToughSchedulingCasesPage):
"""Why: Test a moderately heavy requestAnimationFrame handler."""
def __init__(self, page_set):
super(Page14, self).__init__(
url='file://tough_scheduling_cases/raf.html?heavy_handler',
page_set=page_set)
self.synthetic_delays = {
'cc.RasterRequiredForActivation': {'target_duration': 0.024},
'cc.BeginMainFrame': {'target_duration': 0.024},
'gpu.AsyncTexImage': {'target_duration': 0.024}
}
class Page15(ToughSchedulingCasesPage):
"""Why: Simulate a heavily GPU bound page."""
def __init__(self, page_set):
super(Page15, self).__init__(
url='file://tough_scheduling_cases/raf.html?gpu_bound',
page_set=page_set)
self.synthetic_delays = {'gpu.PresentingFrame': {'target_duration': 0.1}}
class Page16(ToughSchedulingCasesPage):
"""Why: Test a requestAnimationFrame handler with a heavy first frame."""
def __init__(self, page_set):
super(Page16, self).__init__(
url='file://tough_scheduling_cases/raf.html?heavy_first_frame',
page_set=page_set)
self.synthetic_delays = {'cc.BeginMainFrame': {'target_duration': 0.15,
'mode': 'oneshot'}}
class Page17(ToughSchedulingCasesPage):
"""Why: Medium stress test for the scheduler."""
def __init__(self, page_set):
super(Page17, self).__init__(
url='file://tough_scheduling_cases/raf_touch_animation.html?medium',
page_set=page_set)
self.synthetic_delays = {
'cc.DrawAndSwap': {'target_duration': 0.004},
'cc.BeginMainFrame': {'target_duration': 0.004}
}
class Page18(ToughSchedulingCasesPage):
"""Why: Heavy stress test for the scheduler."""
def __init__(self, page_set):
super(Page18, self).__init__(
url='file://tough_scheduling_cases/raf_touch_animation.html?heavy',
page_set=page_set)
self.synthetic_delays = {
'cc.DrawAndSwap': {'target_duration': 0.012},
'cc.BeginMainFrame': {'target_duration': 0.012}
}
class Page19(ToughSchedulingCasesPage):
"""Why: Both main and impl thread animating concurrently."""
def __init__(self, page_set):
super(Page19, self).__init__(
url='file://tough_scheduling_cases/split_animation.html',
page_set=page_set)
def RunPageInteractions(self, action_runner):
with action_runner.CreateInteraction('SplitAnimation'):
action_runner.Wait(3)
class Page20(ToughSchedulingCasesPage):
"""Why: Simple JS touch dragging."""
def __init__(self, page_set):
super(Page20, self).__init__(
url='file://tough_scheduling_cases/simple_touch_drag.html',
page_set=page_set)
def RunPageInteractions(self, action_runner):
with action_runner.CreateGestureInteraction('ScrollAction'):
action_runner.ScrollElement(
selector='#card',
use_touch=True,
direction='up',
speed_in_pixels_per_second=150,
distance=400)
class EmptyTouchHandlerPage(ToughSchedulingCasesPage):
"""Why: Scrolling on a page with a touch handler that consumes no events but
may be slow."""
def __init__(self, name, desktop, slow_handler, bounce, page_set):
super(EmptyTouchHandlerPage, self).__init__(
url='file://tough_scheduling_cases/empty_touch_handler' +
('_desktop' if desktop else '') + '.html?' + name,
page_set=page_set)
if slow_handler:
self.synthetic_delays = {
'blink.HandleInputEvent': {'target_duration': 0.2}
}
self.bounce = bounce
def RunPageInteractions(self, action_runner):
if self.bounce:
with action_runner.CreateGestureInteraction('ScrollBounceAction'):
action_runner.ScrollBouncePage()
else:
with action_runner.CreateGestureInteraction('ScrollAction'):
# Speed and distance are tuned to run exactly as long as a scroll
# bounce.
action_runner.ScrollPage(use_touch=True, speed_in_pixels_per_second=400,
distance=2100)
class SynchronizedScrollOffsetPage(ToughSchedulingCasesPage):
"""Why: For measuring the latency of scroll-synchronized effects."""
def __init__(self, page_set):
super(SynchronizedScrollOffsetPage, self).__init__(
url='file://tough_scheduling_cases/sync_scroll_offset.html',
page_set=page_set)
def RunPageInteractions(self, action_runner):
with action_runner.CreateGestureInteraction('ScrollBounceAction'):
action_runner.ScrollBouncePage()
class SecondBatchJsPage(ToughSchedulingCasesPage):
"""Why: For testing dynamically loading a large batch of Javascript and
running a part of it in response to user input.
"""
def __init__(self, page_set, variant='medium'):
super(SecondBatchJsPage, self).__init__(
url='file://tough_scheduling_cases/second_batch_js.html?%s' % variant,
page_set=page_set)
def RunPageInteractions(self, action_runner):
# Do a dummy tap to warm up the synthetic tap code path.
action_runner.TapElement(selector='div[id="spinner"]')
# Begin the action immediately because we want the page to update smoothly
# even while resources are being loaded.
action_runner.WaitForJavaScriptCondition2('window.__ready !== undefined')
with action_runner.CreateGestureInteraction('LoadAction'):
action_runner.ExecuteJavaScript2('kickOffLoading()')
action_runner.WaitForJavaScriptCondition2('window.__ready')
# Click one second after the resources have finished loading.
action_runner.Wait(1)
action_runner.TapElement(selector='input[id="run"]')
# Wait for the test to complete.
action_runner.WaitForJavaScriptCondition2('window.__finished')
class ToughSchedulingCasesPageSet(story.StorySet):
"""Tough scheduler latency test cases."""
def __init__(self):
super(ToughSchedulingCasesPageSet, self).__init__(
archive_data_file='data/tough_scheduling_cases.json',
cloud_storage_bucket=story.INTERNAL_BUCKET)
# Why: Simple scrolling baseline
self.AddStory(ToughSchedulingCasesPage(
'file://tough_scheduling_cases/simple_text_page.html',
self))
self.AddStory(Page1(self))
self.AddStory(Page2(self))
self.AddStory(Page3(self))
self.AddStory(Page4(self))
# Disabled until crbug.com/413829 is fixed.
# self.AddStory(Page5(self))
# Disabled because of crbug.com/413829 and flakiness crbug.com/368532
# self.AddStory(Page6(self))
# Why: Touch handler scrolling baseline
self.AddStory(ToughSchedulingCasesPage(
'file://tough_scheduling_cases/touch_handler_scrolling.html',
self))
self.AddStory(Page7(self))
self.AddStory(Page8(self))
self.AddStory(Page9(self))
self.AddStory(Page10(self))
self.AddStory(Page11(self))
self.AddStory(Page12(self))
# Why: requestAnimationFrame scrolling baseline
self.AddStory(ToughSchedulingCasesPage(
'file://tough_scheduling_cases/raf.html',
self))
# Why: Test canvas blocking behavior
self.AddStory(ToughSchedulingCasesPage(
'file://tough_scheduling_cases/raf_canvas.html',
self))
# Disabled until crbug.com/413829 is fixed.
# self.AddStory(Page13(self))
# Disabled because of crbug.com/413829 and flakiness crbug.com/368532
# self.AddStory(Page14(self))
self.AddStory(Page15(self))
self.AddStory(Page16(self))
# Why: Test a requestAnimationFrame handler with concurrent CSS animation
self.AddStory(ToughSchedulingCasesPage(
'file://tough_scheduling_cases/raf_animation.html',
self))
# Why: Stress test for the scheduler
self.AddStory(ToughSchedulingCasesPage(
'file://tough_scheduling_cases/raf_touch_animation.html',
self))
self.AddStory(Page17(self))
self.AddStory(Page18(self))
self.AddStory(Page19(self))
self.AddStory(Page20(self))
# Why: Baseline for scrolling in the presence of a no-op touch handler
self.AddStory(EmptyTouchHandlerPage(
name='baseline',
desktop=False,
slow_handler=False,
bounce=False,
page_set=self))
# Why: Slow handler blocks scroll start
self.AddStory(EmptyTouchHandlerPage(
name='slow_handler',
desktop=False,
slow_handler=True,
bounce=False,
page_set=self))
# Why: Slow handler blocks scroll start until touch ACK timeout
self.AddStory(EmptyTouchHandlerPage(
name='desktop_slow_handler',
desktop=True,
slow_handler=True,
bounce=False,
page_set=self))
# Why: Scroll bounce showing repeated transitions between scrolling and
# sending synchronous touchmove events. Should be nearly as fast as
# scroll baseline.
self.AddStory(EmptyTouchHandlerPage(
name='bounce',
desktop=False,
slow_handler=False,
bounce=True,
page_set=self))
# Why: Scroll bounce with slow handler, repeated blocking.
self.AddStory(EmptyTouchHandlerPage(
name='bounce_slow_handler',
desktop=False,
slow_handler=True,
bounce=True,
page_set=self))
# Why: Scroll bounce with slow handler on desktop, blocks only once until
# ACK timeout.
self.AddStory(EmptyTouchHandlerPage(
name='bounce_desktop_slow_handler',
desktop=True,
slow_handler=True,
bounce=True,
page_set=self))
# Why: For measuring the latency of scroll-synchronized effects.
self.AddStory(SynchronizedScrollOffsetPage(page_set=self))
# Why: Test loading a large amount of Javascript.
self.AddStory(SecondBatchJsPage(page_set=self, variant='light'))
self.AddStory(SecondBatchJsPage(page_set=self, variant='medium'))
self.AddStory(SecondBatchJsPage(page_set=self, variant='heavy'))