Chromium Code Reviews| Index: chrome/browser/resources/net_internals/timeline_data_series.js |
| =================================================================== |
| --- chrome/browser/resources/net_internals/timeline_data_series.js (revision 0) |
| +++ chrome/browser/resources/net_internals/timeline_data_series.js (revision 0) |
| @@ -0,0 +1,369 @@ |
| +// Copyright (c) 2011 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; |
| + }, |
| + |
| + color: function() { |
|
eroman
2011/11/16 04:03:46
nit: for consistency, I suggest calling this getCo
mmenke
2011/11/16 18:39:35
Done.
|
| + return this.color_; |
| + }, |
| + |
| + setColor: function(color) { |
| + this.color_ = color; |
| + }, |
| + |
| + dataType: function() { |
|
eroman
2011/11/16 04:03:46
nit: for consistency I suggest calling this getDat
mmenke
2011/11/16 18:39:35
Done.
|
| + return this.dataType_; |
| + }, |
| + |
| + /** |
| + * Takes in a list of 2 or more times, in increasing order and equally |
| + * spaced, and returns the value of the data series at each point. |
| + * 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 in a range, to get |
| + * 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 a corresponding |
| + * 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 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 sources in the previous list. |
| + 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 == LogEventPhase.PHASE_BEGIN) { |
| + this.onBeginEvent(entry.source.id, entry.time); |
| + return; |
| + } |
| + if (entry.phase == LogEventPhase.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, LogSourceType.SOCKET, LogEventType.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 == LogEventType.SSL_CONNECT && |
| + entry.phase == LogEventPhase.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. |
|
eroman
2011/11/16 04:03:46
I have been having a hard time figuring exactly ho
mmenke
2011/11/16 18:39:35
Averaging over a time range is probably the right
|
| + */ |
| + 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 combined 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 != LogSourceType.DISK_CACHE_ENTRY || |
| + entry.type != this.eventType_ || |
| + entry.phase != LogEventPhase.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; |
| +})(); |
| Property changes on: chrome\browser\resources\net_internals\timeline_data_series.js |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |