1# Copyright 2014 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
5
6class TimelineBasedMetricException(Exception):
7  """Exception that can be thrown from metrics that implements
8     TimelineBasedMetric to indicate a problem arose when computing the metric.
9     """
10
11
12def _TimeRangesHasOverlap(iterable_time_ranges):
13  """ Returns True if there is are overlapped ranges in time ranges.
14  iterable_time_ranges: an iterable of time ranges. Each time range is a
15  tuple (start time, end time).
16  """
17  # Sort the ranges by the start time
18  sorted_time_ranges = sorted(iterable_time_ranges)
19  last_range = sorted_time_ranges[0]
20  for current_range in sorted_time_ranges[1:]:
21    start_current_range = current_range[0]
22    end_last_range = last_range[1]
23    if start_current_range < end_last_range:
24      return True
25    last_range = current_range
26  return False
27
28
29def IsEventInInteractions(event, interaction_records):
30  """ Return True if event is in any of the interaction records' time range.
31
32  Args:
33    event: an instance of telemetry.timeline.event.TimelineEvent.
34    interaction_records: a list of interaction records, whereas each record is
35      an instance of
36      telemetry.web_perf.timeline_interaction_record.TimelineInteractionRecord.
37
38  Returns:
39    True if |event|'s start & end time is in any of the |interaction_records|'s
40    time range.
41  """
42  return any(ir.start <= event.start and ir.end >= event.end for ir
43             in interaction_records)
44
45
46class TimelineBasedMetric(object):
47
48  def __init__(self):
49    """Computes metrics from a telemetry.timeline Model and a range
50
51    """
52    super(TimelineBasedMetric, self).__init__()
53
54  def AddResults(self, model, renderer_thread, interaction_records, results):
55    """Computes and adds metrics for the interaction_records' time ranges.
56
57    The override of this method should compute results on the data **only**
58    within the interaction_records' start and end time ranges.
59
60    Args:
61      model: An instance of telemetry.timeline.model.TimelineModel.
62      interaction_records: A list of instances of TimelineInteractionRecord. If
63        the override of this method doesn't support overlapped ranges, use
64        VerifyNonOverlappedRecords to check that no records are overlapped.
65      results: An instance of page.PageTestResults.
66
67    """
68    raise NotImplementedError()
69
70  def AddWholeTraceResults(self, model, results):
71    """Computes and adds metrics corresponding to the entire trace.
72
73    Override this method to compute results that correspond to the whole trace.
74
75    Args:
76      model: An instance of telemetry.timeline.model.TimelineModel.
77      results: An instance of page.PageTestResults.
78    """
79    pass
80
81  def VerifyNonOverlappedRecords(self, interaction_records):
82    """This raises exceptions if interaction_records contain overlapped ranges.
83    """
84    if _TimeRangesHasOverlap(((r.start, r.end) for r in interaction_records)):
85      raise TimelineBasedMetricException(
86          'This metric does not support interaction records with overlapped '
87          'time range.')
88