• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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