1# Copyright 2017 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"""Helper methods for working with histograms and diagnostics."""
5from __future__ import print_function
6from __future__ import division
7from __future__ import absolute_import
8
9import re
10
11from tracing.value.diagnostics import reserved_infos
12
13# List of non-TBMv2 chromium.perf Telemetry benchmarks
14_LEGACY_BENCHMARKS = [
15    'blink_perf.bindings', 'blink_perf.canvas', 'blink_perf.css',
16    'blink_perf.dom', 'blink_perf.events', 'blink_perf.image_decoder',
17    'blink_perf.layout', 'blink_perf.owp_storage', 'blink_perf.paint',
18    'blink_perf.parser', 'blink_perf.shadow_dom', 'blink_perf.svg',
19    'cronet_perf_tests', 'dromaeo', 'dummy_benchmark.noisy_benchmark_1',
20    'dummy_benchmark.stable_benchmark_1', 'jetstream', 'kraken', 'octane',
21    'rasterize_and_record_micro.partial_invalidation',
22    'rasterize_and_record_micro.top_25', 'scheduler.tough_scheduling_cases',
23    'smoothness.desktop_tough_pinch_zoom_cases',
24    'smoothness.gpu_rasterization.polymer',
25    'smoothness.gpu_rasterization.top_25_smooth',
26    'smoothness.gpu_rasterization.tough_filters_cases',
27    'smoothness.gpu_rasterization.tough_path_rendering_cases',
28    'smoothness.gpu_rasterization.tough_pinch_zoom_cases',
29    'smoothness.gpu_rasterization.tough_scrolling_cases',
30    'smoothness.gpu_rasterization_and_decoding.image_decoding_cases',
31    'smoothness.image_decoding_cases', 'smoothness.key_desktop_move_cases',
32    'smoothness.key_mobile_sites_smooth', 'smoothness.key_silk_cases',
33    'smoothness.maps', 'smoothness.pathological_mobile_sites',
34    'smoothness.simple_mobile_sites',
35    'smoothness.sync_scroll.key_mobile_sites_smooth',
36    'smoothness.top_25_smooth', 'smoothness.tough_ad_cases',
37    'smoothness.tough_animation_cases', 'smoothness.tough_canvas_cases',
38    'smoothness.tough_filters_cases', 'smoothness.tough_image_decode_cases',
39    'smoothness.tough_path_rendering_cases',
40    'smoothness.tough_pinch_zoom_cases', 'smoothness.tough_scrolling_cases',
41    'smoothness.tough_texture_upload_cases', 'smoothness.tough_webgl_ad_cases',
42    'smoothness.tough_webgl_cases', 'speedometer', 'speedometer-future',
43    'speedometer2', 'speedometer2-future', 'start_with_url.cold.startup_pages',
44    'start_with_url.warm.startup_pages', 'thread_times.key_hit_test_cases',
45    'thread_times.key_idle_power_cases', 'thread_times.key_mobile_sites_smooth',
46    'thread_times.key_noop_cases', 'thread_times.key_silk_cases',
47    'thread_times.simple_mobile_sites', 'thread_times.tough_compositor_cases',
48    'thread_times.tough_scrolling_cases', 'v8.detached_context_age_in_gc'
49]
50_STATS_BLACKLIST = ['std', 'count', 'max', 'min', 'sum']
51
52SUITE_LEVEL_SPARSE_DIAGNOSTIC_NAMES = set([
53    reserved_infos.ARCHITECTURES.name,
54    reserved_infos.BENCHMARKS.name,
55    reserved_infos.BENCHMARK_DESCRIPTIONS.name,
56    reserved_infos.BOTS.name,
57    reserved_infos.BUG_COMPONENTS.name,
58    reserved_infos.DOCUMENTATION_URLS.name,
59    reserved_infos.GPUS.name,
60    reserved_infos.MASTERS.name,
61    reserved_infos.MEMORY_AMOUNTS.name,
62    reserved_infos.OS_NAMES.name,
63    reserved_infos.OS_VERSIONS.name,
64    reserved_infos.OWNERS.name,
65    reserved_infos.PRODUCT_VERSIONS.name,
66])
67
68HISTOGRAM_LEVEL_SPARSE_DIAGNOSTIC_NAMES = set([
69    reserved_infos.DEVICE_IDS.name,
70    reserved_infos.STORIES.name,
71    reserved_infos.STORYSET_REPEATS.name,
72    reserved_infos.STORY_TAGS.name,
73])
74
75SPARSE_DIAGNOSTIC_NAMES = SUITE_LEVEL_SPARSE_DIAGNOSTIC_NAMES.union(
76    HISTOGRAM_LEVEL_SPARSE_DIAGNOSTIC_NAMES)
77
78ADD_HISTOGRAM_RELATED_DIAGNOSTICS = SPARSE_DIAGNOSTIC_NAMES.union(
79    set([
80        reserved_infos.BUILD_URLS.name,
81        reserved_infos.CHROMIUM_COMMIT_POSITIONS.name,
82        reserved_infos.LOG_URLS.name,
83        reserved_infos.POINT_ID.name,
84        reserved_infos.SUMMARY_KEYS.name,
85        reserved_infos.TRACE_URLS.name,
86    ]))
87
88
89def EscapeName(name):
90  """Escapes a trace name so it can be stored in a row.
91
92  Args:
93    name: A string representing a name.
94
95  Returns:
96    An escaped version of the name.
97  """
98  return re.sub(r'[\:|=/#&,]', '_', name)
99
100
101def ComputeTestPath(hist, ignore_grouping_label=False):
102  # If a Histogram represents a summary across multiple stories, then its
103  # 'stories' diagnostic will contain the names of all of the stories.
104  # If a Histogram is not a summary, then its 'stories' diagnostic will contain
105  # the singular name of its story.
106  is_summary = list(hist.diagnostics.get(reserved_infos.SUMMARY_KEYS.name, []))
107
108  grouping_label = GetGroupingLabelFromHistogram(
109      hist) if not ignore_grouping_label else None
110
111  is_ref = hist.diagnostics.get(reserved_infos.IS_REFERENCE_BUILD.name)
112  if is_ref and len(is_ref) == 1:
113    is_ref = is_ref.GetOnlyElement()
114
115  story_name = hist.diagnostics.get(reserved_infos.STORIES.name)
116  if story_name and len(story_name) == 1:
117    story_name = story_name.GetOnlyElement()
118  else:
119    story_name = None
120
121  return ComputeTestPathFromComponents(
122      hist.name,
123      grouping_label=grouping_label,
124      story_name=story_name,
125      is_summary=is_summary,
126      is_ref=is_ref)
127
128
129def ComputeTestPathFromComponents(hist_name,
130                                  grouping_label=None,
131                                  story_name=None,
132                                  is_summary=None,
133                                  is_ref=False,
134                                  needs_escape=True):
135  path = hist_name or ''
136
137  if grouping_label and (not is_summary
138                         or reserved_infos.STORY_TAGS.name in is_summary):
139    path += '/' + grouping_label
140
141  if story_name and not is_summary:
142    if needs_escape:
143      escaped_story_name = EscapeName(story_name)
144      path += '/' + escaped_story_name
145    else:
146      path += '/' + story_name
147    if is_ref:
148      path += '_ref'
149  elif is_ref:
150    path += '/ref'
151
152  return path
153
154
155def GetGroupingLabelFromHistogram(hist):
156  tags = hist.diagnostics.get(reserved_infos.STORY_TAGS.name) or []
157
158  tags_to_use = [t.split(':') for t in tags if ':' in t]
159
160  return '_'.join(v for _, v in sorted(tags_to_use))
161
162
163def IsLegacyBenchmark(benchmark_name):
164  return benchmark_name in _LEGACY_BENCHMARKS
165
166
167def ShouldFilterStatistic(test_name, benchmark_name, stat_name):
168  if test_name == 'benchmark_total_duration':
169    return True
170  if benchmark_name.startswith(
171      'memory') and not benchmark_name.startswith('memory.long_running'):
172    if 'memory:' in test_name and stat_name in _STATS_BLACKLIST:
173      return True
174  if benchmark_name.startswith('memory.long_running'):
175    value_name = '%s_%s' % (test_name, stat_name)
176    return not _ShouldAddMemoryLongRunningValue(value_name)
177  if benchmark_name == 'media.desktop' or benchmark_name == 'media.mobile':
178    value_name = '%s_%s' % (test_name, stat_name)
179    return not _ShouldAddMediaValue(value_name)
180  if benchmark_name.startswith('system_health'):
181    if stat_name in _STATS_BLACKLIST:
182      return True
183  return False
184
185
186def _ShouldAddMediaValue(value_name):
187  media_re = re.compile(
188      r'(?<!dump)(?<!process)_(std|count|max|min|sum|pct_\d{4}(_\d+)?)$')
189  return not media_re.search(value_name)
190
191
192def _ShouldAddMemoryLongRunningValue(value_name):
193  v8_re = re.compile(
194      r'renderer_processes:'
195      r'(reported_by_chrome:v8|reported_by_os:system_memory:[^:]+$)')
196  if 'memory:chrome' in value_name:
197    return ('renderer:subsystem:v8' in value_name
198            or 'renderer:vmstats:overall' in value_name
199            or bool(v8_re.search(value_name)))
200  return 'v8' in value_name
201