aboutsummaryrefslogtreecommitdiff
path: root/catapult/telemetry/telemetry/web_perf/metrics/blob_timeline.py
blob: db81f699854978083690c4b88e88fe7849fe2fd4 (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
# Copyright 2015 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.value import improvement_direction
from telemetry.value import list_of_scalar_values
from telemetry.web_perf.metrics import timeline_based_metric


WRITE_EVENT_NAME = 'Registry::RegisterBlob'
READ_EVENT_NAME = 'BlobRequest'


class BlobTimelineMetric(timeline_based_metric.TimelineBasedMetric):
  """BlobTimelineMetric reports timing information about blob storage.

  The following metrics are added to the results:
    * blob write times (blob_writes)
    * blob read times (blob_reads)
  """

  def __init__(self):
    super(BlobTimelineMetric, self).__init__()

  @staticmethod
  def IsWriteEvent(event):
    return event.name == WRITE_EVENT_NAME

  @staticmethod
  def IsReadEvent(event):
    return event.name == READ_EVENT_NAME

  @staticmethod
  def IsEventInInteraction(event, interaction):
    return interaction.start <= event.start <= interaction.end

  @staticmethod
  def ThreadDurationIfPresent(event):
    if event.thread_duration:
      return event.thread_duration
    else:
      return event.duration

  def AddResults(self, model, renderer_thread, interactions, results):
    assert interactions

    write_events = []
    read_events = []
    for event in model.IterAllEvents(
        event_predicate=lambda e: self.IsWriteEvent(e) or self.IsReadEvent(e)):
      if self.IsReadEvent(event):
        read_events.append(event)
      else:
        write_events.append(event)

    # Only these private methods are tested for mocking simplicity.
    self._AddWriteResultsInternal(write_events, interactions, results)
    self._AddReadResultsInternal(read_events, interactions, results)

  def _AddWriteResultsInternal(self, events, interactions, results):
    writes = []
    for event in events:
      if (self.IsWriteEvent(event) and
          any(self.IsEventInInteraction(event, interaction)
              for interaction in interactions)):
        writes.append(self.ThreadDurationIfPresent(event))
    if writes:
      results.AddValue(list_of_scalar_values.ListOfScalarValues(
          page=results.current_page,
          tir_label=interactions[0].label,
          name='blob-writes',
          units='ms',
          values=writes,
          description='List of durations of blob writes.',
          improvement_direction=improvement_direction.DOWN))
    else:
      results.AddValue(list_of_scalar_values.ListOfScalarValues(
          page=results.current_page,
          tir_label=interactions[0].label,
          name='blob-writes',
          units='ms',
          values=None,
          none_value_reason='No blob write events found for this interaction.',
          improvement_direction=improvement_direction.DOWN))

  def _AddReadResultsInternal(self, events, interactions, results):
    reads = dict()
    for event in events:
      if (not self.IsReadEvent(event) or
          not any(self.IsEventInInteraction(event, interaction)
                 for interaction in interactions)):
        continue
      # Every blob has unique UUID.  To get the total time for reading
      # a blob, we add up the time of all events with the same blob UUID.
      uuid = event.args['uuid']
      if uuid not in reads:
        reads[uuid] = 0
      reads[uuid] += self.ThreadDurationIfPresent(event)

    if reads:
      results.AddValue(list_of_scalar_values.ListOfScalarValues(
          page=results.current_page,
          tir_label=interactions[0].label,
          name='blob-reads',
          units='ms',
          values=reads.values(),
          description='List of read times for blobs.',
          improvement_direction=improvement_direction.DOWN))
    else:
      results.AddValue(list_of_scalar_values.ListOfScalarValues(
          page=results.current_page,
          tir_label=interactions[0].label,
          name='blob-reads',
          units='ms',
          values=None,
          none_value_reason='No blob read events found for this interaction.',
          improvement_direction=improvement_direction.DOWN))