1<!DOCTYPE html>
2<!--
3Copyright (c) 2013 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/model/counter_series.html">
9<link rel="import" href="/tracing/model/event_container.html">
10<link rel="import" href="/tracing/base/guid.html">
11<link rel="import" href="/tracing/base/range.html">
12
13<script>
14'use strict';
15
16tr.exportTo('tr.model', function() {
17
18  /**
19   * A container holding all series of a given type of measurement.
20   *
21   * As an example, if we're measuring the throughput of data sent over several
22   * USB connections, the throughput of each cable might be added as a separate
23   * series to a single counter.
24   *
25   * @constructor
26   * @extends {EventContainer}
27   */
28  function Counter(parent, id, category, name) {
29    tr.model.EventContainer.call(this);
30
31    this.parent_ = parent;
32    this.id_ = id;
33    this.category_ = category || '';
34    this.name_ = name;
35
36    this.series_ = [];
37    this.totals = [];
38  }
39
40  Counter.prototype = {
41    __proto__: tr.model.EventContainer.prototype,
42
43    get parent() {
44      return this.parent_;
45    },
46
47    get id() {
48      return this.id_;
49    },
50
51    get category() {
52      return this.category_;
53    },
54
55    get name() {
56      return this.name_;
57    },
58
59    iterateAllEventsInThisContainer: function(eventTypePredicate,
60                                              callback, opt_this) {
61    },
62
63    iterateAllChildEventContainers: function(callback, opt_this) {
64      for (var i = 0; i < this.series_.length; i++)
65        callback.call(opt_this, this.series_[i]);
66    },
67
68    set timestamps(arg) {
69      throw new Error('Bad counter API. No cookie.');
70    },
71
72    set seriesNames(arg) {
73      throw new Error('Bad counter API. No cookie.');
74    },
75
76    set seriesColors(arg) {
77      throw new Error('Bad counter API. No cookie.');
78    },
79
80    set samples(arg) {
81      throw new Error('Bad counter API. No cookie.');
82    },
83
84    addSeries: function(series) {
85      series.counter = this;
86      series.seriesIndex = this.series_.length;
87      this.series_.push(series);
88      return series;
89    },
90
91    getSeries: function(idx) {
92      return this.series_[idx];
93    },
94
95    get series() {
96      return this.series_;
97    },
98
99    get numSeries() {
100      return this.series_.length;
101    },
102
103    get numSamples() {
104      if (this.series_.length === 0)
105        return 0;
106      return this.series_[0].length;
107    },
108
109    get timestamps() {
110      if (this.series_.length === 0)
111        return [];
112      return this.series_[0].timestamps;
113    },
114
115    /**
116     * Obtains min, max, avg, values, start, and end for different series for
117     * a given counter
118     *     getSampleStatistics([0,1])
119     * The statistics objects that this returns are an array of objects, one
120     * object for each series for the counter in the form:
121     * {min: minVal, max: maxVal, avg: avgVal, start: startVal, end: endVal}
122     *
123     * @param {Array.<Number>} Indices to summarize.
124     * @return {Object} An array of statistics. Each element in the array
125     * has data for one of the series in the selected counter.
126     */
127    getSampleStatistics: function(sampleIndices) {
128      sampleIndices.sort();
129
130      var ret = [];
131      this.series_.forEach(function(series) {
132        ret.push(series.getStatistics(sampleIndices));
133      });
134      return ret;
135    },
136
137    /**
138     * Shifts all the timestamps inside this counter forward by the amount
139     * specified.
140     */
141    shiftTimestampsForward: function(amount) {
142      for (var i = 0; i < this.series_.length; ++i)
143        this.series_[i].shiftTimestampsForward(amount);
144    },
145
146    /**
147     * Updates the bounds for this counter based on the samples it contains.
148     */
149    updateBounds: function() {
150      this.totals = [];
151      this.maxTotal = 0;
152      this.bounds.reset();
153
154      if (this.series_.length === 0)
155        return;
156
157      var firstSeries = this.series_[0];
158      var lastSeries = this.series_[this.series_.length - 1];
159
160      this.bounds.addValue(firstSeries.getTimestamp(0));
161      this.bounds.addValue(lastSeries.getTimestamp(lastSeries.length - 1));
162
163      var numSeries = this.numSeries;
164      this.maxTotal = -Infinity;
165
166      // Sum the samples at each timestamp.
167      // Note, this assumes that all series have all timestamps.
168      for (var i = 0; i < firstSeries.length; ++i) {
169        var total = 0;
170        this.series_.forEach(function(series) {
171          total += series.getSample(i).value;
172          this.totals.push(total);
173        }.bind(this));
174
175        this.maxTotal = Math.max(total, this.maxTotal);
176      }
177    }
178  };
179
180  /**
181   * Comparison between counters that orders by parent.compareTo, then name.
182   */
183  Counter.compare = function(x, y) {
184    var tmp = x.parent.compareTo(y);
185    if (tmp != 0)
186      return tmp;
187    var tmp = x.name.localeCompare(y.name);
188    if (tmp == 0)
189      return x.tid - y.tid;
190    return tmp;
191  };
192
193  return {
194    Counter: Counter
195  };
196});
197</script>
198