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

Side by Side Diff: Source/devtools/front_end/timeline/TimelineModelImpl.js

Issue 709423002: DevTools: remove old Timeline front-end implementation (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Updated LayoutTests/inspector/layers/layer-canvas-log.html Created 6 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @constructor
7 * @extends {WebInspector.TimelineModel}
8 * @implements {WebInspector.TargetManager.Observer}
9 */
10 WebInspector.TimelineModelImpl = function()
11 {
12 WebInspector.TimelineModel.call(this);
13 /** @type {?WebInspector.Target} */
14 this._currentTarget = null;
15 this._filters = [];
16 this._bindings = new WebInspector.TimelineModelImpl.InterRecordBindings();
17
18 this.reset();
19
20 WebInspector.targetManager.addModelListener(WebInspector.TimelineManager, We bInspector.TimelineManager.EventTypes.TimelineEventRecorded, this._onRecordAdded , this);
21 WebInspector.targetManager.addModelListener(WebInspector.TimelineManager, We bInspector.TimelineManager.EventTypes.TimelineStarted, this._onStarted, this);
22 WebInspector.targetManager.addModelListener(WebInspector.TimelineManager, We bInspector.TimelineManager.EventTypes.TimelineStopped, this._onStopped, this);
23 WebInspector.targetManager.addModelListener(WebInspector.TimelineManager, We bInspector.TimelineManager.EventTypes.TimelineProgress, this._onProgress, this);
24 WebInspector.targetManager.observeTargets(this);
25 }
26
27 WebInspector.TimelineModelImpl.TransferChunkLengthBytes = 5000000;
28
29 WebInspector.TimelineModelImpl.prototype = {
30 /**
31 * @param {!WebInspector.Target} target
32 */
33 targetAdded: function(target) { },
34
35 /**
36 * @param {!WebInspector.Target} target
37 */
38 targetRemoved: function(target)
39 {
40 if (this._currentTarget === target)
41 this._currentTarget = null;
42 },
43
44 /**
45 * @param {boolean} captureCauses
46 * @param {boolean} captureMemory
47 * @param {boolean} capturePictures
48 */
49 startRecording: function(captureCauses, captureMemory, capturePictures)
50 {
51 console.assert(!capturePictures, "Legacy timeline does not support captu ring pictures");
52 this.reset();
53 this._currentTarget = WebInspector.context.flavor(WebInspector.Target);
54 console.assert(this._currentTarget);
55
56 this._clientInitiatedRecording = true;
57 var maxStackFrames = captureCauses ? 30 : 0;
58 var includeGPUEvents = Runtime.experiments.isEnabled("gpuTimeline");
59 var liveEvents = [ WebInspector.TimelineModel.RecordType.BeginFrame,
60 WebInspector.TimelineModel.RecordType.DrawFrame,
61 WebInspector.TimelineModel.RecordType.RequestMainThre adFrame,
62 WebInspector.TimelineModel.RecordType.ActivateLayerTr ee ];
63 this._currentTarget.timelineManager.start(maxStackFrames, liveEvents.joi n(","), captureMemory, includeGPUEvents, this._fireRecordingStarted.bind(this));
64 },
65
66 stopRecording: function()
67 {
68 if (!this._currentTarget)
69 return;
70
71 if (!this._clientInitiatedRecording) {
72 this._currentTarget.timelineManager.start(undefined, undefined, unde fined, undefined, stopTimeline.bind(this));
73 return;
74 }
75
76 /**
77 * Console started this one and we are just sniffing it. Initiate record ing so that we
78 * could stop it.
79 * @this {WebInspector.TimelineModelImpl}
80 */
81 function stopTimeline()
82 {
83 this._currentTarget.timelineManager.stop(this._fireRecordingStopped. bind(this));
84 }
85
86 this._clientInitiatedRecording = false;
87 this._currentTarget.timelineManager.stop(this._fireRecordingStopped.bind (this));
88 },
89
90 /**
91 * @return {!Array.<!WebInspector.TimelineModel.Record>}
92 */
93 records: function()
94 {
95 return this._records;
96 },
97
98 /**
99 * @param {!WebInspector.Event} event
100 */
101 _onRecordAdded: function(event)
102 {
103 var timelineManager = /** @type {!WebInspector.TimelineManager} */ (even t.target);
104 if (this._collectionEnabled && timelineManager.target() === this._curren tTarget)
105 this._addRecord(/** @type {!TimelineAgent.TimelineEvent} */(event.da ta));
106 },
107
108 /**
109 * @param {!WebInspector.Event} event
110 */
111 _onStarted: function(event)
112 {
113 if (!event.data || this._collectionEnabled)
114 return;
115 // Started from console.
116 var timelineManager = /** @type {!WebInspector.TimelineManager} */ (even t.target);
117 if (this._currentTarget !== timelineManager.target()) {
118 this.reset();
119 this._currentTarget = timelineManager.target();
120 }
121 this._fireRecordingStarted();
122 },
123
124 /**
125 * @param {!WebInspector.Event} event
126 */
127 _onStopped: function(event)
128 {
129 var timelineManager = /** @type {!WebInspector.TimelineManager} */ (even t.target);
130 if (timelineManager.target() !== this._currentTarget)
131 return;
132 // We were buffering events, discard those that got through, the real on es are coming!
133 this.reset();
134 this._currentTarget = timelineManager.target();
135
136 var events = /** @type {!Array.<!TimelineAgent.TimelineEvent>} */ (event .data.events);
137 for (var i = 0; i < events.length; ++i)
138 this._addRecord(events[i]);
139
140 if (event.data.consoleTimeline) {
141 // Stopped from console.
142 this._fireRecordingStopped(null);
143 }
144
145 this._collectionEnabled = false;
146 },
147
148 /**
149 * @param {!WebInspector.Event} event
150 */
151 _onProgress: function(event)
152 {
153 var timelineManager = /** @type {!WebInspector.TimelineManager} */ (even t.target);
154 if (timelineManager.target() === this._currentTarget)
155 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Reco rdingProgress, event.data);
156 },
157
158 _fireRecordingStarted: function()
159 {
160 this._collectionEnabled = true;
161 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin gStarted);
162 },
163
164 /**
165 * @param {?Protocol.Error} error
166 */
167 _fireRecordingStopped: function(error)
168 {
169 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin gStopped);
170 },
171
172 /**
173 * @param {!TimelineAgent.TimelineEvent} payload
174 */
175 _addRecord: function(payload)
176 {
177 this._internStrings(payload);
178 this._payloads.push(payload);
179
180 var record = this._innerAddRecord(payload, null);
181 this._updateBoundaries(record);
182 this._records.push(record);
183 if (record.type() === WebInspector.TimelineModel.RecordType.Program)
184 this._mainThreadTasks.push(record);
185 if (record.type() === WebInspector.TimelineModel.RecordType.GPUTask)
186 this._gpuThreadTasks.push(record);
187
188 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordAd ded, record);
189 },
190
191 /**
192 * @param {!TimelineAgent.TimelineEvent} payload
193 * @param {?WebInspector.TimelineModel.Record} parentRecord
194 * @return {!WebInspector.TimelineModel.Record}
195 */
196 _innerAddRecord: function(payload, parentRecord)
197 {
198 var record = new WebInspector.TimelineModel.RecordImpl(this, payload, pa rentRecord);
199 if (WebInspector.TimelineUIUtilsImpl.isEventDivider(record))
200 this._eventDividerRecords.push(record);
201
202 for (var i = 0; payload.children && i < payload.children.length; ++i)
203 this._innerAddRecord.call(this, payload.children[i], record);
204
205 if (parentRecord)
206 parentRecord._selfTime -= record.endTime() - record.startTime();
207 return record;
208 },
209
210 /**
211 * @param {!WebInspector.ChunkedFileReader} fileReader
212 * @param {!WebInspector.Progress} progress
213 * @return {!WebInspector.OutputStream}
214 */
215 createLoader: function(fileReader, progress)
216 {
217 return new WebInspector.TimelineModelLoader(this, fileReader, progress);
218 },
219
220 /**
221 * @param {!WebInspector.OutputStream} stream
222 */
223 writeToStream: function(stream)
224 {
225 var saver = new WebInspector.TimelineSaver(stream);
226 saver.save(this._payloads, window.navigator.appVersion);
227 },
228
229 reset: function()
230 {
231 if (!this._collectionEnabled)
232 this._currentTarget = null;
233 this._payloads = [];
234 this._stringPool = {};
235 this._bindings._reset();
236 this._minimumRecordTime = 0;
237 this._maximumRecordTime = 0;
238 WebInspector.TimelineModel.prototype.reset.call(this);
239 },
240
241 /**
242 * @return {number}
243 */
244 minimumRecordTime: function()
245 {
246 return this._minimumRecordTime;
247 },
248
249 /**
250 * @return {number}
251 */
252 maximumRecordTime: function()
253 {
254 return this._maximumRecordTime;
255 },
256
257 /**
258 * @param {!WebInspector.TimelineModel.Record} record
259 */
260 _updateBoundaries: function(record)
261 {
262 var startTime = record.startTime();
263 var endTime = record.endTime();
264
265 if (!this._minimumRecordTime || startTime < this._minimumRecordTime)
266 this._minimumRecordTime = startTime;
267 if (endTime > this._maximumRecordTime)
268 this._maximumRecordTime = endTime;
269 },
270
271 /**
272 * @param {!TimelineAgent.TimelineEvent} record
273 */
274 _internStrings: function(record)
275 {
276 for (var name in record) {
277 var value = record[name];
278 if (typeof value !== "string")
279 continue;
280
281 var interned = this._stringPool[value];
282 if (typeof interned === "string")
283 record[name] = interned;
284 else
285 this._stringPool[value] = value;
286 }
287
288 var children = record.children;
289 for (var i = 0; children && i < children.length; ++i)
290 this._internStrings(children[i]);
291 },
292
293 __proto__: WebInspector.TimelineModel.prototype
294 }
295
296
297 /**
298 * @constructor
299 */
300 WebInspector.TimelineModelImpl.InterRecordBindings = function() {
301 this._reset();
302 }
303
304 WebInspector.TimelineModelImpl.InterRecordBindings.prototype = {
305 _reset: function()
306 {
307 this._sendRequestRecords = {};
308 this._timerRecords = {};
309 this._requestAnimationFrameRecords = {};
310 this._layoutInvalidate = {};
311 this._lastScheduleStyleRecalculation = {};
312 this._webSocketCreateRecords = {};
313 }
314 }
315
316 /**
317 * @constructor
318 * @implements {WebInspector.TimelineModel.Record}
319 * @param {!WebInspector.TimelineModel} model
320 * @param {!TimelineAgent.TimelineEvent} timelineEvent
321 * @param {?WebInspector.TimelineModel.Record} parentRecord
322 */
323 WebInspector.TimelineModel.RecordImpl = function(model, timelineEvent, parentRec ord)
324 {
325 this._model = model;
326 var bindings = this._model._bindings;
327 this._record = timelineEvent;
328 this._thread = this._record.thread || WebInspector.TimelineModel.MainThreadN ame;
329 this._children = [];
330 if (parentRecord) {
331 this.parent = parentRecord;
332 parentRecord.children().push(this);
333 }
334
335 this._selfTime = this.endTime() - this.startTime();
336
337 var recordTypes = WebInspector.TimelineModel.RecordType;
338 switch (timelineEvent.type) {
339 case recordTypes.ResourceSendRequest:
340 // Make resource receive record last since request was sent; make finish record last since response received.
341 bindings._sendRequestRecords[timelineEvent.data["requestId"]] = this;
342 break;
343
344 case recordTypes.ResourceReceiveResponse:
345 case recordTypes.ResourceReceivedData:
346 case recordTypes.ResourceFinish:
347 this._initiator = bindings._sendRequestRecords[timelineEvent.data["reque stId"]];
348 break;
349
350 case recordTypes.TimerInstall:
351 bindings._timerRecords[timelineEvent.data["timerId"]] = this;
352 break;
353
354 case recordTypes.TimerFire:
355 this._initiator = bindings._timerRecords[timelineEvent.data["timerId"]];
356 break;
357
358 case recordTypes.RequestAnimationFrame:
359 bindings._requestAnimationFrameRecords[timelineEvent.data["id"]] = this;
360 break;
361
362 case recordTypes.FireAnimationFrame:
363 this._initiator = bindings._requestAnimationFrameRecords[timelineEvent.d ata["id"]];
364 break;
365
366 case recordTypes.ScheduleStyleRecalculation:
367 bindings._lastScheduleStyleRecalculation[this.frameId()] = this;
368 break;
369
370 case recordTypes.RecalculateStyles:
371 this._initiator = bindings._lastScheduleStyleRecalculation[this.frameId( )];
372 break;
373
374 case recordTypes.InvalidateLayout:
375 // Consider style recalculation as a reason for layout invalidation,
376 // but only if we had no earlier layout invalidation records.
377 var layoutInitator = this;
378 if (!bindings._layoutInvalidate[this.frameId()] && parentRecord.type() = == recordTypes.RecalculateStyles)
379 layoutInitator = parentRecord._initiator;
380 bindings._layoutInvalidate[this.frameId()] = layoutInitator;
381 break;
382
383 case recordTypes.Layout:
384 this._initiator = bindings._layoutInvalidate[this.frameId()];
385 bindings._layoutInvalidate[this.frameId()] = null;
386 if (this.stackTrace())
387 this.addWarning(WebInspector.UIString("Forced synchronous layout is a possible performance bottleneck."));
388 break;
389
390 case recordTypes.WebSocketCreate:
391 bindings._webSocketCreateRecords[timelineEvent.data["identifier"]] = thi s;
392 break;
393
394 case recordTypes.WebSocketSendHandshakeRequest:
395 case recordTypes.WebSocketReceiveHandshakeResponse:
396 case recordTypes.WebSocketDestroy:
397 this._initiator = bindings._webSocketCreateRecords[timelineEvent.data["i dentifier"]];
398 break;
399 }
400 }
401
402 WebInspector.TimelineModel.RecordImpl.prototype = {
403 /**
404 * @return {?Array.<!ConsoleAgent.CallFrame>}
405 */
406 callSiteStackTrace: function()
407 {
408 return this._initiator ? this._initiator.stackTrace() : null;
409 },
410
411 /**
412 * @return {?WebInspector.TimelineModel.Record}
413 */
414 initiator: function()
415 {
416 return this._initiator;
417 },
418
419 /**
420 * @return {?WebInspector.Target}
421 */
422 target: function()
423 {
424 return this._model._currentTarget;
425 },
426
427 /**
428 * @return {number}
429 */
430 selfTime: function()
431 {
432 return this._selfTime;
433 },
434
435 /**
436 * @return {!Array.<!WebInspector.TimelineModel.Record>}
437 */
438 children: function()
439 {
440 return this._children;
441 },
442
443 /**
444 * @return {number}
445 */
446 startTime: function()
447 {
448 return this._record.startTime;
449 },
450
451 /**
452 * @return {string}
453 */
454 thread: function()
455 {
456 return this._thread;
457 },
458
459 /**
460 * @return {number}
461 */
462 endTime: function()
463 {
464 return this._endTime || this._record.endTime || this._record.startTime;
465 },
466
467 /**
468 * @param {number} endTime
469 */
470 setEndTime: function(endTime)
471 {
472 this._endTime = endTime;
473 },
474
475 /**
476 * @return {!Object}
477 */
478 data: function()
479 {
480 return this._record.data;
481 },
482
483 /**
484 * @return {string}
485 */
486 type: function()
487 {
488 return this._record.type;
489 },
490
491 /**
492 * @return {string}
493 */
494 frameId: function()
495 {
496 return this._record.frameId || "";
497 },
498
499 /**
500 * @return {?Array.<!ConsoleAgent.CallFrame>}
501 */
502 stackTrace: function()
503 {
504 if (this._record.stackTrace && this._record.stackTrace.length)
505 return this._record.stackTrace;
506 return null;
507 },
508
509 /**
510 * @param {string} key
511 * @return {?Object}
512 */
513 getUserObject: function(key)
514 {
515 if (!this._userObjects)
516 return null;
517 return this._userObjects.get(key);
518 },
519
520 /**
521 * @param {string} key
522 * @param {?Object|undefined} value
523 */
524 setUserObject: function(key, value)
525 {
526 if (!this._userObjects)
527 this._userObjects = new Map();
528 this._userObjects.set(key, value);
529 },
530
531 /**
532 * @param {string} message
533 */
534 addWarning: function(message)
535 {
536 if (!this._warnings)
537 this._warnings = [];
538 this._warnings.push(message);
539 },
540
541 /**
542 * @return {?Array.<string>}
543 */
544 warnings: function()
545 {
546 return this._warnings;
547 }
548 }
549
550 /**
551 * @constructor
552 * @implements {WebInspector.OutputStream}
553 * @param {!WebInspector.TimelineModel} model
554 * @param {!{cancel: function()}} reader
555 * @param {!WebInspector.Progress} progress
556 */
557 WebInspector.TimelineModelLoader = function(model, reader, progress)
558 {
559 this._model = model;
560 this._reader = reader;
561 this._progress = progress;
562 this._buffer = "";
563 this._firstChunk = true;
564 }
565
566 WebInspector.TimelineModelLoader.prototype = {
567 /**
568 * @param {string} chunk
569 */
570 write: function(chunk)
571 {
572 var data = this._buffer + chunk;
573 var lastIndex = 0;
574 var index;
575 do {
576 index = lastIndex;
577 lastIndex = WebInspector.TextUtils.findBalancedCurlyBrackets(data, i ndex);
578 } while (lastIndex !== -1)
579
580 var json = data.slice(0, index) + "]";
581 this._buffer = data.slice(index);
582
583 if (!index)
584 return;
585
586 if (this._firstChunk) {
587 this._firstChunk = false;
588 this._model.reset();
589 } else {
590 // Prepending "0" to turn string into valid JSON.
591 json = "[0" + json;
592 }
593
594 var items;
595 try {
596 items = /** @type {!Array.<!TimelineAgent.TimelineEvent>} */ (JSON.p arse(json));
597 } catch (e) {
598 WebInspector.console.error("Malformed timeline data.");
599 this._model.reset();
600 this._reader.cancel();
601 this._progress.done();
602 return;
603 }
604
605 // Skip 0-th element - it is either version or 0.
606 for (var i = 1, size = items.length; i < size; ++i)
607 this._model._addRecord(items[i]);
608 },
609
610 close: function()
611 {
612 }
613 }
614
615 /**
616 * @constructor
617 * @param {!WebInspector.OutputStream} stream
618 */
619 WebInspector.TimelineSaver = function(stream)
620 {
621 this._stream = stream;
622 }
623
624 WebInspector.TimelineSaver.prototype = {
625 /**
626 * @param {!Array.<*>} payloads
627 * @param {string} version
628 */
629 save: function(payloads, version)
630 {
631 this._payloads = payloads;
632 this._recordIndex = 0;
633 this._prologue = "[" + JSON.stringify(version);
634
635 this._writeNextChunk(this._stream);
636 },
637
638 _writeNextChunk: function(stream)
639 {
640 const separator = ",\n";
641 var data = [];
642 var length = 0;
643
644 if (this._prologue) {
645 data.push(this._prologue);
646 length += this._prologue.length;
647 delete this._prologue;
648 } else {
649 if (this._recordIndex === this._payloads.length) {
650 stream.close();
651 return;
652 }
653 data.push("");
654 }
655 while (this._recordIndex < this._payloads.length) {
656 var item = JSON.stringify(this._payloads[this._recordIndex]);
657 var itemLength = item.length + separator.length;
658 if (length + itemLength > WebInspector.TimelineModelImpl.TransferChu nkLengthBytes)
659 break;
660 length += itemLength;
661 data.push(item);
662 ++this._recordIndex;
663 }
664 if (this._recordIndex === this._payloads.length)
665 data.push(data.pop() + "]");
666 stream.write(data.join(separator), this._writeNextChunk.bind(this));
667 }
668 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/timeline/TimelineModel.js ('k') | Source/devtools/front_end/timeline/TimelinePanel.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698