1# Copyright 2019 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
5from collections import defaultdict
6
7from core import path_util
8path_util.AddTracingToPath()
9from core import perf_benchmark
10
11from contrib.cluster_telemetry import ct_benchmarks_util
12from contrib.cluster_telemetry import page_set as ct_page_set
13import page_sets
14from telemetry import benchmark
15from telemetry import timeline
16from telemetry.page import legacy_page_test
17
18from tracing.trace_data import trace_data as trace_data_module
19
20
21class _GenericTraceMeasurement(legacy_page_test.LegacyPageTest):
22
23  def __init__(self, options):
24    super(_GenericTraceMeasurement, self).__init__()
25    self._trace_categories = ','.join(options.trace_categories)
26    trace_names = ','.join(options.trace_names).split(',')
27    self._trace_names = [name for name in trace_names if name]
28
29  def WillNavigateToPage(self, page, tab):
30    config = timeline.tracing_config.TracingConfig()
31    config.enable_chrome_trace = True
32    config.chrome_trace_config.category_filter.AddFilterString(
33        self._trace_categories)
34    tab.browser.platform.tracing_controller.StartTracing(config)
35
36  def ValidateAndMeasurePage(self, page, tab, results):
37    with tab.browser.platform.tracing_controller.StopTracing() as trace_builder:
38      trace_data = trace_builder.AsData()
39    measurements = defaultdict(list)
40    for trace in trace_data.GetTracesFor(trace_data_module.CHROME_TRACE_PART):
41      for event in trace['traceEvents']:
42        # We collect data from duration begin, complete, instant and count
43        # events. See benchmark documentation for details.
44        if event['ph'] not in ('B', 'X', 'I', 'C'):
45          continue
46        if self._trace_names and event['name'] not in self._trace_names:
47          continue
48        for arg_name, arg_value in event.get('args', {}).iteritems():
49          if not isinstance(arg_value, int):
50            continue
51          value_name = '/'.join([event['cat'], event['name'], arg_name])
52          measurements[value_name].append(arg_value)
53    for name, value in measurements.items():
54      results.AddMeasurement(name, 'count', value)
55
56
57class _GenericTraceBenchmark(perf_benchmark.PerfBenchmark):
58  @classmethod
59  def AddBenchmarkCommandLineArgs(cls, parser):
60    parser.add_option('--trace-categories', default=[], action='append',
61                      help='Trace categories to enable')
62    parser.add_option('--trace-names', default=[], action='append',
63                      help='Names of trace event to collect '
64                           'If not specified, all trace events in the enabled '
65                           'categories will be collected')
66
67  @classmethod
68  def ProcessCommandLineArgs(cls, parser, args):
69    if not args.trace_categories:
70      parser.error('--trace-categories is required')
71
72  def CreatePageTest(self, options):
73    return _GenericTraceMeasurement(options)
74
75
76@benchmark.Info(emails=['wangxianzhu@chromium.org'],
77                documentation_url='https://bit.ly/2DIOVy3')
78# For local verification.
79class GenericTraceTop25(_GenericTraceBenchmark):
80  page_set = page_sets.StaticTop25PageSet
81
82  @classmethod
83  def Name(cls):
84    return 'generic_trace.top25'
85
86
87@benchmark.Info(emails=['wangxianzhu@chromium.org'],
88                documentation_url='https://bit.ly/2DIOVy3')
89class GenericTraceClusterTelemetry(_GenericTraceBenchmark):
90  @classmethod
91  def Name(cls):
92    return 'generic_trace_ct'
93
94  @classmethod
95  def AddBenchmarkCommandLineArgs(cls, parser):
96    _GenericTraceBenchmark.AddBenchmarkCommandLineArgs(parser)
97    ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
98
99  @classmethod
100  def ProcessCommandLineArgs(cls, parser, args):
101    _GenericTraceBenchmark.ProcessCommandLineArgs(parser, args)
102    ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
103
104  def CreateStorySet(self, options):
105    return ct_page_set.CTPageSet(
106        options.urls_list, options.user_agent, options.archive_data_file)
107