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

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

Powered by Google App Engine
This is Rietveld 408576698