1# Copyright 2013 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 5import optparse 6import time 7 8from metrics import v8_object_stats 9from telemetry.page import page_test 10from telemetry.value import scalar 11 12# V8 statistics counter names. These can be retrieved using 13# v8_object_stats.V8ObjectStatsMetric.GetV8StatsTable. 14_V8_BYTES_COMMITTED = [ 15 'V8.MemoryNewSpaceBytesCommitted', 16 'V8.MemoryOldPointerSpaceBytesCommitted', 17 'V8.MemoryOldDataSpaceBytesCommitted', 18 'V8.MemoryCodeSpaceBytesCommitted', 19 'V8.MemoryMapSpaceBytesCommitted', 20 'V8.MemoryCellSpaceBytesCommitted', 21 'V8.MemoryPropertyCellSpaceBytesCommitted', 22 'V8.MemoryLoSpaceBytesCommitted', 23] 24_V8_BYTES_USED = [ 25 'V8.MemoryNewSpaceBytesUsed', 26 'V8.MemoryOldPointerSpaceBytesUsed', 27 'V8.MemoryOldDataSpaceBytesUsed', 28 'V8.MemoryCodeSpaceBytesUsed', 29 'V8.MemoryMapSpaceBytesUsed', 30 'V8.MemoryCellSpaceBytesUsed', 31 'V8.MemoryPropertyCellSpaceBytesUsed', 32 'V8.MemoryLoSpaceBytesUsed', 33] 34_V8_MEMORY_ALLOCATED = [ 35 'V8.OsMemoryAllocated', 36] 37 38 39# NOTE(chrishenry): This measurement does NOT work anymore. The 40# feature it depends on has been removed from telemetry. The benchmark 41# has been disabled on bot. 42class Endure(page_test.PageTest): 43 44 def __init__(self): 45 super(Endure, self).__init__('RunEndure') 46 # Browser object, saved so that browser.memory_stats can be accessed. 47 self._browser = None 48 49 # Dictionary of trace name to lists of y-values, for making summary values. 50 self._y_values = {} 51 52 # Number of page repetitions since the start of the test. 53 self._iterations_elapsed = 0 54 55 # Start time of the test, used to report total time. 56 self._start_time = None 57 58 @classmethod 59 def AddCommandLineArgs(cls, parser): 60 group = optparse.OptionGroup(parser, 'Endure options') 61 group.add_option('--perf-stats-interval', 62 dest='perf_stats_interval', 63 default=1, 64 type='int', 65 help='Number of iterations per sampling of statistics.') 66 parser.add_option_group(group) 67 68 def DidStartBrowser(self, browser): 69 """Initializes the measurement after the browser is started.""" 70 self._browser = browser 71 self._start_time = time.time() 72 73 def CustomizeBrowserOptions(self, options): 74 """Adds extra command-line options to the browser.""" 75 v8_object_stats.V8ObjectStatsMetric.CustomizeBrowserOptions(options) 76 77 def ValidateAndMeasurePage(self, page, tab, results): 78 """Takes a sample and adds a result if enough time has passed.""" 79 self._iterations_elapsed += 1 80 if self._iterations_elapsed % int(self.options.perf_stats_interval) == 0: 81 self._SampleStats(tab, results) 82 83 def _SampleStats(self, tab, results): 84 """Records information and add it to the results.""" 85 86 def AddPoint(trace_name, units_y, value_y, chart_name=None): 87 """Adds one data point to the results object.""" 88 if chart_name: 89 trace_name = '%s.%s' % (chart_name, trace_name) 90 else: 91 assert '.' not in trace_name, ( 92 'Trace names cannot contain "." with an empty chart_name since this' 93 ' is used to delimit chart_name.trace_name.') 94 results.AddValue(scalar.ScalarValue( 95 results.current_page, trace_name + '_X', 'iterations', 96 self._iterations_elapsed, important=False)) 97 results.AddValue(scalar.ScalarValue( 98 results.current_page, trace_name + '_Y', units_y, value_y, 99 important=False)) 100 101 # Save the value so that summary stats can be calculated. 102 if trace_name not in self._y_values: 103 self._y_values[trace_name] = { 104 'units': units_y, 105 'chart_name': chart_name, 106 'values': [], 107 } 108 self._y_values[trace_name]['values'].append(value_y) 109 110 # DOM nodes and event listeners. 111 dom_stats = tab.dom_stats 112 dom_node_count = dom_stats['node_count'] 113 event_listener_count = dom_stats['event_listener_count'] 114 AddPoint('dom_nodes', 'count', dom_node_count, chart_name='object_counts') 115 AddPoint('event_listeners', 'count', event_listener_count, 116 chart_name='object_counts') 117 118 # Browser and renderer virtual memory stats. 119 memory_stats = self._browser.memory_stats 120 def BrowserVMStats(statistic_name): 121 """Get VM stats from the Browser object in KB.""" 122 return memory_stats[statistic_name].get('VM', 0) / 1024.0 123 AddPoint('browser_vm', 'KB', BrowserVMStats('Browser'), 124 chart_name='vm_stats') 125 AddPoint('renderer_vm', 'KB', BrowserVMStats('Renderer'), 126 chart_name='vm_stats') 127 AddPoint('gpu_vm', 'KB', BrowserVMStats('Gpu'), chart_name='vm_stats') 128 129 # V8 counter stats. 130 def V8StatsSum(counters): 131 """Given a list of V8 counter names, get the sum of the values in KB.""" 132 stats = v8_object_stats.V8ObjectStatsMetric.GetV8StatsTable(tab, counters) 133 return sum(stats.values()) / 1024.0 134 AddPoint('v8_memory_committed', 'KB', V8StatsSum(_V8_BYTES_COMMITTED), 135 chart_name='v8_counter_stats') 136 AddPoint('v8_memory_used', 'KB', V8StatsSum(_V8_BYTES_USED), 137 chart_name='v8_counter_stats') 138 AddPoint('v8_memory_allocated', 'KB', V8StatsSum(_V8_MEMORY_ALLOCATED), 139 chart_name='v8_counter_stats') 140 141 def DidRunTest(self, browser, results): 142 """Adds summary results (single number for one test run).""" 143 # Report test run length. 144 results.AddSummaryValue(scalar.ScalarValue(None, 'total_iterations', 145 'iterations', 146 self._iterations_elapsed, 147 important=False)) 148 results.AddSummaryValue(scalar.ScalarValue(None, 'total_time', 'seconds', 149 time.time() - self._start_time, 150 important=False)) 151 152 # Add summary stats which could be monitored for anomalies. 153 for trace_name in self._y_values: 154 units = self._y_values[trace_name]['units'] 155 chart_name = self._y_values[trace_name]['chart_name'] 156 values = self._y_values[trace_name]['values'] 157 value_name = '%s.%s_max' % (chart_name, trace_name) 158 results.AddSummaryValue( 159 scalar.ScalarValue(None, value_name, units, max(values))) 160