1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @param {WebInspector.TimelineModel} model 34 * @param {WebInspector.TimelineOverviewPane} overviewPane 35 * @param {WebInspector.TimelinePresentationModel} presentationModel 36 */ 37 WebInspector.TimelineFrameController = function(model, overviewPane, presentationModel) 38 { 39 this._lastFrame = null; 40 this._model = model; 41 this._overviewPane = overviewPane; 42 this._presentationModel = presentationModel; 43 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this); 44 this._model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this); 45 46 var records = model.records; 47 for (var i = 0; i < records.length; ++i) 48 this._addRecord(records[i]); 49 } 50 51 WebInspector.TimelineFrameController.prototype = { 52 _onRecordAdded: function(event) 53 { 54 this._addRecord(event.data); 55 }, 56 57 _onRecordsCleared: function() 58 { 59 this._lastFrame = null; 60 }, 61 62 _addRecord: function(record) 63 { 64 if (record.isBackground) 65 return; 66 var records; 67 var programRecord; 68 if (record.type === WebInspector.TimelineModel.RecordType.Program) { 69 programRecord = record; 70 if (this._lastFrame) 71 this._lastFrame.timeByCategory["other"] += WebInspector.TimelineModel.durationInSeconds(programRecord); 72 records = record["children"] || []; 73 } else 74 records = [record]; 75 records.forEach(this._innerAddRecord.bind(this, programRecord)); 76 }, 77 78 /** 79 * @param {Object} programRecord 80 * @param {Object} record 81 */ 82 _innerAddRecord: function(programRecord, record) 83 { 84 var isFrameRecord = record.type === WebInspector.TimelineModel.RecordType.BeginFrame; 85 var programTimeCarryover = isFrameRecord && programRecord ? WebInspector.TimelineModel.endTimeInSeconds(programRecord) - WebInspector.TimelineModel.startTimeInSeconds(record) : 0; 86 if (isFrameRecord && this._lastFrame) 87 this._flushFrame(record, programTimeCarryover); 88 else { 89 if (!this._lastFrame) 90 this._lastFrame = this._createFrame(record, programTimeCarryover); 91 if (!record.thread) 92 WebInspector.TimelineModel.aggregateTimeForRecord(this._lastFrame.timeByCategory, record); 93 var duration = WebInspector.TimelineModel.durationInSeconds(record); 94 this._lastFrame.cpuTime += duration; 95 this._lastFrame.timeByCategory["other"] -= duration; 96 } 97 }, 98 99 /** 100 * @param {Object} record 101 * @param {number} programTimeCarryover 102 */ 103 _flushFrame: function(record, programTimeCarryover) 104 { 105 this._lastFrame.endTime = WebInspector.TimelineModel.startTimeInSeconds(record); 106 this._lastFrame.duration = this._lastFrame.endTime - this._lastFrame.startTime; 107 this._lastFrame.timeByCategory["other"] -= programTimeCarryover; 108 // Alternatively, we could compute CPU time as sum of all Program events. 109 // This way it's a bit more flexible, as it works in case there's no program events. 110 this._lastFrame.cpuTime += this._lastFrame.timeByCategory["other"]; 111 this._overviewPane.addFrame(this._lastFrame); 112 this._presentationModel.addFrame(this._lastFrame); 113 this._lastFrame = this._createFrame(record, programTimeCarryover); 114 }, 115 116 /** 117 * @param {Object} record 118 * @param {number} programTimeCarryover 119 */ 120 _createFrame: function(record, programTimeCarryover) 121 { 122 var frame = new WebInspector.TimelineFrame(); 123 frame.startTime = WebInspector.TimelineModel.startTimeInSeconds(record); 124 frame.startTimeOffset = this._model.recordOffsetInSeconds(record); 125 frame.timeByCategory["other"] = programTimeCarryover; 126 return frame; 127 }, 128 129 dispose: function() 130 { 131 this._model.removeEventListener(WebInspector.TimelineModel.Events.RecordAdded, this._onRecordAdded, this); 132 this._model.removeEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this); 133 } 134 } 135 136 /** 137 * @constructor 138 * @param {Array.<WebInspector.TimelineFrame>} frames 139 */ 140 WebInspector.FrameStatistics = function(frames) 141 { 142 this.frameCount = frames.length; 143 this.minDuration = Infinity; 144 this.maxDuration = 0; 145 this.timeByCategory = {}; 146 this.startOffset = frames[0].startTimeOffset; 147 var lastFrame = frames[this.frameCount - 1]; 148 this.endOffset = lastFrame.startTimeOffset + lastFrame.duration; 149 150 var totalDuration = 0; 151 var sumOfSquares = 0; 152 for (var i = 0; i < this.frameCount; ++i) { 153 var duration = frames[i].duration; 154 totalDuration += duration; 155 sumOfSquares += duration * duration; 156 this.minDuration = Math.min(this.minDuration, duration); 157 this.maxDuration = Math.max(this.maxDuration, duration); 158 WebInspector.TimelineModel.aggregateTimeByCategory(this.timeByCategory, frames[i].timeByCategory); 159 } 160 this.average = totalDuration / this.frameCount; 161 var variance = sumOfSquares / this.frameCount - this.average * this.average; 162 this.stddev = Math.sqrt(variance); 163 } 164 165 /** 166 * @constructor 167 */ 168 WebInspector.TimelineFrame = function() 169 { 170 this.timeByCategory = {}; 171 this.cpuTime = 0; 172 } 173