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 7This measurement registers a window load handler in which is forces a layout and 8then records the value of performance.now(). This call to now() measures the 9time from navigationStart (immediately after the previous page's beforeunload 10event) until after the layout in the page's load event. In addition, two garbage 11collections are performed in between the page loads (in the beforeunload event). 12This extra garbage collection time is not included in the measurement times. 13 14Finally, various memory and IO statistics are gathered at the very end of 15cycling all pages. 16""" 17 18import os 19import sys 20 21from metrics import histogram 22from metrics import memory 23from telemetry.core import util 24from telemetry.page import page_measurement 25 26 27MEMORY_HISTOGRAMS = [ 28 {'name': 'V8.MemoryExternalFragmentationTotal', 'units': 'percent'}, 29 {'name': 'V8.MemoryHeapSampleTotalCommitted', 'units': 'kb'}, 30 {'name': 'V8.MemoryHeapSampleTotalUsed', 'units': 'kb'}] 31 32 33class PageCycler(page_measurement.PageMeasurement): 34 def __init__(self, *args, **kwargs): 35 super(PageCycler, self).__init__(*args, **kwargs) 36 37 with open(os.path.join(os.path.dirname(__file__), 38 'page_cycler.js'), 'r') as f: 39 self._page_cycler_js = f.read() 40 41 self._memory_metric = None 42 self._histograms = None 43 44 def AddCommandLineOptions(self, parser): 45 # The page cyclers should default to 10 iterations. In order to change the 46 # default of an option, we must remove and re-add it. 47 # TODO: Remove this after transition to run_benchmark. 48 pageset_repeat_option = parser.get_option('--pageset-repeat') 49 pageset_repeat_option.default = 10 50 parser.remove_option('--pageset-repeat') 51 parser.add_option(pageset_repeat_option) 52 53 def DidStartBrowser(self, browser): 54 """Initialize metrics once right after the browser has been launched.""" 55 self._memory_metric = memory.MemoryMetric(browser) 56 self._memory_metric.Start() 57 self._histograms = [histogram.HistogramMetric( 58 h, histogram.RENDERER_HISTOGRAM) 59 for h in MEMORY_HISTOGRAMS] 60 61 def DidStartHTTPServer(self, tab): 62 # Avoid paying for a cross-renderer navigation on the first page on legacy 63 # page cyclers which use the filesystem. 64 tab.Navigate(tab.browser.http_server.UrlOf('nonexistent.html')) 65 66 def WillNavigateToPage(self, page, tab): 67 page.script_to_evaluate_on_commit = self._page_cycler_js 68 69 def DidNavigateToPage(self, page, tab): 70 for h in self._histograms: 71 h.Start(page, tab) 72 73 def CustomizeBrowserOptions(self, options): 74 options.AppendExtraBrowserArg('--enable-stats-collection-bindings') 75 options.AppendExtraBrowserArg('--js-flags=--expose_gc') 76 options.AppendExtraBrowserArg('--no-sandbox') 77 78 # Old commandline flags used for reference builds. 79 options.AppendExtraBrowserArg('--dom-automation') 80 81 # Temporarily disable typical_25 page set on mac. 82 if sys.platform == 'darwin' and sys.argv[-1].endswith('/typical_25.json'): 83 print 'typical_25 is currently disabled on mac. Skipping test.' 84 sys.exit(0) 85 86 def MeasureIO(self, tab, results): 87 io_stats = tab.browser.io_stats 88 if not io_stats['Browser']: 89 return 90 91 def AddSummariesForProcessType(process_type_io, process_type_trace): 92 if 'ReadOperationCount' in io_stats[process_type_io]: 93 results.AddSummary('read_operations_' + process_type_trace, '', 94 io_stats[process_type_io] 95 ['ReadOperationCount'], 96 data_type='unimportant') 97 if 'WriteOperationCount' in io_stats[process_type_io]: 98 results.AddSummary('write_operations_' + process_type_trace, '', 99 io_stats[process_type_io] 100 ['WriteOperationCount'], 101 data_type='unimportant') 102 if 'ReadTransferCount' in io_stats[process_type_io]: 103 results.AddSummary('read_bytes_' + process_type_trace, 'kb', 104 io_stats[process_type_io] 105 ['ReadTransferCount'] / 1024, 106 data_type='unimportant') 107 if 'WriteTransferCount' in io_stats[process_type_io]: 108 results.AddSummary('write_bytes_' + process_type_trace, 'kb', 109 io_stats[process_type_io] 110 ['WriteTransferCount'] / 1024, 111 data_type='unimportant') 112 AddSummariesForProcessType('Browser', 'browser') 113 AddSummariesForProcessType('Renderer', 'renderer') 114 AddSummariesForProcessType('Gpu', 'gpu') 115 116 def MeasurePage(self, page, tab, results): 117 def _IsDone(): 118 return bool(tab.EvaluateJavaScript('__pc_load_time')) 119 util.WaitFor(_IsDone, 60) 120 121 for h in self._histograms: 122 h.GetValue(page, tab, results) 123 124 results.Add('page_load_time', 'ms', 125 int(float(tab.EvaluateJavaScript('__pc_load_time'))), 126 chart_name='times') 127 128 def DidRunTest(self, tab, results): 129 self._memory_metric.Stop() 130 self._memory_metric.AddResults(tab, results) 131 self.MeasureIO(tab, results) 132 133