1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class TimelineBasedMetricException(Exception):
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """Exception that can be thrown from metrics that implements
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     TimelineBasedMetric to indicate a problem arised when computing the metric.
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)     """
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)def _TimeRangesHasOverlap(iterable_time_ranges):
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """ Returns True if there is are overlapped ranges in time ranges.
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  iterable_time_ranges: an iterable of time ranges. Each time range is a
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  tuple (start time, end time).
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  """
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  # Sort the ranges by the start time
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  sorted_time_ranges = sorted(iterable_time_ranges)
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  last_range = sorted_time_ranges[0]
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for current_range in sorted_time_ranges[1:]:
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    start_current_range = current_range[0]
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    end_last_range = last_range[1]
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if start_current_range < end_last_range:
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return True
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    last_range = current_range
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return False
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class TimelineBasedMetric(object):
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def __init__(self):
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    """Computes metrics from a telemetry.timeline Model and a range
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    super(TimelineBasedMetric, self).__init__()
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  def AddResults(self, model, renderer_thread, interaction_records, results):
380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    """Computes and adds metrics for the interaction_records' time ranges.
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    The override of this method should compute results on the data **only**
410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    within the interaction_records' start and end time ranges.
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Args:
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      model: An instance of telemetry.timeline.model.TimelineModel.
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      interaction_records: A list of instances of TimelineInteractionRecord. If
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        the override of this method doesn't support overlapped ranges, use
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        VerifyNonOverlappedRecords to check that no records are overlapped.
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      results: An instance of page.PageTestResults.
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    raise NotImplementedError()
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  def VerifyNonOverlappedRecords(self, interaction_records):
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """This raises exceptions if interaction_records contain overlapped ranges.
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    """
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if _TimeRangesHasOverlap(((r.start, r.end) for r in interaction_records)):
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise TimelineBasedMetricException(
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          'This metric does not support interaction records with overlapped '
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          'time range.')
60