blob: fc2b6f82fe36699ff6153893456c90f8d2870711 [file] [log] [blame]
# Copyright 2013 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.
import os
from core import path_util
from core import perf_benchmark
from telemetry import benchmark
from telemetry import page as page_module
from telemetry.page import legacy_page_test
from telemetry.page import shared_page_state
from telemetry import story
from telemetry.value import list_of_scalar_values
from telemetry.value import scalar
from benchmarks import pywebsocket_server
from measurements import timeline_controller
from page_sets import webgl_supported_shared_state
BLINK_PERF_BASE_DIR = os.path.join(path_util.GetChromiumSrcDir(),
'third_party', 'WebKit', 'PerformanceTests')
SKIPPED_FILE = os.path.join(BLINK_PERF_BASE_DIR, 'Skipped')
def CreateStorySetFromPath(path, skipped_file,
shared_page_state_class=(
shared_page_state.SharedPageState)):
assert os.path.exists(path)
page_urls = []
serving_dirs = set()
def _AddPage(path):
if not path.endswith('.html'):
return
if '../' in open(path, 'r').read():
# If the page looks like it references its parent dir, include it.
serving_dirs.add(os.path.dirname(os.path.dirname(path)))
page_urls.append('file://' + path.replace('\\', '/'))
def _AddDir(dir_path, skipped):
for candidate_path in os.listdir(dir_path):
if candidate_path == 'resources':
continue
candidate_path = os.path.join(dir_path, candidate_path)
if candidate_path.startswith(skipped):
continue
if os.path.isdir(candidate_path):
_AddDir(candidate_path, skipped)
else:
_AddPage(candidate_path)
if os.path.isdir(path):
skipped = []
if os.path.exists(skipped_file):
for line in open(skipped_file, 'r').readlines():
line = line.strip()
if line and not line.startswith('#'):
skipped_path = os.path.join(os.path.dirname(skipped_file), line)
skipped.append(skipped_path.replace('/', os.sep))
_AddDir(path, tuple(skipped))
else:
_AddPage(path)
ps = story.StorySet(base_dir=os.getcwd() + os.sep,
serving_dirs=serving_dirs)
for url in page_urls:
ps.AddStory(page_module.Page(
url, ps, ps.base_dir,
shared_page_state_class=shared_page_state_class))
return ps
class _BlinkPerfMeasurement(legacy_page_test.LegacyPageTest):
"""Tuns a blink performance test and reports the results."""
def __init__(self):
super(_BlinkPerfMeasurement, self).__init__()
with open(os.path.join(os.path.dirname(__file__),
'blink_perf.js'), 'r') as f:
self._blink_perf_js = f.read()
def WillNavigateToPage(self, page, tab):
del tab # unused
page.script_to_evaluate_on_commit = self._blink_perf_js
def CustomizeBrowserOptions(self, options):
options.AppendExtraBrowserArgs([
'--js-flags=--expose_gc',
'--enable-experimental-web-platform-features',
'--disable-gesture-requirement-for-media-playback',
'--enable-experimental-canvas-features',
# TODO(qinmin): After fixing crbug.com/592017, remove this command line.
'--reduce-security-for-testing'
])
if 'content-shell' in options.browser_type:
options.AppendExtraBrowserArgs('--expose-internals-for-testing')
def ValidateAndMeasurePage(self, page, tab, results):
tab.WaitForJavaScriptCondition('testRunner.isDone', timeout=600)
log = tab.EvaluateJavaScript('document.getElementById("log").innerHTML')
for line in log.splitlines():
if line.startswith("FATAL: "):
print line
continue
if not line.startswith('values '):
continue
parts = line.split()
values = [float(v.replace(',', '')) for v in parts[1:-1]]
units = parts[-1]
metric = page.display_name.split('.')[0].replace('/', '_')
results.AddValue(list_of_scalar_values.ListOfScalarValues(
results.current_page, metric, units, values))
break
print log
# TODO(wangxianzhu): Convert the paint benchmarks to use the new blink_perf
# tracing once it's ready.
class _BlinkPerfPaintMeasurement(_BlinkPerfMeasurement):
"""Also collects prePaint and paint timing from traces."""
def __init__(self):
super(_BlinkPerfPaintMeasurement, self).__init__()
self._controller = None
def WillNavigateToPage(self, page, tab):
super(_BlinkPerfPaintMeasurement, self).WillNavigateToPage(page, tab)
self._controller = timeline_controller.TimelineController()
self._controller.trace_categories = 'blink,blink.console'
self._controller.SetUp(page, tab)
self._controller.Start(tab)
def DidRunPage(self, platform):
if self._controller:
self._controller.CleanUp(platform)
def ValidateAndMeasurePage(self, page, tab, results):
super(_BlinkPerfPaintMeasurement, self).ValidateAndMeasurePage(
page, tab, results)
self._controller.Stop(tab, results)
renderer = self._controller.model.GetRendererThreadFromTabId(tab.id)
# The marker marks the beginning and ending of the measured runs.
marker = next(event for event in renderer.async_slices
if event.name == 'blink_perf'
and event.category == 'blink.console')
assert marker
for event in renderer.all_slices:
if event.start < marker.start or event.end > marker.end:
continue
if event.name == 'FrameView::prePaint':
results.AddValue(
scalar.ScalarValue(page, 'prePaint', 'ms', event.duration))
if event.name == 'FrameView::paintTree':
results.AddValue(
scalar.ScalarValue(page, 'paint', 'ms', event.duration))
class _BlinkPerfBenchmark(perf_benchmark.PerfBenchmark):
test = _BlinkPerfMeasurement
@classmethod
def Name(cls):
return 'blink_perf.' + cls.tag
def CreateStorySet(self, options):
path = os.path.join(BLINK_PERF_BASE_DIR, self.subdir)
return CreateStorySetFromPath(path, SKIPPED_FILE)
class _SharedPywebsocketPageState(shared_page_state.SharedPageState):
"""Runs a pywebsocket server."""
def __init__(self, test, finder_options, user_story_set):
super(_SharedPywebsocketPageState, self).__init__(
test, finder_options, user_story_set)
self.platform.StartLocalServer(pywebsocket_server.PywebsocketServer())
@benchmark.Owner(emails=['yukishiino@chromium.org',
'bashi@chromium.org',
'haraken@chromium.org'])
class BlinkPerfBindings(_BlinkPerfBenchmark):
tag = 'bindings'
subdir = 'Bindings'
@classmethod
def ShouldDisable(cls, possible_browser):
# http://crbug.com/563979
return (cls.IsSvelte(possible_browser)
# http://crbug.com/653970
or (possible_browser.browser_type == 'reference' and
possible_browser.platform.GetOSName() == 'android'))
@benchmark.Enabled('content-shell')
class BlinkPerfBlinkGC(_BlinkPerfBenchmark):
tag = 'blink_gc'
subdir = 'BlinkGC'
@benchmark.Owner(emails=['rune@opera.com'])
class BlinkPerfCSS(_BlinkPerfBenchmark):
tag = 'css'
subdir = 'CSS'
@benchmark.Disabled('android', # http://crbug.com/685320
'android-webview', # http://crbug.com/593200
'reference') # http://crbug.com/576779
@benchmark.Owner(emails=['junov@chromium.org'])
class BlinkPerfCanvas(_BlinkPerfBenchmark):
tag = 'canvas'
subdir = 'Canvas'
@classmethod
def ShouldDisable(cls, possible_browser):
return cls.IsSvelte(possible_browser) # http://crbug.com/593973.
def CreateStorySet(self, options):
path = os.path.join(BLINK_PERF_BASE_DIR, self.subdir)
story_set = CreateStorySetFromPath(
path, SKIPPED_FILE,
shared_page_state_class=(
webgl_supported_shared_state.WebGLSupportedSharedState))
# WebGLSupportedSharedState requires the skipped_gpus property to
# be set on each page.
for page in story_set:
page.skipped_gpus = []
return story_set
@benchmark.Owner(emails=['yukishiino@chromium.org',
'bashi@chromium.org',
'haraken@chromium.org'])
class BlinkPerfDOM(_BlinkPerfBenchmark):
tag = 'dom'
subdir = 'DOM'
@benchmark.Owner(emails=['hayato@chromium.org'])
class BlinkPerfEvents(_BlinkPerfBenchmark):
tag = 'events'
subdir = 'Events'
@benchmark.Disabled('win8') # http://crbug.com/462350
@benchmark.Owner(emails=['eae@chromium.org'])
class BlinkPerfLayout(_BlinkPerfBenchmark):
tag = 'layout'
subdir = 'Layout'
@classmethod
def ShouldDisable(cls, possible_browser):
return cls.IsSvelte(possible_browser) # http://crbug.com/551950
@benchmark.Owner(emails=['wangxianzhu@chromium.org'])
class BlinkPerfPaint(_BlinkPerfBenchmark):
test = _BlinkPerfPaintMeasurement
tag = 'paint'
subdir = 'Paint'
@classmethod
def ShouldDisable(cls, possible_browser):
return cls.IsSvelte(possible_browser) # http://crbug.com/574483
@benchmark.Disabled('win') # crbug.com/488493
@benchmark.Owner(emails=['yukishiino@chromium.org',
'bashi@chromium.org',
'haraken@chromium.org'])
class BlinkPerfParser(_BlinkPerfBenchmark):
tag = 'parser'
subdir = 'Parser'
@benchmark.Owner(emails=['kouhei@chromium.org', 'fs@opera.com'])
class BlinkPerfSVG(_BlinkPerfBenchmark):
tag = 'svg'
subdir = 'SVG'
@benchmark.Owner(emails=['hayato@chromium.org'])
class BlinkPerfShadowDOM(_BlinkPerfBenchmark):
tag = 'shadow_dom'
subdir = 'ShadowDOM'
@classmethod
def ShouldDisable(cls, possible_browser): # http://crbug.com/702319
return possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X'
# This benchmark is for local testing, doesn't need to run on bots.
@benchmark.Disabled('all')
@benchmark.Owner(emails=['tyoshino@chromium.org', 'hiroshige@chromium.org'])
class BlinkPerfXMLHttpRequest(_BlinkPerfBenchmark):
tag = 'xml_http_request'
subdir = 'XMLHttpRequest'
# Disabled on Windows and ChromeOS due to https://crbug.com/521887
#@benchmark.Disabled('win', 'chromeos')
# Disabling on remaining platforms due to heavy flake https://crbug.com/646938
@benchmark.Disabled('all')
@benchmark.Owner(emails=['tyoshino@chromium.org', 'yhirano@chromium.org'])
class BlinkPerfPywebsocket(_BlinkPerfBenchmark):
"""The blink_perf.pywebsocket tests measure turn-around-time of 10MB
send/receive for XHR, Fetch API and WebSocket. We might ignore < 10%
regressions, because the tests are noisy and such regressions are
often unreproducible (https://crbug.com/549017).
"""
tag = 'pywebsocket'
subdir = 'Pywebsocket'
def CreateStorySet(self, options):
path = os.path.join(BLINK_PERF_BASE_DIR, self.subdir)
return CreateStorySetFromPath(
path, SKIPPED_FILE,
shared_page_state_class=_SharedPywebsocketPageState)
@classmethod
def ShouldDisable(cls, possible_browser):
return cls.IsSvelte(possible_browser) # http://crbug.com/551950