2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * @extends {WebInspector.Object}
35 * @param {!WebInspector.TimelineModel} model
36 * @param {!WebInspector.TimelineUIUtils} uiUtils
38 WebInspector.TimelinePresentationModel = function(model, uiUtils)
41 this._uiUtils = uiUtils;
44 * @type {!Map.<!WebInspector.TimelineModel.Record, !WebInspector.TimelinePresentationModel.Record>}
46 this._recordToPresentationRecord = new Map();
50 WebInspector.TimelinePresentationModel.prototype = {
52 * @param {number} startTime
53 * @param {number} endTime
55 setWindowTimes: function(startTime, endTime)
57 this._windowStartTime = startTime;
58 this._windowEndTime = endTime;
62 * @param {?WebInspector.TimelineModel.Record} record
63 * @return {?WebInspector.TimelinePresentationModel.Record}
65 toPresentationRecord: function(record)
67 return record ? this._recordToPresentationRecord.get(record) || null : null;
71 * @return {!WebInspector.TimelinePresentationModel.Record}
73 rootRecord: function()
75 return this._rootRecord;
80 this._recordToPresentationRecord.clear();
81 this._rootRecord = new WebInspector.TimelinePresentationModel.RootRecord();
82 /** @type {!Object.<string, !WebInspector.TimelinePresentationModel.Record>} */
83 this._coalescingBuckets = {};
87 * @param {!WebInspector.TimelineModel.Record} record
89 addRecord: function(record)
91 if (this._uiUtils.isProgram(record)) {
92 var records = record.children();
93 for (var i = 0; i < records.length; ++i)
94 this._innerAddRecord(this._rootRecord, records[i]);
96 this._innerAddRecord(this._rootRecord, record);
101 * @param {!WebInspector.TimelinePresentationModel.Record} parentRecord
102 * @param {!WebInspector.TimelineModel.Record} record
104 _innerAddRecord: function(parentRecord, record)
106 var coalescingBucket;
108 // On main thread, only coalesce if the last event is of same type.
109 if (parentRecord === this._rootRecord)
110 coalescingBucket = record.thread() ? record.type() : "mainThread";
111 var coalescedRecord = this._findCoalescedParent(record, parentRecord, coalescingBucket);
113 parentRecord = coalescedRecord;
115 var formattedRecord = new WebInspector.TimelinePresentationModel.ActualRecord(record, parentRecord);
116 this._recordToPresentationRecord.set(record, formattedRecord);
118 formattedRecord._collapsed = parentRecord === this._rootRecord;
119 if (coalescingBucket)
120 this._coalescingBuckets[coalescingBucket] = formattedRecord;
122 for (var i = 0; record.children() && i < record.children().length; ++i)
123 this._innerAddRecord(formattedRecord, record.children()[i]);
125 if (parentRecord.coalesced())
126 this._updateCoalescingParent(formattedRecord);
130 * @param {!WebInspector.TimelineModel.Record} record
131 * @param {!WebInspector.TimelinePresentationModel.Record} newParent
132 * @param {string=} bucket
133 * @return {?WebInspector.TimelinePresentationModel.Record}
135 _findCoalescedParent: function(record, newParent, bucket)
137 const coalescingThresholdMillis = 5;
139 var lastRecord = bucket ? this._coalescingBuckets[bucket] : newParent._presentationChildren.peekLast();
140 if (lastRecord && lastRecord.coalesced())
141 lastRecord = lastRecord._presentationChildren.peekLast();
142 var startTime = record.startTime();
143 var endTime = record.endTime();
146 if (lastRecord.record().type() !== record.type())
148 if (!this._uiUtils.isCoalescable(record.type()))
150 if (lastRecord.record().endTime() + coalescingThresholdMillis < startTime)
152 if (endTime + coalescingThresholdMillis < lastRecord.record().startTime())
154 if (lastRecord.presentationParent().coalesced())
155 return lastRecord.presentationParent();
156 return this._replaceWithCoalescedRecord(lastRecord);
160 * @param {!WebInspector.TimelinePresentationModel.Record} presentationRecord
161 * @return {!WebInspector.TimelinePresentationModel.Record}
163 _replaceWithCoalescedRecord: function(presentationRecord)
165 var record = presentationRecord.record();
166 var parent = presentationRecord._presentationParent;
167 var coalescedRecord = new WebInspector.TimelinePresentationModel.CoalescedRecord(record);
169 coalescedRecord._collapsed = true;
170 coalescedRecord._presentationChildren.push(presentationRecord);
171 presentationRecord._presentationParent = coalescedRecord;
172 if (presentationRecord.hasWarnings() || presentationRecord.childHasWarnings())
173 coalescedRecord._childHasWarnings = true;
175 coalescedRecord._presentationParent = parent;
176 parent._presentationChildren[parent._presentationChildren.indexOf(presentationRecord)] = coalescedRecord;
178 return coalescedRecord;
182 * @param {!WebInspector.TimelinePresentationModel.Record} presentationRecord
184 _updateCoalescingParent: function(presentationRecord)
186 var parentRecord = presentationRecord._presentationParent;
187 if (parentRecord.endTime() < presentationRecord.endTime())
188 parentRecord._endTime = presentationRecord.endTime();
192 * @param {?RegExp} textFilter
194 setTextFilter: function(textFilter)
196 var records = this._recordToPresentationRecord.values();
197 for (var i = 0; i < records.length; ++i)
198 records[i]._expandedOrCollapsedWhileFiltered = false;
199 this._textFilter = textFilter;
202 refreshRecords: function()
205 var modelRecords = this._model.records();
206 for (var i = 0; i < modelRecords.length; ++i)
207 this.addRecord(modelRecords[i]);
210 invalidateFilteredRecords: function()
212 delete this._filteredRecords;
216 * @return {!Array.<!WebInspector.TimelinePresentationModel.Record>}
218 filteredRecords: function()
220 if (this._filteredRecords)
221 return this._filteredRecords;
223 var recordsInWindow = [];
225 var stack = [{children: this._rootRecord._presentationChildren, index: 0, parentIsCollapsed: false, parentRecord: {}}];
226 var revealedDepth = 0;
228 function revealRecordsInStack() {
229 for (var depth = revealedDepth + 1; depth < stack.length; ++depth) {
230 if (stack[depth - 1].parentIsCollapsed) {
231 stack[depth].parentRecord._presentationParent._expandable = true;
234 stack[depth - 1].parentRecord._collapsed = false;
235 recordsInWindow.push(stack[depth].parentRecord);
236 stack[depth].windowLengthBeforeChildrenTraversal = recordsInWindow.length;
237 stack[depth].parentIsRevealed = true;
238 revealedDepth = depth;
242 while (stack.length) {
243 var entry = stack[stack.length - 1];
244 var records = entry.children;
245 if (records && entry.index < records.length) {
246 var record = records[entry.index];
248 if (record.startTime() < this._windowEndTime && record.endTime() > this._windowStartTime) {
249 if (this._model.isVisible(record.record())) {
250 record._presentationParent._expandable = true;
251 if (this._textFilter)
252 revealRecordsInStack();
253 if (!entry.parentIsCollapsed) {
254 recordsInWindow.push(record);
255 revealedDepth = stack.length;
256 entry.parentRecord._collapsed = false;
261 record._expandable = false;
263 stack.push({children: record._presentationChildren,
265 parentIsCollapsed: entry.parentIsCollapsed || (record._collapsed && (!this._textFilter || record._expandedOrCollapsedWhileFiltered)),
266 parentRecord: record,
267 windowLengthBeforeChildrenTraversal: recordsInWindow.length});
270 revealedDepth = Math.min(revealedDepth, stack.length - 1);
271 entry.parentRecord._visibleChildrenCount = recordsInWindow.length - entry.windowLengthBeforeChildrenTraversal;
275 this._filteredRecords = recordsInWindow;
276 return recordsInWindow;
279 __proto__: WebInspector.Object.prototype
284 * @param {?WebInspector.TimelinePresentationModel.Record} parentRecord
286 WebInspector.TimelinePresentationModel.Record = function(parentRecord)
289 * @type {!Array.<!WebInspector.TimelinePresentationModel.Record>}
291 this._presentationChildren = [];
294 this._presentationParent = parentRecord;
295 parentRecord._presentationChildren.push(this);
299 WebInspector.TimelinePresentationModel.Record.prototype = {
303 startTime: function()
305 throw new Error("Not implemented.");
313 throw new Error("Not implemented.");
321 throw new Error("Not implemented.");
325 * @return {!WebInspector.TimelineModel.Record}
329 throw new Error("Not implemented.");
333 * @return {!Array.<!WebInspector.TimelinePresentationModel.Record>}
335 presentationChildren: function()
337 return this._presentationChildren;
343 coalesced: function()
351 collapsed: function()
353 return this._collapsed;
357 * @param {boolean} collapsed
359 setCollapsed: function(collapsed)
361 this._collapsed = collapsed;
362 this._expandedOrCollapsedWhileFiltered = true;
366 * @return {?WebInspector.TimelinePresentationModel.Record}
368 presentationParent: function()
370 return this._presentationParent || null;
376 visibleChildrenCount: function()
378 return this._visibleChildrenCount || 0;
384 expandable: function()
386 return !!this._expandable;
392 hasWarnings: function()
400 childHasWarnings: function()
402 return this._childHasWarnings;
406 * @return {?WebInspector.TimelineRecordListRow}
410 return this._listRow;
414 * @param {!WebInspector.TimelineRecordListRow} listRow
416 setListRow: function(listRow)
418 this._listRow = listRow;
422 * @return {?WebInspector.TimelineRecordGraphRow}
426 return this._graphRow;
430 * @param {!WebInspector.TimelineRecordGraphRow} graphRow
432 setGraphRow: function(graphRow)
434 this._graphRow = graphRow;
440 * @extends {WebInspector.TimelinePresentationModel.Record}
441 * @param {!WebInspector.TimelineModel.Record} record
442 * @param {?WebInspector.TimelinePresentationModel.Record} parentRecord
444 WebInspector.TimelinePresentationModel.ActualRecord = function(record, parentRecord)
446 WebInspector.TimelinePresentationModel.Record.call(this, parentRecord);
447 this._record = record;
449 if (this.hasWarnings()) {
450 for (var parent = this._presentationParent; parent && !parent._childHasWarnings; parent = parent._presentationParent)
451 parent._childHasWarnings = true;
455 WebInspector.TimelinePresentationModel.ActualRecord.prototype = {
459 startTime: function()
461 return this._record.startTime();
469 return this._record.endTime();
477 return this._record.selfTime();
481 * @return {!WebInspector.TimelineModel.Record}
491 hasWarnings: function()
493 return !!this._record.warnings();
496 __proto__: WebInspector.TimelinePresentationModel.Record.prototype
501 * @extends {WebInspector.TimelinePresentationModel.Record}
502 * @param {!WebInspector.TimelineModel.Record} record
504 WebInspector.TimelinePresentationModel.CoalescedRecord = function(record)
506 WebInspector.TimelinePresentationModel.Record.call(this, null);
507 this._startTime = record.startTime();
508 this._endTime = record.endTime();
511 WebInspector.TimelinePresentationModel.CoalescedRecord.prototype = {
515 startTime: function()
517 return this._startTime;
525 return this._endTime;
537 * @return {!WebInspector.TimelineModel.Record}
541 return this._presentationChildren[0].record();
547 coalesced: function()
555 hasWarnings: function()
560 __proto__: WebInspector.TimelinePresentationModel.Record.prototype
565 * @extends {WebInspector.TimelinePresentationModel.Record}
567 WebInspector.TimelinePresentationModel.RootRecord = function()
569 WebInspector.TimelinePresentationModel.Record.call(this, null);
572 WebInspector.TimelinePresentationModel.RootRecord.prototype = {
576 hasWarnings: function()
581 __proto__: WebInspector.TimelinePresentationModel.Record.prototype