Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1239)

Unified Diff: netlog_viewer/timeline_data_series.js

Issue 2162963002: [polymer] Merge of master into polymer10-migration (Closed) Base URL: git@github.com:catapult-project/catapult.git@polymer10-migration
Patch Set: Merge polymer10-migration int polymer10-merge Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « netlog_viewer/time_util.js ('k') | netlog_viewer/timeline_graph_view.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: netlog_viewer/timeline_data_series.js
diff --git a/netlog_viewer/timeline_data_series.js b/netlog_viewer/timeline_data_series.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef4573fd9e8b5f259390f561e7b86721b1861b17
--- /dev/null
+++ b/netlog_viewer/timeline_data_series.js
@@ -0,0 +1,369 @@
+// Copyright (c) 2012 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.
+
+/**
+ * Different data types that each require their own labelled axis.
+ */
+var TimelineDataType = {
+ SOURCE_COUNT: 0,
+ BYTES_PER_SECOND: 1
+};
+
+/**
+ * A TimelineDataSeries collects an ordered series of (time, value) pairs,
+ * and converts them to graph points. It also keeps track of its color and
+ * current visibility state. DataSeries are solely responsible for tracking
+ * data, and do not send notifications on state changes.
+ *
+ * Abstract class, doesn't implement onReceivedLogEntry.
+ */
+var TimelineDataSeries = (function() {
+ 'use strict';
+
+ /**
+ * @constructor
+ */
+ function TimelineDataSeries(dataType) {
+ // List of DataPoints in chronological order.
+ this.dataPoints_ = [];
+
+ // Data type of the DataSeries. This is used to scale all values with
+ // the same units in the same way.
+ this.dataType_ = dataType;
+ // Default color. Should always be overridden prior to display.
+ this.color_ = 'red';
+ // Whether or not the data series should be drawn.
+ this.isVisible_ = false;
+
+ this.cacheStartTime_ = null;
+ this.cacheStepSize_ = 0;
+ this.cacheValues_ = [];
+ }
+
+ TimelineDataSeries.prototype = {
+ /**
+ * Adds a DataPoint to |this| with the specified time and value.
+ * DataPoints are assumed to be received in chronological order.
+ */
+ addPoint: function(timeTicks, value) {
+ var time = timeutil.convertTimeTicksToDate(timeTicks).getTime();
+ this.dataPoints_.push(new DataPoint(time, value));
+ },
+
+ isVisible: function() {
+ return this.isVisible_;
+ },
+
+ show: function(isVisible) {
+ this.isVisible_ = isVisible;
+ },
+
+ getColor: function() {
+ return this.color_;
+ },
+
+ setColor: function(color) {
+ this.color_ = color;
+ },
+
+ getDataType: function() {
+ return this.dataType_;
+ },
+
+ /**
+ * Returns a list containing the values of the data series at |count|
+ * points, starting at |startTime|, and |stepSize| milliseconds apart.
+ * Caches values, so showing/hiding individual data series is fast, and
+ * derived data series can be efficiently computed, if we add any.
+ */
+ getValues: function(startTime, stepSize, count) {
+ // Use cached values, if we can.
+ if (this.cacheStartTime_ == startTime &&
+ this.cacheStepSize_ == stepSize &&
+ this.cacheValues_.length == count) {
+ return this.cacheValues_;
+ }
+
+ // Do all the work.
+ this.cacheValues_ = this.getValuesInternal_(startTime, stepSize, count);
+ this.cacheStartTime_ = startTime;
+ this.cacheStepSize_ = stepSize;
+
+ return this.cacheValues_;
+ },
+
+ /**
+ * Does all the work of getValues when we can't use cached data.
+ *
+ * The default implementation just uses the |value| of the most recently
+ * seen DataPoint before each time, but other DataSeries may use some
+ * form of interpolation.
+ * TODO(mmenke): Consider returning the maximum value over each interval
+ * to create graphs more stable with respect to zooming.
+ */
+ getValuesInternal_: function(startTime, stepSize, count) {
+ var values = [];
+ var nextPoint = 0;
+ var currentValue = 0;
+ var time = startTime;
+ for (var i = 0; i < count; ++i) {
+ while (nextPoint < this.dataPoints_.length &&
+ this.dataPoints_[nextPoint].time < time) {
+ currentValue = this.dataPoints_[nextPoint].value;
+ ++nextPoint;
+ }
+ values[i] = currentValue;
+ time += stepSize;
+ }
+ return values;
+ }
+ };
+
+ /**
+ * A single point in a data series. Each point has a time, in the form of
+ * milliseconds since the Unix epoch, and a numeric value.
+ * @constructor
+ */
+ function DataPoint(time, value) {
+ this.time = time;
+ this.value = value;
+ }
+
+ return TimelineDataSeries;
+})();
+
+/**
+ * Tracks how many sources of the given type have seen a begin
+ * event of type |eventType| more recently than an end event.
+ */
+var SourceCountDataSeries = (function() {
+ 'use strict';
+
+ var superClass = TimelineDataSeries;
+
+ /**
+ * @constructor
+ */
+ function SourceCountDataSeries(sourceType, eventType) {
+ superClass.call(this, TimelineDataType.SOURCE_COUNT);
+ this.sourceType_ = sourceType;
+ this.eventType_ = eventType;
+
+ // Map of sources for which we've seen a begin event more recently than an
+ // end event. Each such source has a value of "true". All others are
+ // undefined.
+ this.activeSources_ = {};
+ // Number of entries in |activeSources_|.
+ this.activeCount_ = 0;
+ }
+
+ SourceCountDataSeries.prototype = {
+ // Inherit the superclass's methods.
+ __proto__: superClass.prototype,
+
+ onReceivedLogEntry: function(entry) {
+ if (entry.source.type != this.sourceType_ ||
+ entry.type != this.eventType_) {
+ return;
+ }
+
+ if (entry.phase == EventPhase.PHASE_BEGIN) {
+ this.onBeginEvent(entry.source.id, entry.time);
+ return;
+ }
+ if (entry.phase == EventPhase.PHASE_END)
+ this.onEndEvent(entry.source.id, entry.time);
+ },
+
+ /**
+ * Called when the source with the specified id begins doing whatever we
+ * care about. If it's not already an active source, we add it to the map
+ * and add a data point.
+ */
+ onBeginEvent: function(id, time) {
+ if (this.activeSources_[id])
+ return;
+ this.activeSources_[id] = true;
+ ++this.activeCount_;
+ this.addPoint(time, this.activeCount_);
+ },
+
+ /**
+ * Called when the source with the specified id stops doing whatever we
+ * care about. If it's an active source, we remove it from the map and add
+ * a data point.
+ */
+ onEndEvent: function(id, time) {
+ if (!this.activeSources_[id])
+ return;
+ delete this.activeSources_[id];
+ --this.activeCount_;
+ this.addPoint(time, this.activeCount_);
+ }
+ };
+
+ return SourceCountDataSeries;
+})();
+
+/**
+ * Tracks the number of sockets currently in use. Needs special handling of
+ * SSL sockets, so can't just use a normal SourceCountDataSeries.
+ */
+var SocketsInUseDataSeries = (function() {
+ 'use strict';
+
+ var superClass = SourceCountDataSeries;
+
+ /**
+ * @constructor
+ */
+ function SocketsInUseDataSeries() {
+ superClass.call(this, EventSourceType.SOCKET, EventType.SOCKET_IN_USE);
+ }
+
+ SocketsInUseDataSeries.prototype = {
+ // Inherit the superclass's methods.
+ __proto__: superClass.prototype,
+
+ onReceivedLogEntry: function(entry) {
+ // SSL sockets have two nested SOCKET_IN_USE events. This is needed to
+ // mark SSL sockets as unused after SSL negotiation.
+ if (entry.type == EventType.SSL_CONNECT &&
+ entry.phase == EventPhase.PHASE_END) {
+ this.onEndEvent(entry.source.id, entry.time);
+ return;
+ }
+ superClass.prototype.onReceivedLogEntry.call(this, entry);
+ }
+ };
+
+ return SocketsInUseDataSeries;
+})();
+
+/**
+ * Tracks approximate data rate using individual data transfer events.
+ * Abstract class, doesn't implement onReceivedLogEntry.
+ */
+var TransferRateDataSeries = (function() {
+ 'use strict';
+
+ var superClass = TimelineDataSeries;
+
+ /**
+ * @constructor
+ */
+ function TransferRateDataSeries() {
+ superClass.call(this, TimelineDataType.BYTES_PER_SECOND);
+ }
+
+ TransferRateDataSeries.prototype = {
+ // Inherit the superclass's methods.
+ __proto__: superClass.prototype,
+
+ /**
+ * Returns the average data rate over each interval, only taking into
+ * account transfers that occurred within each interval.
+ * TODO(mmenke): Do something better.
+ */
+ getValuesInternal_: function(startTime, stepSize, count) {
+ // Find the first DataPoint after |startTime| - |stepSize|.
+ var nextPoint = 0;
+ while (nextPoint < this.dataPoints_.length &&
+ this.dataPoints_[nextPoint].time < startTime - stepSize) {
+ ++nextPoint;
+ }
+
+ var values = [];
+ var time = startTime;
+ for (var i = 0; i < count; ++i) {
+ // Calculate total bytes transferred from |time| - |stepSize|
+ // to |time|. We look at the transfers before |time| to give
+ // us generally non-varying values for a given time.
+ var transferred = 0;
+ while (nextPoint < this.dataPoints_.length &&
+ this.dataPoints_[nextPoint].time < time) {
+ transferred += this.dataPoints_[nextPoint].value;
+ ++nextPoint;
+ }
+ // Calculate bytes per second.
+ values[i] = 1000 * transferred / stepSize;
+ time += stepSize;
+ }
+ return values;
+ }
+ };
+
+ return TransferRateDataSeries;
+})();
+
+/**
+ * Tracks TCP and UDP transfer rate.
+ */
+var NetworkTransferRateDataSeries = (function() {
+ 'use strict';
+
+ var superClass = TransferRateDataSeries;
+
+ /**
+ * |tcpEvent| and |udpEvent| are the event types for data transfers using
+ * TCP and UDP, respectively.
+ * @constructor
+ */
+ function NetworkTransferRateDataSeries(tcpEvent, udpEvent) {
+ superClass.call(this);
+ this.tcpEvent_ = tcpEvent;
+ this.udpEvent_ = udpEvent;
+ }
+
+ NetworkTransferRateDataSeries.prototype = {
+ // Inherit the superclass's methods.
+ __proto__: superClass.prototype,
+
+ onReceivedLogEntry: function(entry) {
+ if (entry.type != this.tcpEvent_ && entry.type != this.udpEvent_)
+ return;
+ this.addPoint(entry.time, entry.params.byte_count);
+ },
+ };
+
+ return NetworkTransferRateDataSeries;
+})();
+
+/**
+ * Tracks disk cache read or write rate. Doesn't include clearing, opening,
+ * or dooming entries, as they don't have clear size values.
+ */
+var DiskCacheTransferRateDataSeries = (function() {
+ 'use strict';
+
+ var superClass = TransferRateDataSeries;
+
+ /**
+ * @constructor
+ */
+ function DiskCacheTransferRateDataSeries(eventType) {
+ superClass.call(this);
+ this.eventType_ = eventType;
+ }
+
+ DiskCacheTransferRateDataSeries.prototype = {
+ // Inherit the superclass's methods.
+ __proto__: superClass.prototype,
+
+ onReceivedLogEntry: function(entry) {
+ if (entry.source.type != EventSourceType.DISK_CACHE_ENTRY ||
+ entry.type != this.eventType_ ||
+ entry.phase != EventPhase.PHASE_END) {
+ return;
+ }
+ // The disk cache has a lot of 0-length writes, when truncating entries.
+ // Ignore those.
+ if (entry.params.bytes_copied != 0)
+ this.addPoint(entry.time, entry.params.bytes_copied);
+ }
+ };
+
+ return DiskCacheTransferRateDataSeries;
+})();
+
« no previous file with comments | « netlog_viewer/time_util.js ('k') | netlog_viewer/timeline_graph_view.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698