blob: 71f6b501b37629ee7d6517c80bb12a50a7b42e97 [file] [log] [blame]
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import optparse
import time
from metrics import v8_object_stats
from telemetry.page import page_measurement
from telemetry.value import scalar
# V8 statistics counter names. These can be retrieved using
# v8_object_stats.V8ObjectStatsMetric.GetV8StatsTable.
_V8_BYTES_COMMITTED = [
'V8.MemoryNewSpaceBytesCommitted',
'V8.MemoryOldPointerSpaceBytesCommitted',
'V8.MemoryOldDataSpaceBytesCommitted',
'V8.MemoryCodeSpaceBytesCommitted',
'V8.MemoryMapSpaceBytesCommitted',
'V8.MemoryCellSpaceBytesCommitted',
'V8.MemoryPropertyCellSpaceBytesCommitted',
'V8.MemoryLoSpaceBytesCommitted',
]
_V8_BYTES_USED = [
'V8.MemoryNewSpaceBytesUsed',
'V8.MemoryOldPointerSpaceBytesUsed',
'V8.MemoryOldDataSpaceBytesUsed',
'V8.MemoryCodeSpaceBytesUsed',
'V8.MemoryMapSpaceBytesUsed',
'V8.MemoryCellSpaceBytesUsed',
'V8.MemoryPropertyCellSpaceBytesUsed',
'V8.MemoryLoSpaceBytesUsed',
]
_V8_MEMORY_ALLOCATED = [
'V8.OsMemoryAllocated',
]
class Endure(page_measurement.PageMeasurement):
options = {'skip_navigate_on_repeat': True}
def __init__(self):
super(Endure, self).__init__('RunEndure')
# Browser object, saved so that browser.memory_stats can be accessed.
self._browser = None
# Dictionary of trace name to lists of y-values, for making summary values.
self._y_values = {}
# Number of page repetitions since the start of the test.
self._iterations_elapsed = 0
# Start time of the test, used to report total time.
self._start_time = None
@classmethod
def AddCommandLineArgs(cls, parser):
group = optparse.OptionGroup(parser, 'Endure options')
group.add_option('--perf-stats-interval',
dest='perf_stats_interval',
default=1,
type='int',
help='Number of iterations per sampling of statistics.')
parser.add_option_group(group)
def DidStartBrowser(self, browser):
"""Initializes the measurement after the browser is started."""
self._browser = browser
self._start_time = time.time()
def CustomizeBrowserOptions(self, options):
"""Adds extra command-line options to the browser."""
v8_object_stats.V8ObjectStatsMetric.CustomizeBrowserOptions(options)
def MeasurePage(self, page, tab, results):
"""Takes a sample and adds a result if enough time has passed."""
self._iterations_elapsed += 1
if self._iterations_elapsed % int(self.options.perf_stats_interval) == 0:
self._SampleStats(tab, results)
def _SampleStats(self, tab, results):
"""Records information and add it to the results."""
def AddPoint(trace_name, units_y, value_y, chart_name=None):
"""Adds one data point to the results object."""
if chart_name:
trace_name = '%s.%s' % (chart_name, trace_name)
else:
assert '.' not in trace_name, (
'Trace names cannot contain "." with an empty chart_name since this'
' is used to delimit chart_name.trace_name.')
results.AddValue(scalar.ScalarValue(
results.current_page, trace_name + '_X', 'iterations',
self._iterations_elapsed, important=False))
results.AddValue(scalar.ScalarValue(
results.current_page, trace_name + '_Y', units_y, value_y,
important=False))
# Save the value so that summary stats can be calculated.
if trace_name not in self._y_values:
self._y_values[trace_name] = {
'units': units_y,
'chart_name': chart_name,
'values': [],
}
self._y_values[trace_name]['values'].append(value_y)
# DOM nodes and event listeners.
dom_stats = tab.dom_stats
dom_node_count = dom_stats['node_count']
event_listener_count = dom_stats['event_listener_count']
AddPoint('dom_nodes', 'count', dom_node_count, chart_name='object_counts')
AddPoint('event_listeners', 'count', event_listener_count,
chart_name='object_counts')
# Browser and renderer virtual memory stats.
memory_stats = self._browser.memory_stats
def BrowserVMStats(statistic_name):
"""Get VM stats from the Browser object in KB."""
return memory_stats[statistic_name].get('VM', 0) / 1024.0
AddPoint('browser_vm', 'KB', BrowserVMStats('Browser'),
chart_name='vm_stats')
AddPoint('renderer_vm', 'KB', BrowserVMStats('Renderer'),
chart_name='vm_stats')
AddPoint('gpu_vm', 'KB', BrowserVMStats('Gpu'), chart_name='vm_stats')
# V8 counter stats.
def V8StatsSum(counters):
"""Given a list of V8 counter names, get the sum of the values in KB."""
stats = v8_object_stats.V8ObjectStatsMetric.GetV8StatsTable(tab, counters)
return sum(stats.values()) / 1024.0
AddPoint('v8_memory_committed', 'KB', V8StatsSum(_V8_BYTES_COMMITTED),
chart_name='v8_counter_stats')
AddPoint('v8_memory_used', 'KB', V8StatsSum(_V8_BYTES_USED),
chart_name='v8_counter_stats')
AddPoint('v8_memory_allocated', 'KB', V8StatsSum(_V8_MEMORY_ALLOCATED),
chart_name='v8_counter_stats')
def DidRunTest(self, browser, results):
"""Adds summary results (single number for one test run)."""
# Report test run length.
results.AddSummaryValue(scalar.ScalarValue(None, 'total_iterations',
'iterations',
self._iterations_elapsed,
important=False))
results.AddSummaryValue(scalar.ScalarValue(None, 'total_time', 'seconds',
time.time() - self._start_time,
important=False))
# Add summary stats which could be monitored for anomalies.
for trace_name in self._y_values:
units = self._y_values[trace_name]['units']
chart_name = self._y_values[trace_name]['chart_name']
values = self._y_values[trace_name]['values']
value_name = '%s.%s_max' % (chart_name, trace_name)
results.AddSummaryValue(
scalar.ScalarValue(None, value_name, units, max(values)))