# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from collections import defaultdict
from core import path_util
path_util.AddTracingToPath()
from core import perf_benchmark
from contrib.cluster_telemetry import ct_benchmarks_util
from contrib.cluster_telemetry import page_set as ct_page_set
import page_sets
from telemetry import benchmark
from telemetry import timeline
from telemetry.page import legacy_page_test
from tracing.trace_data import trace_data as trace_data_module
class _GenericTraceMeasurement(legacy_page_test.LegacyPageTest):
def __init__(self, options):
super(_GenericTraceMeasurement, self).__init__()
self._trace_categories = ','.join(options.trace_categories)
trace_names = ','.join(options.trace_names).split(',')
self._trace_names = [name for name in trace_names if name]
def WillNavigateToPage(self, page, tab):
config = timeline.tracing_config.TracingConfig()
config.enable_chrome_trace = True
config.chrome_trace_config.category_filter.AddFilterString(
self._trace_categories)
tab.browser.platform.tracing_controller.StartTracing(config)
def ValidateAndMeasurePage(self, page, tab, results):
with tab.browser.platform.tracing_controller.StopTracing() as trace_builder:
trace_data = trace_builder.AsData()
measurements = defaultdict(list)
duration_events = defaultdict(list)
duration_measurements = defaultdict(list)
for trace in trace_data.GetTracesFor(trace_data_module.CHROME_TRACE_PART):
for event in trace['traceEvents']:
# We collect data from duration begin, complete, instant and count
# events. See benchmark documentation for details.
if event['ph'] not in ('B', 'E', 'X', 'I', 'C'):
continue
if self._trace_names and event['name'] not in self._trace_names:
continue
event_name = '/'.join([event['cat'], event['name']])
if event['ph'] == 'B':
duration_events[event_name].append(int(event['ts']))
elif event['ph'] == 'E':
elapsed = int(event['ts']) - duration_events[event_name].pop()
value_name = '/'.join([event_name, 'elapsed'])
duration_measurements[value_name].append(elapsed)
elif event['ph'] == 'X':
elapsed = int(event['dur'])
value_name = '/'.join([event_name, 'elapsed'])
duration_measurements[value_name].append(elapsed)
for arg_name, arg_value in event.get('args', {}).items():
if not isinstance(arg_value, int):
continue
value_name = '/'.join([event_name, arg_name])
measurements[value_name].append(arg_value)
for name, value in measurements.items():
results.AddMeasurement(name, 'count', value)
for name, value in duration_measurements.items():
results.AddMeasurement(name, 'us', value)
class _GenericTraceBenchmark(perf_benchmark.PerfBenchmark):
@classmethod
def AddBenchmarkCommandLineArgs(cls, parser):
parser.add_argument('--trace-categories',
default=[],
action='append',
help='Trace categories to enable')
parser.add_argument(
'--trace-names',
default=[],
action='append',
help=('Names of trace event to collect '
'If not specified, all trace events in the enabled '
'categories will be collected'))
@classmethod
def ProcessCommandLineArgs(cls, parser, args):
if not args.trace_categories:
parser.error('--trace-categories is required')
def CreatePageTest(self, options):
return _GenericTraceMeasurement(options)
@benchmark.Info(emails=['[email protected]'],
documentation_url='https://bit.ly/2DIOVy3')
# For local verification.
class GenericTraceTop25(_GenericTraceBenchmark):
page_set = page_sets.StaticTop25PageSet
@classmethod
def Name(cls):
return 'generic_trace.top25'
@benchmark.Info(emails=['[email protected]'],
documentation_url='https://bit.ly/2DIOVy3')
class GenericTraceClusterTelemetry(_GenericTraceBenchmark):
@classmethod
def Name(cls):
return 'generic_trace_ct'
@classmethod
def AddBenchmarkCommandLineArgs(cls, parser):
_GenericTraceBenchmark.AddBenchmarkCommandLineArgs(parser)
ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
@classmethod
def ProcessCommandLineArgs(cls, parser, args):
_GenericTraceBenchmark.ProcessCommandLineArgs(parser, args)
ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
def CreateStorySet(self, options):
return ct_page_set.CTPageSet(
options.urls_list, options.user_agent, options.archive_data_file)