Home | History | Annotate | Download | only in measurements
      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 
      5 import optparse
      6 import time
      7 
      8 from metrics import v8_object_stats
      9 from telemetry.page import page_test
     10 from 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.
     42 class 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