Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / perf / measurements / page_cycler.py
1 # Copyright (c) 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.
4
5 """The page cycler measurement.
6
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.
13
14 Finally, various memory and IO statistics are gathered at the very end of
15 cycling all pages.
16 """
17
18 import collections
19 import os
20
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_measurement
29
30 class PageCycler(page_measurement.PageMeasurement):
31   options = {'pageset_repeat': 10}
32
33   def __init__(self, *args, **kwargs):
34     super(PageCycler, self).__init__(*args, **kwargs)
35
36     with open(os.path.join(os.path.dirname(__file__),
37                            'page_cycler.js'), 'r') as f:
38       self._page_cycler_js = f.read()
39
40     self._speedindex_metric = speedindex.SpeedIndexMetric()
41     self._memory_metric = None
42     self._power_metric = power.PowerMetric()
43     self._cpu_metric = None
44     self._v8_object_stats_metric = None
45     self._cold_run_start_index = None
46     self._has_loaded_page = collections.defaultdict(int)
47
48   @classmethod
49   def AddCommandLineArgs(cls, parser):
50     parser.add_option('--v8-object-stats',
51         action='store_true',
52         help='Enable detailed V8 object statistics.')
53
54     parser.add_option('--report-speed-index',
55         action='store_true',
56         help='Enable the speed index metric.')
57
58     parser.add_option('--cold-load-percent', type='int', default=50,
59                       help='%d of page visits for which a cold load is forced')
60
61   @classmethod
62   def ProcessCommandLineArgs(cls, parser, args):
63     cls._record_v8_object_stats = args.v8_object_stats
64     cls._report_speed_index = args.report_speed_index
65
66   def DidStartBrowser(self, browser):
67     """Initialize metrics once right after the browser has been launched."""
68     self._memory_metric = memory.MemoryMetric(browser)
69     self._cpu_metric = cpu.CpuMetric(browser)
70     if self._record_v8_object_stats:
71       self._v8_object_stats_metric = v8_object_stats.V8ObjectStatsMetric()
72
73   def DidStartHTTPServer(self, tab):
74     # Avoid paying for a cross-renderer navigation on the first page on legacy
75     # page cyclers which use the filesystem.
76     tab.Navigate(tab.browser.http_server.UrlOf('nonexistent.html'))
77
78   def WillNavigateToPage(self, page, tab):
79     page.script_to_evaluate_on_commit = self._page_cycler_js
80     if self.ShouldRunCold(page.url):
81       tab.ClearCache(force=True)
82     if self._report_speed_index:
83       self._speedindex_metric.Start(page, tab)
84     self._cpu_metric.Start(page, tab)
85
86   def DidNavigateToPage(self, page, tab):
87     self._memory_metric.Start(page, tab)
88     self._power_metric.Start(page, tab)
89     if self._record_v8_object_stats:
90       self._v8_object_stats_metric.Start(page, tab)
91
92   def CustomizeBrowserOptions(self, options):
93     memory.MemoryMetric.CustomizeBrowserOptions(options)
94     power.PowerMetric.CustomizeBrowserOptions(options)
95     iometric.IOMetric.CustomizeBrowserOptions(options)
96     options.AppendExtraBrowserArgs('--js-flags=--expose_gc')
97
98     if self._record_v8_object_stats:
99       v8_object_stats.V8ObjectStatsMetric.CustomizeBrowserOptions(options)
100     if self._report_speed_index:
101       self._speedindex_metric.CustomizeBrowserOptions(options)
102
103     # TODO: Move the rest of this method to ProcessCommandLineArgs.
104     cold_runs_percent_set = (options.cold_load_percent != None)
105     # Handle requests for cold cache runs
106     if (cold_runs_percent_set and
107         (options.cold_load_percent < 0 or options.cold_load_percent > 100)):
108       raise Exception('--cold-load-percent must be in the range [0-100]')
109
110     # Make sure _cold_run_start_index is an integer multiple of page_repeat.
111     # Without this, --pageset_shuffle + --page_repeat could lead to
112     # assertion failures on _started_warm in WillNavigateToPage.
113     if cold_runs_percent_set:
114       number_warm_pageset_runs = int(
115           (int(options.pageset_repeat) - 1) *
116           (100 - options.cold_load_percent) / 100)
117       number_warm_runs = number_warm_pageset_runs * options.page_repeat
118       self._cold_run_start_index = number_warm_runs + options.page_repeat
119       self.discard_first_result = (not options.cold_load_percent or
120                                    self.discard_first_result)
121     else:
122       self._cold_run_start_index = options.pageset_repeat * options.page_repeat
123
124   def MeasurePage(self, page, tab, results):
125     tab.WaitForJavaScriptExpression('__pc_load_time', 60)
126
127     chart_name_prefix = ('cold_' if self.IsRunCold(page.url) else
128                          'warm_')
129
130     results.Add('page_load_time', 'ms',
131                 int(float(tab.EvaluateJavaScript('__pc_load_time'))),
132                 chart_name=chart_name_prefix+'times')
133
134     self._has_loaded_page[page.url] += 1
135
136     self._power_metric.Stop(page, tab)
137     self._memory_metric.Stop(page, tab)
138     self._memory_metric.AddResults(tab, results)
139     self._power_metric.AddResults(tab, results)
140
141     self._cpu_metric.Stop(page, tab)
142     self._cpu_metric.AddResults(tab, results)
143     if self._record_v8_object_stats:
144       self._v8_object_stats_metric.Stop(page, tab)
145       self._v8_object_stats_metric.AddResults(tab, results)
146
147     if self._report_speed_index:
148       def SpeedIndexIsFinished():
149         return self._speedindex_metric.IsFinished(tab)
150       util.WaitFor(SpeedIndexIsFinished, 60)
151       self._speedindex_metric.Stop(page, tab)
152       self._speedindex_metric.AddResults(
153           tab, results, chart_name=chart_name_prefix+'speed_index')
154
155   def DidRunTest(self, browser, results):
156     iometric.IOMetric().AddSummaryResults(browser, results)
157
158   def IsRunCold(self, url):
159     return (self.ShouldRunCold(url) or
160             self._has_loaded_page[url] == 0)
161
162   def ShouldRunCold(self, url):
163     # We do the warm runs first for two reasons.  The first is so we can
164     # preserve any initial profile cache for as long as possible.
165     # The second is that, if we did cold runs first, we'd have a transition
166     # page set during which we wanted the run for each URL to both
167     # contribute to the cold data and warm the catch for the following
168     # warm run, and clearing the cache before the load of the following
169     # URL would eliminate the intended warmup for the previous URL.
170     return (self._has_loaded_page[url] >= self._cold_run_start_index)
171
172   def results_are_the_same_on_every_page(self):
173     return False