• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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.
4from telemetry.util import statistics
5from telemetry.value import scalar
6from telemetry.web_perf.metrics import timeline_based_metric
7
8
9class V8ExecutionMetric(timeline_based_metric.TimelineBasedMetric):
10  """ This Metric aggregates various V8 runtime measurements."""
11  _EVENTS = ('v8.run', 'v8.compile', 'V8.Execute', 'WindowProxy::initialize',)
12  _RENDERER_MAIN_THREAD = 'CrRendererMain'
13
14  def __init__(self):
15    super(V8ExecutionMetric, self).__init__()
16    self._stats = [
17      V8TotalTimeStats('v8_execution_time_total', ['V8.Execute']),
18      V8SelfTimeStats('v8_execution_time_self', ['V8.Execute']),
19      V8SelfTimeStats('v8_parse_lazy_total',
20                      ['V8.ParseLazy', 'V8.ParseLazyMicroSeconds']),
21      V8SelfTimeStats('v8_compile_fullcode_total',
22                      ['V8.CompileFullCode']),
23      V8SelfTimeStats('v8_compile_ignition_total',
24                      ['V8.CompileIgnition']),
25      V8TotalTimeStats('v8_recompile_total',
26                       ['V8.RecompileSynchronous',
27                         'V8.RecompileConcurrent']),
28      V8TotalTimeStats('v8_recompile_synchronous_total',
29                       ['V8.RecompileSynchronous']),
30      V8TotalTimeStats('v8_recompile_concurrent_total',
31                       ['V8.RecompileConcurrent']),
32      V8TotalTimeStats('v8_optimize_code_total', ['V8.OptimizeCode']),
33      V8TotalTimeStats('v8_deoptimize_code_total', ['V8.DeoptimizeCode']),
34      V8OptimizeParseLazyStats('v8_optimize_parse_lazy_total'),
35    ]
36    self._name_to_stats = {}
37    for stat in self._stats:
38      for event_name in stat.event_names:
39        if event_name not in self._name_to_stats:
40          self._name_to_stats[event_name] = [stat]
41        else:
42          self._name_to_stats[event_name].append(stat)
43
44  def AddResults(self, timeline_model, renderer_thread, interactions, results):
45    self.VerifyNonOverlappedRecords(interactions)
46    self._ResetMetrics()
47    self._CollectEvents(timeline_model, interactions)
48    self._AddMetricResults(results, interactions[0].label)
49
50  def _ResetMetrics(self):
51    for metric in self._stats:
52      metric.Reset()
53
54  def _CollectEvents(self, timeline_model, interactions):
55    for event in timeline_model.IterAllSlices():
56      if not timeline_based_metric.IsEventInInteractions(event, interactions):
57        continue
58      self._CollectEvent(event)
59
60  def _CollectEvent(self, event):
61    if event.name not in self._name_to_stats:
62      return
63    for stat in self._name_to_stats[event.name]:
64      stat.CollectEvent(event)
65
66  def _AddMetricResults(self, results, label):
67    for stat in self._stats:
68      stat.AddResults(results, label)
69
70
71class V8TimeStats(object):
72  def __init__(self, name, event_names, description=None):
73    self.name = name
74    self.event_names = event_names
75    self.description = description
76    self.durations = []
77
78  def Reset(self):
79    self.durations = []
80
81  def Duration(self):
82    return sum(self.durations)
83
84  def Count(self):
85    return len(self.durations)
86
87  def Average(self):
88    return statistics.DivideIfPossibleOrZero(self.Duration(), self.Count())
89
90  def AddResults(self, results, label):
91    results.AddValue(
92      scalar.ScalarValue(
93          results.current_page,
94          self.name, 'ms', self.Duration(),
95          description=self.description,
96          tir_label=label))
97    results.AddValue(
98      scalar.ScalarValue(
99          results.current_page,
100          "%s_count" % self.name, 'count', self.Count(),
101          description=self.description,
102          tir_label=label))
103    results.AddValue(
104      scalar.ScalarValue(
105          results.current_page,
106          "%s_average" % self.name, 'ms', self.Average(),
107          description=self.description,
108          tir_label=label))
109
110  def CollectEvent(self, event):
111    raise NotImplementedError()
112
113
114class V8TotalTimeStats(V8TimeStats):
115  def CollectEvent(self, event):
116    self.durations.append(event.duration)
117
118
119class V8SelfTimeStats(V8TimeStats):
120  def CollectEvent(self, event):
121    self.durations.append(event.self_time)
122
123
124class V8OptimizeParseLazyStats(V8TimeStats):
125  def __init__(self, name):
126    super(V8OptimizeParseLazyStats, self).__init__(
127      name,
128      ['V8.ParseLazy', 'V8.ParseLazyMicroSeconds'],
129      'Time spent in lazy-parsing due to optimizing code')
130
131  def CollectEvent(self, event):
132    if event.parent_slice is None or \
133       event.parent_slice.name != "V8.OptimizeCode":
134      return
135    self.durations.append(event.self_time)
136