-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Copyright 2012 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 collections
import os
-import sys
from metrics import cpu
-from metrics import io
+from metrics import iometric
from metrics import memory
+from metrics import power
from metrics import speedindex
from metrics import v8_object_stats
from telemetry.core import util
-from telemetry.page import page_measurement
+from telemetry.page import page_test
+from telemetry.value import scalar
+
+
+class PageCycler(page_test.PageTest):
+ options = {'pageset_repeat': 10}
-class PageCycler(page_measurement.PageMeasurement):
def __init__(self, *args, **kwargs):
super(PageCycler, self).__init__(*args, **kwargs)
'page_cycler.js'), 'r') as f:
self._page_cycler_js = f.read()
- self._record_v8_object_stats = False
- self._report_speed_index = False
self._speedindex_metric = speedindex.SpeedIndexMetric()
self._memory_metric = None
+ self._power_metric = None
self._cpu_metric = None
self._v8_object_stats_metric = None
- self._number_warm_runs = None
- self._cold_runs_requested = False
- self._cold_run_start_index = None
self._has_loaded_page = collections.defaultdict(int)
+ self._initial_renderer_url = None # to avoid cross-renderer navigation
- def AddCommandLineOptions(self, parser):
- # The page cyclers should default to 10 iterations. In order to change the
- # default of an option, we must remove and re-add it.
- # TODO: Remove this after transition to run_benchmark.
- pageset_repeat_option = parser.get_option('--pageset-repeat')
- pageset_repeat_option.default = 10
- parser.remove_option('--pageset-repeat')
- parser.add_option(pageset_repeat_option)
-
+ @classmethod
+ def AddCommandLineArgs(cls, parser):
parser.add_option('--v8-object-stats',
action='store_true',
help='Enable detailed V8 object statistics.')
action='store_true',
help='Enable the speed index metric.')
- parser.add_option('--cold-load-percent', type='int',
+ parser.add_option('--cold-load-percent', type='int', default=50,
help='%d of page visits for which a cold load is forced')
+ @classmethod
+ def ProcessCommandLineArgs(cls, parser, args):
+ cls._record_v8_object_stats = args.v8_object_stats
+ cls._report_speed_index = args.report_speed_index
+
+ cold_runs_percent_set = (args.cold_load_percent != None)
+ # Handle requests for cold cache runs
+ if (cold_runs_percent_set and
+ (args.cold_load_percent < 0 or args.cold_load_percent > 100)):
+ raise Exception('--cold-load-percent must be in the range [0-100]')
+
+ # Make sure _cold_run_start_index is an integer multiple of page_repeat.
+ # Without this, --pageset_shuffle + --page_repeat could lead to
+ # assertion failures on _started_warm in WillNavigateToPage.
+ if cold_runs_percent_set:
+ number_warm_pageset_runs = int(
+ (int(args.pageset_repeat) - 1) * (100 - args.cold_load_percent) / 100)
+ number_warm_runs = number_warm_pageset_runs * args.page_repeat
+ cls._cold_run_start_index = number_warm_runs + args.page_repeat
+ cls.discard_first_result = (not args.cold_load_percent or
+ cls.discard_first_result)
+ else:
+ cls._cold_run_start_index = args.pageset_repeat * args.page_repeat
+
+ def WillStartBrowser(self, platform):
+ """Initialize metrics once right before the browser has been launched."""
+ self._power_metric = power.PowerMetric(platform)
+
def DidStartBrowser(self, browser):
"""Initialize metrics once right after the browser has been launched."""
self._memory_metric = memory.MemoryMetric(browser)
if self._record_v8_object_stats:
self._v8_object_stats_metric = v8_object_stats.V8ObjectStatsMetric()
- def DidStartHTTPServer(self, tab):
- # Avoid paying for a cross-renderer navigation on the first page on legacy
- # page cyclers which use the filesystem.
- tab.Navigate(tab.browser.http_server.UrlOf('nonexistent.html'))
-
def WillNavigateToPage(self, page, tab):
+ if page.is_file:
+ # For legacy page cyclers which use the filesystem, do an initial
+ # navigate to avoid paying for a cross-renderer navigation.
+ initial_url = tab.browser.http_server.UrlOf('nonexistent.html')
+ if self._initial_renderer_url != initial_url:
+ self._initial_renderer_url = initial_url
+ tab.Navigate(self._initial_renderer_url)
+
page.script_to_evaluate_on_commit = self._page_cycler_js
if self.ShouldRunCold(page.url):
- tab.ClearCache()
+ tab.ClearCache(force=True)
if self._report_speed_index:
self._speedindex_metric.Start(page, tab)
+ self._cpu_metric.Start(page, tab)
+ self._power_metric.Start(page, tab)
def DidNavigateToPage(self, page, tab):
self._memory_metric.Start(page, tab)
- # TODO(qyearsley): Uncomment the following line and move it to
- # WillNavigateToPage once the cpu metric has been changed.
- # This is being temporarily commented out to let the page cycler
- # results return to how they were before the cpu metric was added.
- # self._cpu_metric.Start(page, tab) See crbug.com/301714.
if self._record_v8_object_stats:
self._v8_object_stats_metric.Start(page, tab)
def CustomizeBrowserOptions(self, options):
memory.MemoryMetric.CustomizeBrowserOptions(options)
- io.IOMetric.CustomizeBrowserOptions(options)
+ power.PowerMetric.CustomizeBrowserOptions(options)
+ iometric.IOMetric.CustomizeBrowserOptions(options)
options.AppendExtraBrowserArgs('--js-flags=--expose_gc')
- if options.v8_object_stats:
- self._record_v8_object_stats = True
+ if self._record_v8_object_stats:
v8_object_stats.V8ObjectStatsMetric.CustomizeBrowserOptions(options)
+ if self._report_speed_index:
+ self._speedindex_metric.CustomizeBrowserOptions(options)
- if options.report_speed_index:
- self._report_speed_index = True
-
- # A disk cache bug causes some page cyclers to hang on mac.
- # TODO(tonyg): Re-enable these tests when crbug.com/268646 is fixed.
- if (sys.platform == 'darwin' and
- (sys.argv[-1].endswith('/intl_hi_ru.json') or
- sys.argv[-1].endswith('/tough_layout_cases.json') or
- sys.argv[-1].endswith('/typical_25.json'))):
- print '%s is currently disabled on mac. Skipping test.' % sys.argv[-1]
- sys.exit(0)
-
- self._cold_runs_requested = (options.cold_load_percent != None)
- # Handle requests for cold cache runs
- if (self._cold_runs_requested and
- (options.repeat_options.page_repeat_secs or
- options.repeat_options.pageset_repeat_secs)):
- raise Exception('--cold-load-percent is incompatible with timed repeat')
-
- if (self._cold_runs_requested and
- (options.cold_load_percent < 0 or options.cold_load_percent > 100)):
- raise Exception('--cold-load-percent must be in the range [0-100]')
-
- # TODO(rdsmith): Properly handle interaction of page_repeat with
- # dropping the first run.
- number_warm_pageset_runs = int(
- (int(options.repeat_options.pageset_repeat_iters) - 1) *
- (100 - int(options.cold_load_percent or 0)) / 100)
-
- # Make sure _number_cold_runs is an integer multiple of page_repeat.
- # Without this, --pageset_shuffle + --page_repeat could lead to
- # assertion failures on _started_warm in WillNavigateToPage.
- self._number_warm_runs = (number_warm_pageset_runs *
- options.repeat_options.page_repeat_iters)
- self._cold_run_start_index = (self._number_warm_runs +
- options.repeat_options.page_repeat_iters)
- self.discard_first_result = ((self._cold_runs_requested and
- not options.cold_load_percent) or
- self.discard_first_result)
-
- def MeasurePage(self, page, tab, results):
+ def ValidateAndMeasurePage(self, page, tab, results):
tab.WaitForJavaScriptExpression('__pc_load_time', 60)
- chart_name_prefix = ('' if not self._cold_runs_requested else
- 'cold_' if self.IsRunCold(page.url) else
+ chart_name_prefix = ('cold_' if self.IsRunCold(page.url) else
'warm_')
- results.Add('page_load_time', 'ms',
- int(float(tab.EvaluateJavaScript('__pc_load_time'))),
- chart_name=chart_name_prefix+'times')
+ results.AddValue(scalar.ScalarValue(
+ results.current_page, '%stimes.page_load_time' % chart_name_prefix,
+ 'ms', tab.EvaluateJavaScript('__pc_load_time'),
+ description='Average page load time. Measured from '
+ 'performance.timing.navigationStart until the completion '
+ 'time of a layout after the window.load event. Cold times '
+ 'are the times when the page is loaded cold, i.e. without '
+ 'loading it before, and warm times are times when the '
+ 'page is loaded after being loaded previously.'))
self._has_loaded_page[page.url] += 1
+ self._power_metric.Stop(page, tab)
self._memory_metric.Stop(page, tab)
self._memory_metric.AddResults(tab, results)
- # TODO(qyearsley): Uncomment the following line when CPU metric is
- # changed. See crbug.com/301714.
- # self._cpu_metric.Stop(page, tab)
- # self._cpu_metric.AddResults(tab, results)
+ self._power_metric.AddResults(tab, results)
+
+ self._cpu_metric.Stop(page, tab)
+ self._cpu_metric.AddResults(tab, results)
if self._record_v8_object_stats:
self._v8_object_stats_metric.Stop(page, tab)
self._v8_object_stats_metric.AddResults(tab, results)
tab, results, chart_name=chart_name_prefix+'speed_index')
def DidRunTest(self, browser, results):
- self._memory_metric.AddSummaryResults(results)
- io.IOMetric().AddSummaryResults(browser, results)
+ iometric.IOMetric().AddSummaryResults(browser, results)
def IsRunCold(self, url):
return (self.ShouldRunCold(url) or
- (self._cold_runs_requested and
- self._has_loaded_page[url] == 0))
+ self._has_loaded_page[url] == 0)
def ShouldRunCold(self, url):
# We do the warm runs first for two reasons. The first is so we can
# contribute to the cold data and warm the catch for the following
# warm run, and clearing the cache before the load of the following
# URL would eliminate the intended warmup for the previous URL.
- return (self._cold_runs_requested and
- self._has_loaded_page[url] >= self._cold_run_start_index)
-
- def results_are_the_same_on_every_page(self):
- return not self._cold_runs_requested
+ return (self._has_loaded_page[url] >= self._cold_run_start_index)