Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / tools / perf / measurements / page_cycler.py
blob1f9f63f03b3c471f8069b64efdf832f165e0948e
1 # Copyright 2012 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.
5 """The page cycler measurement.
7 This measurement registers a window load handler in which is forces a layout and
8 then records the value of performance.now(). This call to now() measures the
9 time from navigationStart (immediately after the previous page's beforeunload
10 event) until after the layout in the page's load event. In addition, two garbage
11 collections are performed in between the page loads (in the beforeunload event).
12 This extra garbage collection time is not included in the measurement times.
14 Finally, various memory and IO statistics are gathered at the very end of
15 cycling all pages.
16 """
18 import collections
19 import os
21 from metrics import cpu
22 from metrics import iometric
23 from metrics import memory
24 from metrics import power
25 from metrics import speedindex
26 from metrics import v8_object_stats
27 from telemetry.core import util
28 from telemetry.page import page_test
29 from telemetry.value import scalar
32 class PageCycler(page_test.PageTest):
33 def __init__(self, page_repeat, pageset_repeat, cold_load_percent=50,
34 record_v8_object_stats=False, report_speed_index=False,
35 clear_cache_before_each_run=False):
36 super(PageCycler, self).__init__(
37 clear_cache_before_each_run=clear_cache_before_each_run)
39 with open(os.path.join(os.path.dirname(__file__),
40 'page_cycler.js'), 'r') as f:
41 self._page_cycler_js = f.read()
43 self._record_v8_object_stats = record_v8_object_stats
44 self._report_speed_index = report_speed_index
45 self._speedindex_metric = speedindex.SpeedIndexMetric()
46 self._memory_metric = None
47 self._power_metric = None
48 self._cpu_metric = None
49 self._v8_object_stats_metric = None
50 self._has_loaded_page = collections.defaultdict(int)
51 self._initial_renderer_url = None # to avoid cross-renderer navigation
53 cold_runs_percent_set = (cold_load_percent != None)
54 # Handle requests for cold cache runs
55 if (cold_runs_percent_set and
56 (cold_load_percent < 0 or cold_load_percent > 100)):
57 raise Exception('cold-load-percent must be in the range [0-100]')
59 # Make sure _cold_run_start_index is an integer multiple of page_repeat.
60 # Without this, --pageset_shuffle + --page_repeat could lead to
61 # assertion failures on _started_warm in WillNavigateToPage.
62 if cold_runs_percent_set:
63 number_warm_pageset_runs = int(
64 (int(pageset_repeat) - 1) * (100 - cold_load_percent) / 100)
65 number_warm_runs = number_warm_pageset_runs * page_repeat
66 self._cold_run_start_index = number_warm_runs + page_repeat
67 self._discard_first_result = (not cold_load_percent or
68 self._discard_first_result)
69 else:
70 self._cold_run_start_index = pageset_repeat * page_repeat
72 def WillStartBrowser(self, platform):
73 """Initialize metrics once right before the browser has been launched."""
74 self._power_metric = power.PowerMetric(platform)
76 def DidStartBrowser(self, browser):
77 """Initialize metrics once right after the browser has been launched."""
78 self._memory_metric = memory.MemoryMetric(browser)
79 self._cpu_metric = cpu.CpuMetric(browser)
80 if self._record_v8_object_stats:
81 self._v8_object_stats_metric = v8_object_stats.V8ObjectStatsMetric()
83 def WillNavigateToPage(self, page, tab):
84 if page.is_file:
85 # For legacy page cyclers which use the filesystem, do an initial
86 # navigate to avoid paying for a cross-renderer navigation.
87 initial_url = tab.browser.http_server.UrlOf('nonexistent.html')
88 if self._initial_renderer_url != initial_url:
89 self._initial_renderer_url = initial_url
90 tab.Navigate(self._initial_renderer_url)
92 page.script_to_evaluate_on_commit = self._page_cycler_js
93 if self.ShouldRunCold(page.url):
94 tab.ClearCache(force=True)
95 if self._report_speed_index:
96 self._speedindex_metric.Start(page, tab)
97 self._cpu_metric.Start(page, tab)
98 self._power_metric.Start(page, tab)
100 def DidNavigateToPage(self, page, tab):
101 self._memory_metric.Start(page, tab)
102 if self._record_v8_object_stats:
103 self._v8_object_stats_metric.Start(page, tab)
105 def CustomizeBrowserOptions(self, options):
106 memory.MemoryMetric.CustomizeBrowserOptions(options)
107 power.PowerMetric.CustomizeBrowserOptions(options)
108 iometric.IOMetric.CustomizeBrowserOptions(options)
109 options.AppendExtraBrowserArgs('--js-flags=--expose_gc')
111 if self._record_v8_object_stats:
112 v8_object_stats.V8ObjectStatsMetric.CustomizeBrowserOptions(options)
113 if self._report_speed_index:
114 self._speedindex_metric.CustomizeBrowserOptions(options)
116 def ValidateAndMeasurePage(self, page, tab, results):
117 tab.WaitForJavaScriptExpression('__pc_load_time', 60)
119 chart_name_prefix = ('cold_' if self.IsRunCold(page.url) else
120 'warm_')
122 results.AddValue(scalar.ScalarValue(
123 results.current_page, '%stimes.page_load_time' % chart_name_prefix,
124 'ms', tab.EvaluateJavaScript('__pc_load_time'),
125 description='Average page load time. Measured from '
126 'performance.timing.navigationStart until the completion '
127 'time of a layout after the window.load event. Cold times '
128 'are the times when the page is loaded cold, i.e. without '
129 'loading it before, and warm times are times when the '
130 'page is loaded after being loaded previously.'))
132 self._has_loaded_page[page.url] += 1
134 self._power_metric.Stop(page, tab)
135 self._memory_metric.Stop(page, tab)
136 self._memory_metric.AddResults(tab, results)
137 self._power_metric.AddResults(tab, results)
139 self._cpu_metric.Stop(page, tab)
140 self._cpu_metric.AddResults(tab, results)
141 if self._record_v8_object_stats:
142 self._v8_object_stats_metric.Stop(page, tab)
143 self._v8_object_stats_metric.AddResults(tab, results)
145 if self._report_speed_index:
146 def SpeedIndexIsFinished():
147 return self._speedindex_metric.IsFinished(tab)
148 util.WaitFor(SpeedIndexIsFinished, 60)
149 self._speedindex_metric.Stop(page, tab)
150 self._speedindex_metric.AddResults(
151 tab, results, chart_name=chart_name_prefix+'speed_index')
153 def DidRunTest(self, browser, results):
154 iometric.IOMetric().AddSummaryResults(browser, results)
156 def IsRunCold(self, url):
157 return (self.ShouldRunCold(url) or
158 self._has_loaded_page[url] == 0)
160 def ShouldRunCold(self, url):
161 # We do the warm runs first for two reasons. The first is so we can
162 # preserve any initial profile cache for as long as possible.
163 # The second is that, if we did cold runs first, we'd have a transition
164 # page set during which we wanted the run for each URL to both
165 # contribute to the cold data and warm the catch for the following
166 # warm run, and clearing the cache before the load of the following
167 # URL would eliminate the intended warmup for the previous URL.
168 return (self._has_loaded_page[url] >= self._cold_run_start_index)