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

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

Issue 715803002: DevTools: merge TracingTimelineModel into TimelineModel (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: 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 * @param {!WebInspector.TracingManager} tracingManager
8 * @param {!WebInspector.TracingModel} tracingModel
9 * @param {!WebInspector.TimelineModel.Filter} recordFilter
10 * @extends {WebInspector.TimelineModel}
11 */
12 WebInspector.TracingTimelineModel = function(tracingManager, tracingModel, recor dFilter)
13 {
14 WebInspector.TimelineModel.call(this);
15
16 this._tracingManager = tracingManager;
17 this._tracingModel = tracingModel;
18 this._recordFilter = recordFilter;
19 this._tracingManager.addEventListener(WebInspector.TracingManager.Events.Tra cingStarted, this._onTracingStarted, this);
20 this._tracingManager.addEventListener(WebInspector.TracingManager.Events.Eve ntsCollected, this._onEventsCollected, this);
21 this._tracingManager.addEventListener(WebInspector.TracingManager.Events.Tra cingComplete, this._onTracingComplete, this);
22 this.reset();
23 }
24
25 WebInspector.TracingTimelineModel.RecordType = {
26 Program: "Program",
27 EventDispatch: "EventDispatch",
28
29 GPUTask: "GPUTask",
30
31 RequestMainThreadFrame: "RequestMainThreadFrame",
32 BeginFrame: "BeginFrame",
33 BeginMainThreadFrame: "BeginMainThreadFrame",
34 ActivateLayerTree: "ActivateLayerTree",
35 DrawFrame: "DrawFrame",
36 ScheduleStyleRecalculation: "ScheduleStyleRecalculation",
37 RecalculateStyles: "RecalculateStyles",
38 InvalidateLayout: "InvalidateLayout",
39 Layout: "Layout",
40 UpdateLayer: "UpdateLayer",
41 UpdateLayerTree: "UpdateLayerTree",
42 PaintSetup: "PaintSetup",
43 Paint: "Paint",
44 PaintImage: "PaintImage",
45 Rasterize: "Rasterize",
46 RasterTask: "RasterTask",
47 ScrollLayer: "ScrollLayer",
48 CompositeLayers: "CompositeLayers",
49
50 StyleRecalcInvalidationTracking: "StyleRecalcInvalidationTracking",
51 LayoutInvalidationTracking: "LayoutInvalidationTracking",
52 LayerInvalidationTracking: "LayerInvalidationTracking",
53 PaintInvalidationTracking: "PaintInvalidationTracking",
54
55 ParseHTML: "ParseHTML",
56
57 TimerInstall: "TimerInstall",
58 TimerRemove: "TimerRemove",
59 TimerFire: "TimerFire",
60
61 XHRReadyStateChange: "XHRReadyStateChange",
62 XHRLoad: "XHRLoad",
63 EvaluateScript: "EvaluateScript",
64
65 MarkLoad: "MarkLoad",
66 MarkDOMContent: "MarkDOMContent",
67 MarkFirstPaint: "MarkFirstPaint",
68
69 TimeStamp: "TimeStamp",
70 ConsoleTime: "ConsoleTime",
71
72 ResourceSendRequest: "ResourceSendRequest",
73 ResourceReceiveResponse: "ResourceReceiveResponse",
74 ResourceReceivedData: "ResourceReceivedData",
75 ResourceFinish: "ResourceFinish",
76
77 FunctionCall: "FunctionCall",
78 GCEvent: "GCEvent",
79 JSFrame: "JSFrame",
80 JSSample: "JSSample",
81
82 UpdateCounters: "UpdateCounters",
83
84 RequestAnimationFrame: "RequestAnimationFrame",
85 CancelAnimationFrame: "CancelAnimationFrame",
86 FireAnimationFrame: "FireAnimationFrame",
87
88 WebSocketCreate : "WebSocketCreate",
89 WebSocketSendHandshakeRequest : "WebSocketSendHandshakeRequest",
90 WebSocketReceiveHandshakeResponse : "WebSocketReceiveHandshakeResponse",
91 WebSocketDestroy : "WebSocketDestroy",
92
93 EmbedderCallback : "EmbedderCallback",
94
95 CallStack: "CallStack",
96 SetLayerTreeId: "SetLayerTreeId",
97 TracingStartedInPage: "TracingStartedInPage",
98 TracingSessionIdForWorker: "TracingSessionIdForWorker",
99
100 DecodeImage: "Decode Image",
101 ResizeImage: "Resize Image",
102 DrawLazyPixelRef: "Draw LazyPixelRef",
103 DecodeLazyPixelRef: "Decode LazyPixelRef",
104
105 LazyPixelRef: "LazyPixelRef",
106 LayerTreeHostImplSnapshot: "cc::LayerTreeHostImpl",
107 PictureSnapshot: "cc::Picture",
108
109 // CpuProfile is a virtual event created on frontend to support
110 // serialization of CPU Profiles within tracing timeline data.
111 CpuProfile: "CpuProfile"
112 };
113
114 /**
115 * @constructor
116 * @param {string} name
117 */
118 WebInspector.TracingTimelineModel.VirtualThread = function(name)
119 {
120 this.name = name;
121 /** @type {!Array.<!WebInspector.TracingModel.Event>} */
122 this.events = [];
123 /** @type {!Array.<!Array.<!WebInspector.TracingModel.Event>>} */
124 this.asyncEvents = [];
125 }
126
127 WebInspector.TracingTimelineModel.prototype = {
128 /**
129 * @param {boolean} captureCauses
130 * @param {boolean} enableJSSampling
131 * @param {boolean} captureMemory
132 * @param {boolean} capturePictures
133 */
134 startRecording: function(captureCauses, enableJSSampling, captureMemory, cap turePictures)
135 {
136 function disabledByDefault(category)
137 {
138 return "disabled-by-default-" + category;
139 }
140 var categoriesArray = [
141 "-*",
142 disabledByDefault("devtools.timeline"),
143 disabledByDefault("devtools.timeline.frame"),
144 WebInspector.TracingModel.ConsoleEventCategory
145 ];
146 if (captureCauses || enableJSSampling)
147 categoriesArray.push(disabledByDefault("devtools.timeline.stack"));
148 if (enableJSSampling)
149 this._startCpuProfilingOnAllTargets();
150 if (captureCauses && Runtime.experiments.isEnabled("timelineInvalidation Tracking"))
151 categoriesArray.push(disabledByDefault("devtools.timeline.invalidati onTracking"));
152 if (capturePictures) {
153 categoriesArray = categoriesArray.concat([
154 disabledByDefault("devtools.timeline.layers"),
155 disabledByDefault("devtools.timeline.picture"),
156 disabledByDefault("blink.graphics_context_annotations")]);
157 }
158 var categories = categoriesArray.join(",");
159 this._startRecordingWithCategories(categories);
160 },
161
162 stopRecording: function()
163 {
164 this._stopCallbackBarrier = new CallbackBarrier();
165 this._stopProfilingOnAllTargets();
166 this._tracingManager.stop();
167 },
168
169 /**
170 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events
171 */
172 setEventsForTest: function(events)
173 {
174 this._startCollectingTraceEvents(false);
175 this._tracingModel.addEvents(events);
176 this._onTracingComplete();
177 },
178
179 _startCpuProfilingOnAllTargets: function()
180 {
181 this._profilingTargets = WebInspector.targetManager.targets();
182 for (var i = 0; i < this._profilingTargets.length; ++i) {
183 var target = this._profilingTargets[i];
184 this._configureCpuProfilerSamplingInterval(target);
185 target.profilerAgent().start();
186 }
187 },
188
189 _stopProfilingOnAllTargets: function()
190 {
191 if (!this._profilingTargets)
192 return;
193 for (var i = 0; i < this._profilingTargets.length; ++i) {
194 var target = this._profilingTargets[i];
195 target.profilerAgent().stop(this._stopCallbackBarrier.createCallback (this._didStopRecordingJSSamples.bind(this, target)));
196 }
197 this._profilingTargets = null;
198 },
199
200 /**
201 * @param {!WebInspector.Target} target
202 */
203 _configureCpuProfilerSamplingInterval: function(target)
204 {
205 var intervalUs = WebInspector.settings.highResolutionCpuProfiling.get() ? 100 : 1000;
206 target.profilerAgent().setSamplingInterval(intervalUs, didChangeInterval );
207
208 function didChangeInterval(error)
209 {
210 if (error)
211 WebInspector.console.error(error);
212 }
213 },
214
215 /**
216 * @param {string} categories
217 */
218 _startRecordingWithCategories: function(categories)
219 {
220 this._tracingManager.start(categories, "");
221 },
222
223 _onTracingStarted: function()
224 {
225 this._startCollectingTraceEvents(false);
226 },
227
228 /**
229 * @param {boolean} fromFile
230 */
231 _startCollectingTraceEvents: function(fromFile)
232 {
233 this.reset();
234 this._tracingModel.reset();
235 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin gStarted, { fromFile: fromFile });
236 },
237
238 /**
239 * @param {!WebInspector.Event} event
240 */
241 _onEventsCollected: function(event)
242 {
243 var traceEvents = /** @type {!Array.<!WebInspector.TracingManager.EventP ayload>} */ (event.data);
244 this._tracingModel.addEvents(traceEvents);
245 },
246
247 _onTracingComplete: function()
248 {
249 if (this._stopCallbackBarrier) {
250 this._stopCallbackBarrier.callWhenDone(this._didStopRecordingTraceEv ents.bind(this));
251 this._stopCallbackBarrier = null;
252 } else {
253 this._didStopRecordingTraceEvents();
254 }
255 },
256
257 /**
258 * @param {!WebInspector.Target} target
259 * @param {?Protocol.Error} error
260 * @param {?ProfilerAgent.CPUProfile} cpuProfile
261 */
262 _didStopRecordingJSSamples: function(target, error, cpuProfile)
263 {
264 if (error)
265 WebInspector.console.error(error);
266 if (!this._cpuProfiles)
267 this._cpuProfiles = {};
268 this._cpuProfiles[target.id()] = cpuProfile;
269 },
270
271 _didStopRecordingTraceEvents: function()
272 {
273 this._tracingModel.tracingComplete();
274
275 var events = this._tracingModel.devtoolsPageMetadataEvents();
276 var workerMetadataEvents = this._tracingModel.devtoolsWorkerMetadataEven ts();
277
278 this._resetProcessingState();
279 for (var i = 0, length = events.length; i < length; i++) {
280 var event = events[i];
281 var process = event.thread.process();
282 var startTime = event.startTime;
283
284 var endTime = Infinity;
285 if (i + 1 < length)
286 endTime = events[i + 1].startTime;
287
288 var threads = process.sortedThreads();
289 for (var j = 0; j < threads.length; j++) {
290 var thread = threads[j];
291 if (thread.name() === "WebCore: Worker" && workerMetadataEvents. every(function(e) { return e.args["data"]["workerThreadId"] !== thread.id(); }))
292 continue;
293 this._processThreadEvents(startTime, endTime, event.thread, thre ad);
294 }
295 }
296 this._resetProcessingState();
297
298 this._inspectedTargetEvents.sort(WebInspector.TracingModel.Event.compare StartTime);
299
300 this._cpuProfiles = null;
301
302 this._buildTimelineRecords();
303 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin gStopped);
304 },
305
306 /**
307 * @param {!ProfilerAgent.CPUProfile} cpuProfile
308 */
309 _injectCpuProfileEvent: function(cpuProfile)
310 {
311 var metaEvent = this._tracingModel.devtoolsPageMetadataEvents().peekLast ();
312 if (!metaEvent)
313 return;
314 var cpuProfileEvent = /** @type {!WebInspector.TracingManager.EventPaylo ad} */ ({
315 cat: WebInspector.TracingModel.DevToolsMetadataEventCategory,
316 ph: WebInspector.TracingModel.Phase.Instant,
317 ts: this._tracingModel.maximumRecordTime() * 1000,
318 pid: metaEvent.thread.process().id(),
319 tid: metaEvent.thread.id(),
320 name: WebInspector.TracingTimelineModel.RecordType.CpuProfile,
321 args: { data: { cpuProfile: cpuProfile } }
322 });
323 this._tracingModel.addEvents([cpuProfileEvent]);
324 },
325
326 /**
327 * @return {number}
328 */
329 minimumRecordTime: function()
330 {
331 return this._tracingModel.minimumRecordTime();
332 },
333
334 /**
335 * @return {number}
336 */
337 maximumRecordTime: function()
338 {
339 return this._tracingModel.maximumRecordTime();
340 },
341
342 /**
343 * @return {!Array.<!WebInspector.TracingModel.Event>}
344 */
345 inspectedTargetEvents: function()
346 {
347 return this._inspectedTargetEvents;
348 },
349
350 /**
351 * @return {!Array.<!WebInspector.TracingModel.Event>}
352 */
353 mainThreadEvents: function()
354 {
355 return this._mainThreadEvents;
356 },
357
358 /**
359 * @param {!Array.<!WebInspector.TracingModel.Event>} events
360 */
361 _setMainThreadEvents: function(events)
362 {
363 this._mainThreadEvents = events;
364 },
365
366 /**
367 * @return {!Array.<!Array.<!WebInspector.TracingModel.Event>>}
368 */
369 mainThreadAsyncEvents: function()
370 {
371 return this._mainThreadAsyncEvents;
372 },
373
374 /**
375 * @return {!Array.<!WebInspector.TracingTimelineModel.VirtualThread>}
376 */
377 virtualThreads: function()
378 {
379 return this._virtualThreads;
380 },
381
382 /**
383 * @param {!WebInspector.ChunkedFileReader} fileReader
384 * @param {!WebInspector.Progress} progress
385 * @return {!WebInspector.OutputStream}
386 */
387 createLoader: function(fileReader, progress)
388 {
389 return new WebInspector.TracingModelLoader(this, fileReader, progress);
390 },
391
392 /**
393 * @param {!WebInspector.OutputStream} stream
394 */
395 writeToStream: function(stream)
396 {
397 var saver = new WebInspector.TracingTimelineSaver(stream);
398 this._tracingModel.writeToStream(stream, saver);
399 },
400
401 reset: function()
402 {
403 this._virtualThreads = [];
404 this._mainThreadEvents = [];
405 this._mainThreadAsyncEvents = [];
406 this._inspectedTargetEvents = [];
407 WebInspector.TimelineModel.prototype.reset.call(this);
408 },
409
410 _buildTimelineRecords: function()
411 {
412 var topLevelRecords = this._buildTimelineRecordsForThread(this.mainThrea dEvents());
413
414 /**
415 * @param {!WebInspector.TracingTimelineModel.TraceEventRecord} a
416 * @param {!WebInspector.TracingTimelineModel.TraceEventRecord} b
417 * @return {number}
418 */
419 function compareRecordStartTime(a, b)
420 {
421 // Never return 0 as otherwise equal records would be merged.
422 return (a.startTime() <= b.startTime()) ? -1 : +1;
423 }
424
425 /**
426 * @param {!WebInspector.TracingTimelineModel.VirtualThread} virtualThre ad
427 * @this {!WebInspector.TracingTimelineModel}
428 */
429 function processVirtualThreadEvents(virtualThread)
430 {
431 var threadRecords = this._buildTimelineRecordsForThread(virtualThrea d.events);
432 topLevelRecords = topLevelRecords.mergeOrdered(threadRecords, compar eRecordStartTime);
433 }
434 this.virtualThreads().forEach(processVirtualThreadEvents.bind(this));
435
436
437 for (var i = 0; i < topLevelRecords.length; i++) {
438 var record = topLevelRecords[i];
439 if (record.type() === WebInspector.TracingTimelineModel.RecordType.P rogram)
440 this._mainThreadTasks.push(record);
441 if (record.type() === WebInspector.TracingTimelineModel.RecordType.G PUTask)
442 this._gpuThreadTasks.push(record);
443 }
444 this._records = topLevelRecords;
445 },
446
447 /**
448 * @param {!Array.<!WebInspector.TracingModel.Event>} threadEvents
449 * @return {!Array.<!WebInspector.TracingTimelineModel.TraceEventRecord>}
450 */
451 _buildTimelineRecordsForThread: function(threadEvents)
452 {
453 var recordStack = [];
454 var topLevelRecords = [];
455
456 for (var i = 0, size = threadEvents.length; i < size; ++i) {
457 var event = threadEvents[i];
458 for (var top = recordStack.peekLast(); top && top._event.endTime <= event.startTime; top = recordStack.peekLast()) {
459 recordStack.pop();
460 if (!recordStack.length)
461 topLevelRecords.push(top);
462 }
463 if (event.phase === WebInspector.TracingModel.Phase.AsyncEnd || even t.phase === WebInspector.TracingModel.Phase.NestableAsyncEnd)
464 continue;
465 var parentRecord = recordStack.peekLast();
466 // Maintain the back-end logic of old timeline, skip console.time() / console.timeEnd() that are not properly nested.
467 if (WebInspector.TracingModel.isAsyncBeginPhase(event.phase) && pare ntRecord && event.endTime > parentRecord._event.endTime)
468 continue;
469 var record = new WebInspector.TracingTimelineModel.TraceEventRecord( this, event);
470 if (WebInspector.TimelineUIUtils.isMarkerEvent(event))
471 this._eventDividerRecords.push(record);
472 if (!this._recordFilter.accept(record))
473 continue;
474 if (parentRecord)
475 parentRecord._addChild(record);
476 if (event.endTime)
477 recordStack.push(record);
478 }
479
480 if (recordStack.length)
481 topLevelRecords.push(recordStack[0]);
482
483 return topLevelRecords;
484 },
485
486 _resetProcessingState: function()
487 {
488 this._sendRequestEvents = {};
489 this._timerEvents = {};
490 this._requestAnimationFrameEvents = {};
491 this._invalidationTracker = new WebInspector.InvalidationTracker();
492 this._layoutInvalidate = {};
493 this._lastScheduleStyleRecalculation = {};
494 this._webSocketCreateEvents = {};
495 this._paintImageEventByPixelRefId = {};
496 this._lastPaintForLayer = {};
497 this._lastRecalculateStylesEvent = null;
498 this._currentScriptEvent = null;
499 this._eventStack = [];
500 },
501
502 /**
503 * @param {number} startTime
504 * @param {?number} endTime
505 * @param {!WebInspector.TracingModel.Thread} mainThread
506 * @param {!WebInspector.TracingModel.Thread} thread
507 */
508 _processThreadEvents: function(startTime, endTime, mainThread, thread)
509 {
510 var events = thread.events();
511 var length = events.length;
512 var i = events.lowerBound(startTime, function (time, event) { return tim e - event.startTime });
513
514 var threadEvents;
515 var virtualThread = null;
516 if (thread === mainThread) {
517 threadEvents = this._mainThreadEvents;
518 this._mainThreadAsyncEvents = this._mainThreadAsyncEvents.concat(thr ead.asyncEvents());
519 } else {
520 virtualThread = new WebInspector.TracingTimelineModel.VirtualThread( thread.name());
521 threadEvents = virtualThread.events;
522 virtualThread.asyncEvents = virtualThread.asyncEvents.concat(thread. asyncEvents());
523 this._virtualThreads.push(virtualThread);
524 }
525
526 this._eventStack = [];
527 for (; i < length; i++) {
528 var event = events[i];
529 if (endTime && event.startTime >= endTime)
530 break;
531 this._processEvent(event);
532 threadEvents.push(event);
533 this._inspectedTargetEvents.push(event);
534 }
535
536 if (this._cpuProfiles && thread.target()) {
537 var cpuProfile = this._cpuProfiles[thread.target().id()];
538 if (cpuProfile) {
539 var jsSamples = WebInspector.TimelineJSProfileProcessor.generate TracingEventsFromCpuProfile(cpuProfile, thread);
540 var mergedEvents = threadEvents.mergeOrdered(jsSamples, WebInspe ctor.TracingModel.Event.orderedCompareStartTime);
541 var jsFrameEvents = WebInspector.TimelineJSProfileProcessor.gene rateJSFrameEvents(mergedEvents);
542 mergedEvents = jsFrameEvents.mergeOrdered(mergedEvents, WebInspe ctor.TracingModel.Event.orderedCompareStartTime);
543 if (virtualThread)
544 virtualThread.events = mergedEvents;
545 else
546 this._mainThreadEvents = mergedEvents;
547 this._inspectedTargetEvents = this._inspectedTargetEvents.concat (jsSamples, jsFrameEvents);
548 }
549 }
550 },
551
552 /**
553 * @param {!WebInspector.TracingModel.Event} event
554 */
555 _processEvent: function(event)
556 {
557 var recordTypes = WebInspector.TracingTimelineModel.RecordType;
558
559 var eventStack = this._eventStack;
560 while (eventStack.length && eventStack.peekLast().endTime < event.startT ime)
561 eventStack.pop();
562 var duration = event.duration;
563 if (duration) {
564 if (eventStack.length) {
565 var parent = eventStack.peekLast();
566 parent.selfTime -= duration;
567 }
568 event.selfTime = duration;
569 eventStack.push(event);
570 }
571
572 if (this._currentScriptEvent && event.startTime > this._currentScriptEve nt.endTime)
573 this._currentScriptEvent = null;
574
575 switch (event.name) {
576 case recordTypes.CallStack:
577 var lastMainThreadEvent = this.mainThreadEvents().peekLast();
578 if (lastMainThreadEvent && event.args["stack"] && event.args["stack" ].length)
579 lastMainThreadEvent.stackTrace = event.args["stack"];
580 break;
581
582 case recordTypes.CpuProfile:
583 this._cpuProfile = event.args["data"]["cpuProfile"];
584 break;
585
586 case recordTypes.ResourceSendRequest:
587 this._sendRequestEvents[event.args["data"]["requestId"]] = event;
588 event.imageURL = event.args["data"]["url"];
589 break;
590
591 case recordTypes.ResourceReceiveResponse:
592 case recordTypes.ResourceReceivedData:
593 case recordTypes.ResourceFinish:
594 event.initiator = this._sendRequestEvents[event.args["data"]["reques tId"]];
595 if (event.initiator)
596 event.imageURL = event.initiator.imageURL;
597 break;
598
599 case recordTypes.TimerInstall:
600 this._timerEvents[event.args["data"]["timerId"]] = event;
601 break;
602
603 case recordTypes.TimerFire:
604 event.initiator = this._timerEvents[event.args["data"]["timerId"]];
605 break;
606
607 case recordTypes.RequestAnimationFrame:
608 this._requestAnimationFrameEvents[event.args["data"]["id"]] = event;
609 break;
610
611 case recordTypes.FireAnimationFrame:
612 event.initiator = this._requestAnimationFrameEvents[event.args["data "]["id"]];
613 break;
614
615 case recordTypes.ScheduleStyleRecalculation:
616 this._lastScheduleStyleRecalculation[event.args["frame"]] = event;
617 break;
618
619 case recordTypes.RecalculateStyles:
620 this._invalidationTracker.didRecalcStyle(event);
621 event.initiator = this._lastScheduleStyleRecalculation[event.args["f rame"]];
622 this._lastRecalculateStylesEvent = event;
623 break;
624
625 case recordTypes.StyleRecalcInvalidationTracking:
626 case recordTypes.LayoutInvalidationTracking:
627 case recordTypes.LayerInvalidationTracking:
628 case recordTypes.PaintInvalidationTracking:
629 this._invalidationTracker.addInvalidation(event);
630 break;
631
632 case recordTypes.InvalidateLayout:
633 // Consider style recalculation as a reason for layout invalidation,
634 // but only if we had no earlier layout invalidation records.
635 var layoutInitator = event;
636 var frameId = event.args["frame"];
637 if (!this._layoutInvalidate[frameId] && this._lastRecalculateStylesE vent && this._lastRecalculateStylesEvent.endTime > event.startTime)
638 layoutInitator = this._lastRecalculateStylesEvent.initiator;
639 this._layoutInvalidate[frameId] = layoutInitator;
640 break;
641
642 case recordTypes.Layout:
643 this._invalidationTracker.didLayout(event);
644 var frameId = event.args["beginData"]["frame"];
645 event.initiator = this._layoutInvalidate[frameId];
646 // In case we have no closing Layout event, endData is not available .
647 if (event.args["endData"]) {
648 event.backendNodeId = event.args["endData"]["rootNode"];
649 event.highlightQuad = event.args["endData"]["root"];
650 }
651 this._layoutInvalidate[frameId] = null;
652 if (this._currentScriptEvent)
653 event.warning = WebInspector.UIString("Forced synchronous layout is a possible performance bottleneck.");
654 break;
655
656 case recordTypes.WebSocketCreate:
657 this._webSocketCreateEvents[event.args["data"]["identifier"]] = even t;
658 break;
659
660 case recordTypes.WebSocketSendHandshakeRequest:
661 case recordTypes.WebSocketReceiveHandshakeResponse:
662 case recordTypes.WebSocketDestroy:
663 event.initiator = this._webSocketCreateEvents[event.args["data"]["id entifier"]];
664 break;
665
666 case recordTypes.EvaluateScript:
667 case recordTypes.FunctionCall:
668 if (!this._currentScriptEvent)
669 this._currentScriptEvent = event;
670 break;
671
672 case recordTypes.SetLayerTreeId:
673 this._inspectedTargetLayerTreeId = event.args["layerTreeId"];
674 break;
675
676 case recordTypes.Paint:
677 this._invalidationTracker.didPaint(event);
678 event.highlightQuad = event.args["data"]["clip"];
679 event.backendNodeId = event.args["data"]["nodeId"];
680 var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLay er);
681 if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== th is._inspectedTargetLayerTreeId)
682 break;
683 // Only keep layer paint events, skip paints for subframes that get painted to the same layer as parent.
684 if (!event.args["data"]["layerId"])
685 break;
686 this._lastPaintForLayer[layerUpdateEvent.args["layerId"]] = event;
687 break;
688
689 case recordTypes.PictureSnapshot:
690 var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLay er);
691 if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== th is._inspectedTargetLayerTreeId)
692 break;
693 var paintEvent = this._lastPaintForLayer[layerUpdateEvent.args["laye rId"]];
694 if (paintEvent)
695 paintEvent.picture = event;
696 break;
697
698 case recordTypes.ScrollLayer:
699 event.backendNodeId = event.args["data"]["nodeId"];
700 break;
701
702 case recordTypes.PaintImage:
703 event.backendNodeId = event.args["data"]["nodeId"];
704 event.imageURL = event.args["data"]["url"];
705 break;
706
707 case recordTypes.DecodeImage:
708 case recordTypes.ResizeImage:
709 var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage );
710 if (!paintImageEvent) {
711 var decodeLazyPixelRefEvent = this._findAncestorEvent(recordType s.DecodeLazyPixelRef);
712 paintImageEvent = decodeLazyPixelRefEvent && this._paintImageEve ntByPixelRefId[decodeLazyPixelRefEvent.args["LazyPixelRef"]];
713 }
714 if (!paintImageEvent)
715 break;
716 event.backendNodeId = paintImageEvent.backendNodeId;
717 event.imageURL = paintImageEvent.imageURL;
718 break;
719
720 case recordTypes.DrawLazyPixelRef:
721 var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage );
722 if (!paintImageEvent)
723 break;
724 this._paintImageEventByPixelRefId[event.args["LazyPixelRef"]] = pain tImageEvent;
725 event.backendNodeId = paintImageEvent.backendNodeId;
726 event.imageURL = paintImageEvent.imageURL;
727 break;
728 }
729 },
730
731 /**
732 * @param {string} name
733 * @return {?WebInspector.TracingModel.Event}
734 */
735 _findAncestorEvent: function(name)
736 {
737 for (var i = this._eventStack.length - 1; i >= 0; --i) {
738 var event = this._eventStack[i];
739 if (event.name === name)
740 return event;
741 }
742 return null;
743 },
744
745 __proto__: WebInspector.TimelineModel.prototype
746 }
747
748 /**
749 * @interface
750 */
751 WebInspector.TracingTimelineModel.Filter = function() { }
752
753 WebInspector.TracingTimelineModel.Filter.prototype = {
754 /**
755 * @param {!WebInspector.TracingModel.Event} event
756 * @return {boolean}
757 */
758 accept: function(event) { }
759 }
760
761 /**
762 * @constructor
763 * @implements {WebInspector.TracingTimelineModel.Filter}
764 * @param {!Array.<string>} eventNames
765 */
766 WebInspector.TracingTimelineModel.EventNameFilter = function(eventNames)
767 {
768 this._eventNames = eventNames.keySet();
769 }
770
771 WebInspector.TracingTimelineModel.EventNameFilter.prototype = {
772 /**
773 * @param {!WebInspector.TracingModel.Event} event
774 * @return {boolean}
775 */
776 accept: function(event)
777 {
778 throw new Error("Not implemented.");
779 }
780 }
781
782 /**
783 * @constructor
784 * @extends {WebInspector.TracingTimelineModel.EventNameFilter}
785 * @param {!Array.<string>} includeNames
786 */
787 WebInspector.TracingTimelineModel.InclusiveEventNameFilter = function(includeNam es)
788 {
789 WebInspector.TracingTimelineModel.EventNameFilter.call(this, includeNames)
790 }
791
792 WebInspector.TracingTimelineModel.InclusiveEventNameFilter.prototype = {
793 /**
794 * @override
795 * @param {!WebInspector.TracingModel.Event} event
796 * @return {boolean}
797 */
798 accept: function(event)
799 {
800 return event.category === WebInspector.TracingModel.ConsoleEventCategory || !!this._eventNames[event.name];
801 },
802 __proto__: WebInspector.TracingTimelineModel.EventNameFilter.prototype
803 }
804
805 /**
806 * @constructor
807 * @extends {WebInspector.TracingTimelineModel.EventNameFilter}
808 * @param {!Array.<string>} excludeNames
809 */
810 WebInspector.TracingTimelineModel.ExclusiveEventNameFilter = function(excludeNam es)
811 {
812 WebInspector.TracingTimelineModel.EventNameFilter.call(this, excludeNames)
813 }
814
815 WebInspector.TracingTimelineModel.ExclusiveEventNameFilter.prototype = {
816 /**
817 * @override
818 * @param {!WebInspector.TracingModel.Event} event
819 * @return {boolean}
820 */
821 accept: function(event)
822 {
823 return !this._eventNames[event.name];
824 },
825 __proto__: WebInspector.TracingTimelineModel.EventNameFilter.prototype
826 }
827
828 /**
829 * @constructor
830 * @implements {WebInspector.TimelineModel.Record}
831 * @param {!WebInspector.TimelineModel} model
832 * @param {!WebInspector.TracingModel.Event} traceEvent
833 */
834 WebInspector.TracingTimelineModel.TraceEventRecord = function(model, traceEvent)
835 {
836 this._model = model;
837 this._event = traceEvent;
838 traceEvent._timelineRecord = this;
839 this._children = [];
840 }
841
842 WebInspector.TracingTimelineModel.TraceEventRecord.prototype = {
843 /**
844 * @return {?Array.<!ConsoleAgent.CallFrame>}
845 */
846 callSiteStackTrace: function()
847 {
848 var initiator = this._event.initiator;
849 return initiator ? initiator.stackTrace : null;
850 },
851
852 /**
853 * @return {?WebInspector.TimelineModel.Record}
854 */
855 initiator: function()
856 {
857 var initiator = this._event.initiator;
858 return initiator ? initiator._timelineRecord : null;
859 },
860
861 /**
862 * @return {?WebInspector.Target}
863 */
864 target: function()
865 {
866 return this._event.thread.target();
867 },
868
869 /**
870 * @return {number}
871 */
872 selfTime: function()
873 {
874 return this._event.selfTime;
875 },
876
877 /**
878 * @return {!Array.<!WebInspector.TimelineModel.Record>}
879 */
880 children: function()
881 {
882 return this._children;
883 },
884
885 /**
886 * @return {number}
887 */
888 startTime: function()
889 {
890 return this._event.startTime;
891 },
892
893 /**
894 * @return {string}
895 */
896 thread: function()
897 {
898 if (this._event.thread.name() === "CrRendererMain")
899 return WebInspector.TimelineModel.MainThreadName;
900 return this._event.thread.name();
901 },
902
903 /**
904 * @return {number}
905 */
906 endTime: function()
907 {
908 return this._endTime || this._event.endTime || this._event.startTime;
909 },
910
911 /**
912 * @param {number} endTime
913 */
914 setEndTime: function(endTime)
915 {
916 this._endTime = endTime;
917 },
918
919 /**
920 * @return {!Object}
921 */
922 data: function()
923 {
924 return this._event.args["data"];
925 },
926
927 /**
928 * @return {string}
929 */
930 type: function()
931 {
932 if (this._event.category === WebInspector.TracingModel.ConsoleEventCateg ory)
933 return WebInspector.TracingTimelineModel.RecordType.ConsoleTime;
934 return this._event.name;
935 },
936
937 /**
938 * @return {string}
939 */
940 frameId: function()
941 {
942 switch (this._event.name) {
943 case WebInspector.TracingTimelineModel.RecordType.ScheduleStyleRecalcula tion:
944 case WebInspector.TracingTimelineModel.RecordType.RecalculateStyles:
945 case WebInspector.TracingTimelineModel.RecordType.InvalidateLayout:
946 return this._event.args["frameId"];
947 case WebInspector.TracingTimelineModel.RecordType.Layout:
948 return this._event.args["beginData"]["frameId"];
949 default:
950 var data = this._event.args["data"];
951 return (data && data["frame"]) || "";
952 }
953 },
954
955 /**
956 * @return {?Array.<!ConsoleAgent.CallFrame>}
957 */
958 stackTrace: function()
959 {
960 return this._event.stackTrace;
961 },
962
963 /**
964 * @param {string} key
965 * @return {?Object}
966 */
967 getUserObject: function(key)
968 {
969 if (key === "TimelineUIUtils::preview-element")
970 return this._event.previewElement;
971 throw new Error("Unexpected key: " + key);
972 },
973
974 /**
975 * @param {string} key
976 * @param {?Object|undefined} value
977 */
978 setUserObject: function(key, value)
979 {
980 if (key !== "TimelineUIUtils::preview-element")
981 throw new Error("Unexpected key: " + key);
982 this._event.previewElement = /** @type {?Element} */ (value);
983 },
984
985 /**
986 * @return {?Array.<string>}
987 */
988 warnings: function()
989 {
990 if (this._event.warning)
991 return [this._event.warning];
992 return null;
993 },
994
995 /**
996 * @return {!WebInspector.TracingModel.Event}
997 */
998 traceEvent: function()
999 {
1000 return this._event;
1001 },
1002
1003 /**
1004 * @param {!WebInspector.TracingTimelineModel.TraceEventRecord} child
1005 */
1006 _addChild: function(child)
1007 {
1008 this._children.push(child);
1009 child.parent = this;
1010 },
1011
1012 /**
1013 * @return {!WebInspector.TimelineModel}
1014 */
1015 timelineModel: function()
1016 {
1017 return this._model;
1018 }
1019 }
1020
1021
1022
1023 /**
1024 * @constructor
1025 * @implements {WebInspector.OutputStream}
1026 * @param {!WebInspector.TracingTimelineModel} model
1027 * @param {!{cancel: function()}} reader
1028 * @param {!WebInspector.Progress} progress
1029 */
1030 WebInspector.TracingModelLoader = function(model, reader, progress)
1031 {
1032 this._model = model;
1033 this._reader = reader;
1034 this._progress = progress;
1035 this._buffer = "";
1036 this._firstChunk = true;
1037 this._loader = new WebInspector.TracingModel.Loader(model._tracingModel);
1038 }
1039
1040 WebInspector.TracingModelLoader.prototype = {
1041 /**
1042 * @param {string} chunk
1043 */
1044 write: function(chunk)
1045 {
1046 var data = this._buffer + chunk;
1047 var lastIndex = 0;
1048 var index;
1049 do {
1050 index = lastIndex;
1051 lastIndex = WebInspector.TextUtils.findBalancedCurlyBrackets(data, i ndex);
1052 } while (lastIndex !== -1)
1053
1054 var json = data.slice(0, index) + "]";
1055 this._buffer = data.slice(index);
1056
1057 if (!index)
1058 return;
1059
1060 if (this._firstChunk) {
1061 this._model._startCollectingTraceEvents(true);
1062 } else {
1063 var commaIndex = json.indexOf(",");
1064 if (commaIndex !== -1)
1065 json = json.slice(commaIndex + 1);
1066 json = "[" + json;
1067 }
1068
1069 var items;
1070 try {
1071 items = /** @type {!Array.<!WebInspector.TracingManager.EventPayload >} */ (JSON.parse(json));
1072 } catch (e) {
1073 this._reportErrorAndCancelLoading("Malformed timeline data: " + e);
1074 return;
1075 }
1076
1077 if (this._firstChunk) {
1078 this._firstChunk = false;
1079 if (this._looksLikeAppVersion(items[0])) {
1080 this._reportErrorAndCancelLoading("Old Timeline format is not su pported.");
1081 return;
1082 }
1083 }
1084
1085 try {
1086 this._loader.loadNextChunk(items);
1087 } catch(e) {
1088 this._reportErrorAndCancelLoading("Malformed timeline data: " + e);
1089 return;
1090 }
1091 },
1092
1093 _reportErrorAndCancelLoading: function(messsage)
1094 {
1095 WebInspector.console.error(messsage);
1096 this._model._onTracingComplete();
1097 this._model.reset();
1098 this._reader.cancel();
1099 this._progress.done();
1100 },
1101
1102 _looksLikeAppVersion: function(item)
1103 {
1104 return typeof item === "string" && item.indexOf("Chrome") !== -1;
1105 },
1106
1107 close: function()
1108 {
1109 this._loader.finish();
1110 this._model._onTracingComplete();
1111 }
1112 }
1113
1114 /**
1115 * @constructor
1116 * @param {!WebInspector.OutputStream} stream
1117 * @implements {WebInspector.OutputStreamDelegate}
1118 */
1119 WebInspector.TracingTimelineSaver = function(stream)
1120 {
1121 this._stream = stream;
1122 }
1123
1124 WebInspector.TracingTimelineSaver.prototype = {
1125 onTransferStarted: function()
1126 {
1127 this._stream.write("[");
1128 },
1129
1130 onTransferFinished: function()
1131 {
1132 this._stream.write("]");
1133 },
1134
1135 /**
1136 * @param {!WebInspector.ChunkedReader} reader
1137 */
1138 onChunkTransferred: function(reader) { },
1139
1140 /**
1141 * @param {!WebInspector.ChunkedReader} reader
1142 * @param {!Event} event
1143 */
1144 onError: function(reader, event) { },
1145 }
1146
1147 /**
1148 * @constructor
1149 * @param {!WebInspector.TracingModel.Event} event
1150 */
1151 WebInspector.InvalidationTrackingEvent = function(event)
1152 {
1153 this.type = event.name;
1154 this.frameId = event.args["data"]["frame"];
1155 this.nodeId = event.args["data"]["nodeId"];
1156 this.nodeName = event.args["data"]["nodeName"];
1157 this.paintId = event.args["data"]["paintId"];
1158 this.reason = event.args["data"]["reason"];
1159 this.stackTrace = event.args["data"]["stackTrace"];
1160 }
1161
1162 /**
1163 * @constructor
1164 */
1165 WebInspector.InvalidationTracker = function()
1166 {
1167 this._initializePerFrameState();
1168 }
1169
1170 WebInspector.InvalidationTracker.prototype = {
1171 /**
1172 * @param {!WebInspector.TracingModel.Event} event
1173 */
1174 addInvalidation: function(event)
1175 {
1176 var invalidation = new WebInspector.InvalidationTrackingEvent(event);
1177
1178 this._startNewFrameIfNeeded();
1179 if (!invalidation.nodeId && !invalidation.paintId) {
1180 console.error("Invalidation lacks node information.");
1181 console.error(invalidation);
1182 }
1183
1184 // Record the paintIds for style recalc or layout invalidations.
1185 // FIXME: This O(n^2) loop could be optimized with a map.
1186 var recordTypes = WebInspector.TracingTimelineModel.RecordType;
1187 if (invalidation.type == recordTypes.PaintInvalidationTracking)
1188 this._invalidationEvents.forEach(updatePaintId);
1189 else
1190 this._invalidationEvents.push(invalidation);
1191
1192 function updatePaintId(invalidationToUpdate)
1193 {
1194 if (invalidationToUpdate.nodeId !== invalidation.nodeId)
1195 return;
1196 if (invalidationToUpdate.type === recordTypes.StyleRecalcInvalidatio nTracking
1197 || invalidationToUpdate.type === recordTypes.LayoutInvalidat ionTracking) {
1198 invalidationToUpdate.paintId = invalidation.paintId;
1199 }
1200 }
1201 },
1202
1203 /**
1204 * @param {!WebInspector.TracingModel.Event} styleRecalcEvent
1205 */
1206 didRecalcStyle: function(styleRecalcEvent)
1207 {
1208 var recalcFrameId = styleRecalcEvent.args["frame"];
1209 var index = this._lastStyleRecalcEventIndex;
1210 var invalidationCount = this._invalidationEvents.length;
1211 for (; index < invalidationCount; index++) {
1212 var invalidation = this._invalidationEvents[index];
1213 if (invalidation.type !== WebInspector.TracingTimelineModel.RecordTy pe.StyleRecalcInvalidationTracking)
1214 continue;
1215 if (invalidation.frameId === recalcFrameId)
1216 this._addInvalidationTrackingEvent(styleRecalcEvent, invalidatio n);
1217 }
1218
1219 this._lastStyleRecalcEventIndex = invalidationCount;
1220 },
1221
1222 /**
1223 * @param {!WebInspector.TracingModel.Event} layoutEvent
1224 */
1225 didLayout: function(layoutEvent)
1226 {
1227 var layoutFrameId = layoutEvent.args["beginData"]["frame"];
1228 var index = this._lastLayoutEventIndex;
1229 var invalidationCount = this._invalidationEvents.length;
1230 for (; index < invalidationCount; index++) {
1231 var invalidation = this._invalidationEvents[index];
1232 if (invalidation.type !== WebInspector.TracingTimelineModel.RecordTy pe.LayoutInvalidationTracking)
1233 continue;
1234 if (invalidation.frameId === layoutFrameId)
1235 this._addInvalidationTrackingEvent(layoutEvent, invalidation);
1236 }
1237
1238 this._lastLayoutEventIndex = invalidationCount;
1239 },
1240
1241 /**
1242 * @param {!WebInspector.TracingModel.Event} paintEvent
1243 */
1244 didPaint: function(paintEvent)
1245 {
1246 this._didPaint = true;
1247
1248 // If a paint doesn't have a corresponding graphics layer id, it paints
1249 // into its parent so add an effectivePaintId to these events.
1250 var layerId = paintEvent.args["data"]["layerId"];
1251 if (layerId)
1252 this._lastPaintWithLayer = paintEvent;
1253 if (!this._lastPaintWithLayer) {
1254 console.error("Failed to find the paint container for a paint event. ");
1255 return;
1256 }
1257
1258 var effectivePaintId = this._lastPaintWithLayer.args["data"]["nodeId"];
1259 var frameId = paintEvent.args["data"]["frame"];
1260 this._invalidationEvents.forEach(recordInvalidationForPaint.bind(this));
1261
1262 /**
1263 * @param {!WebInspector.InvalidationTrackingEvent} invalidation
1264 * @this {WebInspector.InvalidationTracker}
1265 */
1266 function recordInvalidationForPaint(invalidation)
1267 {
1268 if (invalidation.paintId === effectivePaintId && invalidation.frameI d === frameId)
1269 this._addInvalidationTrackingEvent(paintEvent, invalidation);
1270 }
1271 },
1272
1273 /**
1274 * @param {!WebInspector.TracingModel.Event} event
1275 * @param {!WebInspector.InvalidationTrackingEvent} invalidation
1276 */
1277 _addInvalidationTrackingEvent: function(event, invalidation)
1278 {
1279 if (!event.invalidationTrackingEvents)
1280 event.invalidationTrackingEvents = [ invalidation ];
1281 else
1282 event.invalidationTrackingEvents.push(invalidation);
1283 },
1284
1285 _startNewFrameIfNeeded: function()
1286 {
1287 if (!this._didPaint)
1288 return;
1289
1290 this._initializePerFrameState();
1291 },
1292
1293 _initializePerFrameState: function()
1294 {
1295 /** @type {!Array.<!WebInspector.InvalidationTrackingEvent>} */
1296 this._invalidationEvents = [];
1297 this._lastStyleRecalcEventIndex = 0;
1298 this._lastLayoutEventIndex = 0;
1299 this._lastPaintWithLayer = undefined;
1300 this._didPaint = false;
1301 }
1302 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/timeline/TimelineView.js ('k') | Source/devtools/front_end/timeline/module.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698