aboutsummaryrefslogtreecommitdiff
path: root/catapult/telemetry/telemetry/web_perf/metrics/v8_execution.py
blob: 3fbd7de2387c0118f9c8912dbfd9736bfef04d59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# Copyright 2016 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.
from telemetry.util import statistics
from telemetry.value import scalar
from telemetry.web_perf.metrics import timeline_based_metric


class V8ExecutionMetric(timeline_based_metric.TimelineBasedMetric):
  """ This Metric aggregates various V8 runtime measurements."""
  _EVENTS = ('v8.run', 'v8.compile', 'V8.Execute', 'WindowProxy::initialize',)
  _RENDERER_MAIN_THREAD = 'CrRendererMain'

  def __init__(self):
    super(V8ExecutionMetric, self).__init__()
    self._stats = [
      V8TotalTimeStats('v8_execution_time_total', ['V8.Execute']),
      V8SelfTimeStats('v8_execution_time_self', ['V8.Execute']),
      V8SelfTimeStats('v8_parse_lazy_total',
                      ['V8.ParseLazy', 'V8.ParseLazyMicroSeconds']),
      V8SelfTimeStats('v8_compile_fullcode_total',
                      ['V8.CompileFullCode']),
      V8SelfTimeStats('v8_compile_ignition_total',
                      ['V8.CompileIgnition']),
      V8TotalTimeStats('v8_recompile_total',
                       ['V8.RecompileSynchronous',
                         'V8.RecompileConcurrent']),
      V8TotalTimeStats('v8_recompile_synchronous_total',
                       ['V8.RecompileSynchronous']),
      V8TotalTimeStats('v8_recompile_concurrent_total',
                       ['V8.RecompileConcurrent']),
      V8TotalTimeStats('v8_optimize_code_total', ['V8.OptimizeCode']),
      V8TotalTimeStats('v8_deoptimize_code_total', ['V8.DeoptimizeCode']),
      V8OptimizeParseLazyStats('v8_optimize_parse_lazy_total'),
    ]
    self._name_to_stats = {}
    for stat in self._stats:
      for event_name in stat.event_names:
        if event_name not in self._name_to_stats:
          self._name_to_stats[event_name] = [stat]
        else:
          self._name_to_stats[event_name].append(stat)

  def AddResults(self, timeline_model, renderer_thread, interactions, results):
    self.VerifyNonOverlappedRecords(interactions)
    self._ResetMetrics()
    self._CollectEvents(timeline_model, interactions)
    self._AddMetricResults(results, interactions[0].label)

  def _ResetMetrics(self):
    for metric in self._stats:
      metric.Reset()

  def _CollectEvents(self, timeline_model, interactions):
    for event in timeline_model.IterAllSlices():
      if not timeline_based_metric.IsEventInInteractions(event, interactions):
        continue
      self._CollectEvent(event)

  def _CollectEvent(self, event):
    if event.name not in self._name_to_stats:
      return
    for stat in self._name_to_stats[event.name]:
      stat.CollectEvent(event)

  def _AddMetricResults(self, results, label):
    for stat in self._stats:
      stat.AddResults(results, label)


class V8TimeStats(object):
  def __init__(self, name, event_names, description=None):
    self.name = name
    self.event_names = event_names
    self.description = description
    self.durations = []

  def Reset(self):
    self.durations = []

  def Duration(self):
    return sum(self.durations)

  def Count(self):
    return len(self.durations)

  def Average(self):
    return statistics.DivideIfPossibleOrZero(self.Duration(), self.Count())

  def AddResults(self, results, label):
    results.AddValue(
      scalar.ScalarValue(
          results.current_page,
          self.name, 'ms', self.Duration(),
          description=self.description,
          tir_label=label))
    results.AddValue(
      scalar.ScalarValue(
          results.current_page,
          "%s_count" % self.name, 'count', self.Count(),
          description=self.description,
          tir_label=label))
    results.AddValue(
      scalar.ScalarValue(
          results.current_page,
          "%s_average" % self.name, 'ms', self.Average(),
          description=self.description,
          tir_label=label))

  def CollectEvent(self, event):
    raise NotImplementedError()


class V8TotalTimeStats(V8TimeStats):
  def CollectEvent(self, event):
    self.durations.append(event.duration)


class V8SelfTimeStats(V8TimeStats):
  def CollectEvent(self, event):
    self.durations.append(event.self_time)


class V8OptimizeParseLazyStats(V8TimeStats):
  def __init__(self, name):
    super(V8OptimizeParseLazyStats, self).__init__(
      name,
      ['V8.ParseLazy', 'V8.ParseLazyMicroSeconds'],
      'Time spent in lazy-parsing due to optimizing code')

  def CollectEvent(self, event):
    if event.parent_slice is None or \
       event.parent_slice.name != "V8.OptimizeCode":
      return
    self.durations.append(event.self_time)