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
5import telemetry.timeline.event_container as event_container
6
7
8# Doesn't inherit from TimelineEvent because its only a temporary wrapper of a
9# counter sample into an event. During stable operation, the samples are stored
10# a dense array of values rather than in the long-form done by an Event.
11class CounterSample(object):
12  def __init__(self, counter, sample_index):
13    self._counter = counter
14    self._sample_index = sample_index
15
16  @property
17  def name(self):
18    return None
19
20  @property
21  def start(self):
22    return self._counter.timestamps[self._sample_index]
23
24  @start.setter
25  def start(self, start):
26    self._counter.timestamps[self._sample_index] = start
27
28  @property
29  def duration(self):
30    return 0
31
32  @property
33  def end(self):
34    return self.start
35
36  @property
37  def thread_start(self):
38    return None
39
40  @property
41  def thread_duration(self):
42    return None
43
44  @property
45  def thread_end(self):
46    return None
47
48
49class Counter(event_container.TimelineEventContainer):
50  """ Stores all the samples for a given counter.
51  """
52  def __init__(self, parent, category, name):
53    super(Counter, self).__init__(name, parent)
54    self.category = category
55    self.full_name  = category + '.' + name
56    self.samples = []
57    self.timestamps = []
58    self.series_names = []
59    self.totals = []
60    self.max_total = 0
61
62  def IterChildContainers(self):
63    return
64    yield # pylint: disable=W0101
65
66  def IterEventsInThisContainer(self, event_type_predicate, event_predicate):
67    if not event_type_predicate(CounterSample) or not self.timestamps:
68      return
69
70    # Pass event_predicate a reused CounterSample instance to avoid
71    # creating a ton of garbage for rejected samples.
72    test_sample = CounterSample(self, 0)
73    for i in xrange(len(self.timestamps)):
74      test_sample._sample_index = i
75      if event_predicate(test_sample):
76        yield CounterSample(self, i)
77
78  @property
79  def num_series(self):
80    return len(self.series_names)
81
82  @property
83  def num_samples(self):
84    return len(self.timestamps)
85
86  def FinalizeImport(self):
87    if self.num_series * self.num_samples != len(self.samples):
88      raise ValueError(
89          'Length of samples must be a multiple of length of timestamps.')
90
91    self.totals = []
92    self.max_total = 0
93    if not len(self.samples):
94      return
95
96    max_total = None
97    for i in xrange(self.num_samples):
98      total = 0
99      for j in xrange(self.num_series):
100        total += self.samples[i * self.num_series + j]
101        self.totals.append(total)
102      if max_total is None or total > max_total:
103        max_total = total
104    self.max_total = max_total
105