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

Side by Side Diff: Source/devtools/front_end/timeline/TimelineModel.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
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 12 matching lines...) Expand all
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 /** 31 /**
32 * @constructor 32 * @constructor
33 * @param {!WebInspector.TracingManager} tracingManager
34 * @param {!WebInspector.TracingModel} tracingModel
35 * @param {!WebInspector.TimelineModel.Filter} recordFilter
33 * @extends {WebInspector.Object} 36 * @extends {WebInspector.Object}
34 */ 37 */
35 WebInspector.TimelineModel = function() 38 WebInspector.TimelineModel = function(tracingManager, tracingModel, recordFilter )
36 { 39 {
37 WebInspector.Object.call(this); 40 WebInspector.Object.call(this);
38 this._filters = []; 41 this._filters = [];
42 this._tracingManager = tracingManager;
43 this._tracingModel = tracingModel;
44 this._recordFilter = recordFilter;
45 this._tracingManager.addEventListener(WebInspector.TracingManager.Events.Tra cingStarted, this._onTracingStarted, this);
46 this._tracingManager.addEventListener(WebInspector.TracingManager.Events.Eve ntsCollected, this._onEventsCollected, this);
47 this._tracingManager.addEventListener(WebInspector.TracingManager.Events.Tra cingComplete, this._onTracingComplete, this);
48 this.reset();
39 } 49 }
40 50
41 WebInspector.TimelineModel.RecordType = { 51 WebInspector.TimelineModel.RecordType = {
42 Root: "Root",
43 Program: "Program", 52 Program: "Program",
44 EventDispatch: "EventDispatch", 53 EventDispatch: "EventDispatch",
45 54
46 GPUTask: "GPUTask", 55 GPUTask: "GPUTask",
47 56
48 RequestMainThreadFrame: "RequestMainThreadFrame", 57 RequestMainThreadFrame: "RequestMainThreadFrame",
49 BeginFrame: "BeginFrame", 58 BeginFrame: "BeginFrame",
59 BeginMainThreadFrame: "BeginMainThreadFrame",
50 ActivateLayerTree: "ActivateLayerTree", 60 ActivateLayerTree: "ActivateLayerTree",
51 DrawFrame: "DrawFrame", 61 DrawFrame: "DrawFrame",
52 ScheduleStyleRecalculation: "ScheduleStyleRecalculation", 62 ScheduleStyleRecalculation: "ScheduleStyleRecalculation",
53 RecalculateStyles: "RecalculateStyles", 63 RecalculateStyles: "RecalculateStyles",
54 InvalidateLayout: "InvalidateLayout", 64 InvalidateLayout: "InvalidateLayout",
55 Layout: "Layout", 65 Layout: "Layout",
66 UpdateLayer: "UpdateLayer",
56 UpdateLayerTree: "UpdateLayerTree", 67 UpdateLayerTree: "UpdateLayerTree",
57 PaintSetup: "PaintSetup", 68 PaintSetup: "PaintSetup",
58 Paint: "Paint", 69 Paint: "Paint",
70 PaintImage: "PaintImage",
59 Rasterize: "Rasterize", 71 Rasterize: "Rasterize",
72 RasterTask: "RasterTask",
60 ScrollLayer: "ScrollLayer", 73 ScrollLayer: "ScrollLayer",
61 DecodeImage: "DecodeImage",
62 ResizeImage: "ResizeImage",
63 CompositeLayers: "CompositeLayers", 74 CompositeLayers: "CompositeLayers",
64 75
76 StyleRecalcInvalidationTracking: "StyleRecalcInvalidationTracking",
77 LayoutInvalidationTracking: "LayoutInvalidationTracking",
78 LayerInvalidationTracking: "LayerInvalidationTracking",
79 PaintInvalidationTracking: "PaintInvalidationTracking",
80
65 ParseHTML: "ParseHTML", 81 ParseHTML: "ParseHTML",
66 82
67 TimerInstall: "TimerInstall", 83 TimerInstall: "TimerInstall",
68 TimerRemove: "TimerRemove", 84 TimerRemove: "TimerRemove",
69 TimerFire: "TimerFire", 85 TimerFire: "TimerFire",
70 86
71 XHRReadyStateChange: "XHRReadyStateChange", 87 XHRReadyStateChange: "XHRReadyStateChange",
72 XHRLoad: "XHRLoad", 88 XHRLoad: "XHRLoad",
73 EvaluateScript: "EvaluateScript", 89 EvaluateScript: "EvaluateScript",
74 90
75 MarkLoad: "MarkLoad", 91 MarkLoad: "MarkLoad",
76 MarkDOMContent: "MarkDOMContent", 92 MarkDOMContent: "MarkDOMContent",
77 MarkFirstPaint: "MarkFirstPaint", 93 MarkFirstPaint: "MarkFirstPaint",
78 94
79 TimeStamp: "TimeStamp", 95 TimeStamp: "TimeStamp",
80 ConsoleTime: "ConsoleTime", 96 ConsoleTime: "ConsoleTime",
81 97
82 ResourceSendRequest: "ResourceSendRequest", 98 ResourceSendRequest: "ResourceSendRequest",
83 ResourceReceiveResponse: "ResourceReceiveResponse", 99 ResourceReceiveResponse: "ResourceReceiveResponse",
84 ResourceReceivedData: "ResourceReceivedData", 100 ResourceReceivedData: "ResourceReceivedData",
85 ResourceFinish: "ResourceFinish", 101 ResourceFinish: "ResourceFinish",
86 102
87 FunctionCall: "FunctionCall", 103 FunctionCall: "FunctionCall",
88 GCEvent: "GCEvent", 104 GCEvent: "GCEvent",
105 JSFrame: "JSFrame",
106 JSSample: "JSSample",
89 107
90 UpdateCounters: "UpdateCounters", 108 UpdateCounters: "UpdateCounters",
91 109
92 RequestAnimationFrame: "RequestAnimationFrame", 110 RequestAnimationFrame: "RequestAnimationFrame",
93 CancelAnimationFrame: "CancelAnimationFrame", 111 CancelAnimationFrame: "CancelAnimationFrame",
94 FireAnimationFrame: "FireAnimationFrame", 112 FireAnimationFrame: "FireAnimationFrame",
95 113
96 WebSocketCreate : "WebSocketCreate", 114 WebSocketCreate : "WebSocketCreate",
97 WebSocketSendHandshakeRequest : "WebSocketSendHandshakeRequest", 115 WebSocketSendHandshakeRequest : "WebSocketSendHandshakeRequest",
98 WebSocketReceiveHandshakeResponse : "WebSocketReceiveHandshakeResponse", 116 WebSocketReceiveHandshakeResponse : "WebSocketReceiveHandshakeResponse",
99 WebSocketDestroy : "WebSocketDestroy", 117 WebSocketDestroy : "WebSocketDestroy",
100 118
101 EmbedderCallback : "EmbedderCallback", 119 EmbedderCallback : "EmbedderCallback",
120
121 CallStack: "CallStack",
122 SetLayerTreeId: "SetLayerTreeId",
123 TracingStartedInPage: "TracingStartedInPage",
124 TracingSessionIdForWorker: "TracingSessionIdForWorker",
125
126 DecodeImage: "Decode Image",
127 ResizeImage: "Resize Image",
128 DrawLazyPixelRef: "Draw LazyPixelRef",
129 DecodeLazyPixelRef: "Decode LazyPixelRef",
130
131 LazyPixelRef: "LazyPixelRef",
132 LayerTreeHostImplSnapshot: "cc::LayerTreeHostImpl",
133 PictureSnapshot: "cc::Picture",
134
135 // CpuProfile is a virtual event created on frontend to support
136 // serialization of CPU Profiles within tracing timeline data.
137 CpuProfile: "CpuProfile"
102 } 138 }
103 139
104 WebInspector.TimelineModel.Events = { 140 WebInspector.TimelineModel.Events = {
105 RecordsCleared: "RecordsCleared", 141 RecordsCleared: "RecordsCleared",
106 RecordingStarted: "RecordingStarted", 142 RecordingStarted: "RecordingStarted",
107 RecordingStopped: "RecordingStopped", 143 RecordingStopped: "RecordingStopped",
108 RecordFilterChanged: "RecordFilterChanged" 144 RecordFilterChanged: "RecordFilterChanged"
109 } 145 }
110 146
111 WebInspector.TimelineModel.MainThreadName = "main"; 147 WebInspector.TimelineModel.MainThreadName = "main";
(...skipping 22 matching lines...) Expand all
134 if (postOrderCallback && postOrderCallback(record, depth)) 170 if (postOrderCallback && postOrderCallback(record, depth))
135 return true; 171 return true;
136 } 172 }
137 return false; 173 return false;
138 } 174 }
139 return processRecords(recordsArray, 0); 175 return processRecords(recordsArray, 0);
140 } 176 }
141 177
142 WebInspector.TimelineModel.TransferChunkLengthBytes = 5000000; 178 WebInspector.TimelineModel.TransferChunkLengthBytes = 5000000;
143 179
180 /**
181 * @constructor
182 * @param {string} name
183 */
184 WebInspector.TimelineModel.VirtualThread = function(name)
185 {
186 this.name = name;
187 /** @type {!Array.<!WebInspector.TracingModel.Event>} */
188 this.events = [];
189 /** @type {!Array.<!Array.<!WebInspector.TracingModel.Event>>} */
190 this.asyncEvents = [];
191 }
192
193 /**
194 * @constructor
195 * @param {!WebInspector.TimelineModel} model
196 * @param {!WebInspector.TracingModel.Event} traceEvent
197 */
198 WebInspector.TimelineModel.Record = function(model, traceEvent)
199 {
200 this._model = model;
201 this._event = traceEvent;
202 traceEvent._timelineRecord = this;
203 this._children = [];
204 }
205
206 WebInspector.TimelineModel.Record.prototype = {
207 /**
208 * @return {?Array.<!ConsoleAgent.CallFrame>}
209 */
210 callSiteStackTrace: function()
211 {
212 var initiator = this._event.initiator;
213 return initiator ? initiator.stackTrace : null;
214 },
215
216 /**
217 * @return {?WebInspector.TimelineModel.Record}
218 */
219 initiator: function()
220 {
221 var initiator = this._event.initiator;
222 return initiator ? initiator._timelineRecord : null;
223 },
224
225 /**
226 * @return {?WebInspector.Target}
227 */
228 target: function()
229 {
230 return this._event.thread.target();
231 },
232
233 /**
234 * @return {number}
235 */
236 selfTime: function()
237 {
238 return this._event.selfTime;
239 },
240
241 /**
242 * @return {!Array.<!WebInspector.TimelineModel.Record>}
243 */
244 children: function()
245 {
246 return this._children;
247 },
248
249 /**
250 * @return {number}
251 */
252 startTime: function()
253 {
254 return this._event.startTime;
255 },
256
257 /**
258 * @return {string}
259 */
260 thread: function()
261 {
262 if (this._event.thread.name() === "CrRendererMain")
263 return WebInspector.TimelineModel.MainThreadName;
264 return this._event.thread.name();
265 },
266
267 /**
268 * @return {number}
269 */
270 endTime: function()
271 {
272 return this._endTime || this._event.endTime || this._event.startTime;
273 },
274
275 /**
276 * @param {number} endTime
277 */
278 setEndTime: function(endTime)
279 {
280 this._endTime = endTime;
281 },
282
283 /**
284 * @return {!Object}
285 */
286 data: function()
287 {
288 return this._event.args["data"];
289 },
290
291 /**
292 * @return {string}
293 */
294 type: function()
295 {
296 if (this._event.category === WebInspector.TracingModel.ConsoleEventCateg ory)
297 return WebInspector.TimelineModel.RecordType.ConsoleTime;
298 return this._event.name;
299 },
300
301 /**
302 * @return {string}
303 */
304 frameId: function()
305 {
306 switch (this._event.name) {
307 case WebInspector.TimelineModel.RecordType.ScheduleStyleRecalculation:
308 case WebInspector.TimelineModel.RecordType.RecalculateStyles:
309 case WebInspector.TimelineModel.RecordType.InvalidateLayout:
310 return this._event.args["frameId"];
311 case WebInspector.TimelineModel.RecordType.Layout:
312 return this._event.args["beginData"]["frameId"];
313 default:
314 var data = this._event.args["data"];
315 return (data && data["frame"]) || "";
316 }
317 },
318
319 /**
320 * @return {?Array.<!ConsoleAgent.CallFrame>}
321 */
322 stackTrace: function()
323 {
324 return this._event.stackTrace;
325 },
326
327 /**
328 * @param {string} key
329 * @return {?Object}
330 */
331 getUserObject: function(key)
332 {
333 if (key === "TimelineUIUtils::preview-element")
334 return this._event.previewElement;
335 throw new Error("Unexpected key: " + key);
336 },
337
338 /**
339 * @param {string} key
340 * @param {?Object|undefined} value
341 */
342 setUserObject: function(key, value)
343 {
344 if (key !== "TimelineUIUtils::preview-element")
345 throw new Error("Unexpected key: " + key);
346 this._event.previewElement = /** @type {?Element} */ (value);
347 },
348
349 /**
350 * @return {?Array.<string>}
351 */
352 warnings: function()
353 {
354 if (this._event.warning)
355 return [this._event.warning];
356 return null;
357 },
358
359 /**
360 * @return {!WebInspector.TracingModel.Event}
361 */
362 traceEvent: function()
363 {
364 return this._event;
365 },
366
367 /**
368 * @param {!WebInspector.TimelineModel.Record} child
369 */
370 _addChild: function(child)
371 {
372 this._children.push(child);
373 child.parent = this;
374 },
375
376 /**
377 * @return {!WebInspector.TimelineModel}
378 */
379 timelineModel: function()
380 {
381 return this._model;
382 }
383 }
384
144 WebInspector.TimelineModel.prototype = { 385 WebInspector.TimelineModel.prototype = {
145 /** 386 /**
146 * @param {boolean} captureCauses 387 * @param {boolean} captureCauses
388 * @param {boolean} enableJSSampling
147 * @param {boolean} captureMemory 389 * @param {boolean} captureMemory
148 * @param {boolean} capturePictures 390 * @param {boolean} capturePictures
149 */ 391 */
150 startRecording: function(captureCauses, captureMemory, capturePictures) 392 startRecording: function(captureCauses, enableJSSampling, captureMemory, cap turePictures)
151 { 393 {
394 function disabledByDefault(category)
395 {
396 return "disabled-by-default-" + category;
397 }
398 var categoriesArray = [
399 "-*",
400 disabledByDefault("devtools.timeline"),
401 disabledByDefault("devtools.timeline.frame"),
402 WebInspector.TracingModel.ConsoleEventCategory
403 ];
404 if (captureCauses || enableJSSampling)
405 categoriesArray.push(disabledByDefault("devtools.timeline.stack"));
406 if (enableJSSampling) {
407 this._jsProfilerStarted = true;
408 this._currentTarget = WebInspector.context.flavor(WebInspector.Targe t);
409 this._configureCpuProfilerSamplingInterval();
410 this._currentTarget.profilerAgent().start();
411 }
412 if (captureCauses && Runtime.experiments.isEnabled("timelineInvalidation Tracking"))
413 categoriesArray.push(disabledByDefault("devtools.timeline.invalidati onTracking"));
414 if (capturePictures) {
415 categoriesArray = categoriesArray.concat([
416 disabledByDefault("devtools.timeline.layers"),
417 disabledByDefault("devtools.timeline.picture"),
418 disabledByDefault("blink.graphics_context_annotations")]);
419 }
420 var categories = categoriesArray.join(",");
421 this._startRecordingWithCategories(categories);
152 }, 422 },
153 423
154 stopRecording: function() 424 stopRecording: function()
155 { 425 {
156 }, 426 if (this._jsProfilerStarted) {
157 427 this._stopCallbackBarrier = new CallbackBarrier();
158 /** 428 this._currentTarget.profilerAgent().stop(this._stopCallbackBarrier.c reateCallback(this._didStopRecordingJSSamples.bind(this)));
429 this._jsProfilerStarted = false;
430 }
431 this._tracingManager.stop();
432 },
433
434 /**
159 * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspe ctor.TimelineModel.Record,number)} preOrderCallback 435 * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspe ctor.TimelineModel.Record,number)} preOrderCallback
160 * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspect or.TimelineModel.Record,number)=} postOrderCallback 436 * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspect or.TimelineModel.Record,number)=} postOrderCallback
161 */ 437 */
162 forAllRecords: function(preOrderCallback, postOrderCallback) 438 forAllRecords: function(preOrderCallback, postOrderCallback)
163 { 439 {
164 WebInspector.TimelineModel.forAllRecords(this._records, preOrderCallback , postOrderCallback); 440 WebInspector.TimelineModel.forAllRecords(this._records, preOrderCallback , postOrderCallback);
165 }, 441 },
166 442
167 /** 443 /**
168 * @param {!WebInspector.TimelineModel.Filter} filter 444 * @param {!WebInspector.TimelineModel.Filter} filter
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 499
224 /** 500 /**
225 * @return {!Array.<!WebInspector.TimelineModel.Record>} 501 * @return {!Array.<!WebInspector.TimelineModel.Record>}
226 */ 502 */
227 records: function() 503 records: function()
228 { 504 {
229 return this._records; 505 return this._records;
230 }, 506 },
231 507
232 /** 508 /**
509 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events
510 */
511 setEventsForTest: function(events)
512 {
513 this._startCollectingTraceEvents(false);
514 this._tracingModel.addEvents(events);
515 this._onTracingComplete();
516 },
517
518 _configureCpuProfilerSamplingInterval: function()
519 {
520 var intervalUs = WebInspector.settings.highResolutionCpuProfiling.get() ? 100 : 1000;
521 this._currentTarget.profilerAgent().setSamplingInterval(intervalUs, didC hangeInterval);
522
523 function didChangeInterval(error)
524 {
525 if (error)
526 WebInspector.console.error(error);
527 }
528 },
529
530 /**
531 * @param {string} categories
532 */
533 _startRecordingWithCategories: function(categories)
534 {
535 this._tracingManager.start(categories, "");
536 },
537
538 _onTracingStarted: function()
539 {
540 this._startCollectingTraceEvents(false);
541 },
542
543 /**
544 * @param {boolean} fromFile
545 */
546 _startCollectingTraceEvents: function(fromFile)
547 {
548 this.reset();
549 this._tracingModel.reset();
550 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin gStarted, { fromFile: fromFile });
551 },
552
553 /**
554 * @param {!WebInspector.Event} event
555 */
556 _onEventsCollected: function(event)
557 {
558 var traceEvents = /** @type {!Array.<!WebInspector.TracingManager.EventP ayload>} */ (event.data);
559 this._tracingModel.addEvents(traceEvents);
560 },
561
562 _onTracingComplete: function()
563 {
564 if (this._stopCallbackBarrier)
565 this._stopCallbackBarrier.callWhenDone(this._didStopRecordingTraceEv ents.bind(this));
566 else
567 this._didStopRecordingTraceEvents();
568 },
569
570 /**
571 * @param {?Protocol.Error} error
572 * @param {?ProfilerAgent.CPUProfile} cpuProfile
573 */
574 _didStopRecordingJSSamples: function(error, cpuProfile)
575 {
576 if (error)
577 WebInspector.console.error(error);
578 this._recordedCpuProfile = cpuProfile;
579 },
580
581 _didStopRecordingTraceEvents: function()
582 {
583 this._stopCallbackBarrier = null;
584
585 if (this._recordedCpuProfile) {
586 this._injectCpuProfileEvent(this._recordedCpuProfile);
587 this._recordedCpuProfile = null;
588 }
589 this._tracingModel.tracingComplete();
590
591 var events = this._tracingModel.devtoolsPageMetadataEvents();
592 var workerMetadataEvents = this._tracingModel.devtoolsWorkerMetadataEven ts();
593
594 this._resetProcessingState();
595 for (var i = 0, length = events.length; i < length; i++) {
596 var event = events[i];
597 var process = event.thread.process();
598 var startTime = event.startTime;
599
600 var endTime = Infinity;
601 if (i + 1 < length)
602 endTime = events[i + 1].startTime;
603
604 var threads = process.sortedThreads();
605 for (var j = 0; j < threads.length; j++) {
606 var thread = threads[j];
607 if (thread.name() === "WebCore: Worker" && !workerMetadataEvents .some(function(e) { return e.args["data"]["workerThreadId"] === thread.id(); }))
608 continue;
609 this._processThreadEvents(startTime, endTime, event.thread, thre ad);
610 }
611 }
612 this._resetProcessingState();
613
614 this._inspectedTargetEvents.sort(WebInspector.TracingModel.Event.compare StartTime);
615
616 if (this._cpuProfile) {
617 this._processCpuProfile(this._cpuProfile);
618 this._cpuProfile = null;
619 }
620 this._buildTimelineRecords();
621 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin gStopped);
622 },
623
624 /**
625 * @param {!ProfilerAgent.CPUProfile} cpuProfile
626 */
627 _injectCpuProfileEvent: function(cpuProfile)
628 {
629 var metaEvent = this._tracingModel.devtoolsPageMetadataEvents().peekLast ();
630 if (!metaEvent)
631 return;
632 var cpuProfileEvent = /** @type {!WebInspector.TracingManager.EventPaylo ad} */ ({
633 cat: WebInspector.TracingModel.DevToolsMetadataEventCategory,
634 ph: WebInspector.TracingModel.Phase.Instant,
635 ts: this._tracingModel.maximumRecordTime() * 1000,
636 pid: metaEvent.thread.process().id(),
637 tid: metaEvent.thread.id(),
638 name: WebInspector.TimelineModel.RecordType.CpuProfile,
639 args: { data: { cpuProfile: cpuProfile } }
640 });
641 this._tracingModel.addEvents([cpuProfileEvent]);
642 },
643
644 /**
645 * @param {!ProfilerAgent.CPUProfile} cpuProfile
646 */
647 _processCpuProfile: function(cpuProfile)
648 {
649 var jsSamples = WebInspector.TimelineJSProfileProcessor.generateTracingE ventsFromCpuProfile(this, cpuProfile);
650 this._inspectedTargetEvents = this._inspectedTargetEvents.mergeOrdered(j sSamples, WebInspector.TracingModel.Event.orderedCompareStartTime);
651 this._setMainThreadEvents(this.mainThreadEvents().mergeOrdered(jsSamples , WebInspector.TracingModel.Event.orderedCompareStartTime));
652 var jsFrameEvents = WebInspector.TimelineJSProfileProcessor.generateJSFr ameEvents(this.mainThreadEvents());
653 this._setMainThreadEvents(jsFrameEvents.mergeOrdered(this.mainThreadEven ts(), WebInspector.TracingModel.Event.orderedCompareStartTime));
654 this._inspectedTargetEvents = jsFrameEvents.mergeOrdered(this._inspected TargetEvents, WebInspector.TracingModel.Event.orderedCompareStartTime);
655 },
656
657 _buildTimelineRecords: function()
658 {
659 var topLevelRecords = this._buildTimelineRecordsForThread(this.mainThrea dEvents());
660
661 /**
662 * @param {!WebInspector.TimelineModel.Record} a
663 * @param {!WebInspector.TimelineModel.Record} b
664 * @return {number}
665 */
666 function compareRecordStartTime(a, b)
667 {
668 // Never return 0 as otherwise equal records would be merged.
669 return (a.startTime() <= b.startTime()) ? -1 : +1;
670 }
671
672 /**
673 * @param {!WebInspector.TimelineModel.VirtualThread} virtualThread
674 * @this {!WebInspector.TimelineModel}
675 */
676 function processVirtualThreadEvents(virtualThread)
677 {
678 var threadRecords = this._buildTimelineRecordsForThread(virtualThrea d.events);
679 topLevelRecords = topLevelRecords.mergeOrdered(threadRecords, compar eRecordStartTime);
680 }
681 this.virtualThreads().forEach(processVirtualThreadEvents.bind(this));
682
683
684 for (var i = 0; i < topLevelRecords.length; i++) {
685 var record = topLevelRecords[i];
686 if (record.type() === WebInspector.TimelineModel.RecordType.Program)
687 this._mainThreadTasks.push(record);
688 if (record.type() === WebInspector.TimelineModel.RecordType.GPUTask)
689 this._gpuThreadTasks.push(record);
690 }
691 this._records = topLevelRecords;
692 },
693
694 /**
695 * @param {!Array.<!WebInspector.TracingModel.Event>} threadEvents
696 * @return {!Array.<!WebInspector.TimelineModel.Record>}
697 */
698 _buildTimelineRecordsForThread: function(threadEvents)
699 {
700 var recordStack = [];
701 var topLevelRecords = [];
702
703 for (var i = 0, size = threadEvents.length; i < size; ++i) {
704 var event = threadEvents[i];
705 for (var top = recordStack.peekLast(); top && top._event.endTime <= event.startTime; top = recordStack.peekLast()) {
706 recordStack.pop();
707 if (!recordStack.length)
708 topLevelRecords.push(top);
709 }
710 if (event.phase === WebInspector.TracingModel.Phase.AsyncEnd || even t.phase === WebInspector.TracingModel.Phase.NestableAsyncEnd)
711 continue;
712 var parentRecord = recordStack.peekLast();
713 // Maintain the back-end logic of old timeline, skip console.time() / console.timeEnd() that are not properly nested.
714 if (WebInspector.TracingModel.isAsyncBeginPhase(event.phase) && pare ntRecord && event.endTime > parentRecord._event.endTime)
715 continue;
716 var record = new WebInspector.TimelineModel.Record(this, event);
717 if (WebInspector.TimelineUIUtils.isMarkerEvent(event))
718 this._eventDividerRecords.push(record);
719 if (!this._recordFilter.accept(record))
720 continue;
721 if (parentRecord)
722 parentRecord._addChild(record);
723 if (event.endTime)
724 recordStack.push(record);
725 }
726
727 if (recordStack.length)
728 topLevelRecords.push(recordStack[0]);
729
730 return topLevelRecords;
731 },
732
733 _resetProcessingState: function()
734 {
735 this._sendRequestEvents = {};
736 this._timerEvents = {};
737 this._requestAnimationFrameEvents = {};
738 this._invalidationTracker = new WebInspector.InvalidationTracker();
739 this._layoutInvalidate = {};
740 this._lastScheduleStyleRecalculation = {};
741 this._webSocketCreateEvents = {};
742 this._paintImageEventByPixelRefId = {};
743 this._lastPaintForLayer = {};
744 this._lastRecalculateStylesEvent = null;
745 this._currentScriptEvent = null;
746 this._eventStack = [];
747 },
748
749 /**
750 * @param {number} startTime
751 * @param {?number} endTime
752 * @param {!WebInspector.TracingModel.Thread} mainThread
753 * @param {!WebInspector.TracingModel.Thread} thread
754 */
755 _processThreadEvents: function(startTime, endTime, mainThread, thread)
756 {
757 var events = thread.events();
758 var length = events.length;
759 var i = events.lowerBound(startTime, function (time, event) { return tim e - event.startTime });
760
761 var threadEvents;
762 if (thread === mainThread) {
763 threadEvents = this._mainThreadEvents;
764 this._mainThreadAsyncEvents = this._mainThreadAsyncEvents.concat(thr ead.asyncEvents());
765 } else {
766 var virtualThread = new WebInspector.TimelineModel.VirtualThread(thr ead.name());
767 threadEvents = virtualThread.events;
768 virtualThread.asyncEvents = virtualThread.asyncEvents.concat(thread. asyncEvents());
769 this._virtualThreads.push(virtualThread);
770 }
771
772 this._eventStack = [];
773 for (; i < length; i++) {
774 var event = events[i];
775 if (endTime && event.startTime >= endTime)
776 break;
777 this._processEvent(event);
778 threadEvents.push(event);
779 this._inspectedTargetEvents.push(event);
780 }
781 },
782
783 /**
784 * @param {!WebInspector.TracingModel.Event} event
785 */
786 _processEvent: function(event)
787 {
788 var recordTypes = WebInspector.TimelineModel.RecordType;
789
790 var eventStack = this._eventStack;
791 while (eventStack.length && eventStack.peekLast().endTime < event.startT ime)
792 eventStack.pop();
793 var duration = event.duration;
794 if (duration) {
795 if (eventStack.length) {
796 var parent = eventStack.peekLast();
797 parent.selfTime -= duration;
798 }
799 event.selfTime = duration;
800 eventStack.push(event);
801 }
802
803 if (this._currentScriptEvent && event.startTime > this._currentScriptEve nt.endTime)
804 this._currentScriptEvent = null;
805
806 switch (event.name) {
807 case recordTypes.CallStack:
808 var lastMainThreadEvent = this.mainThreadEvents().peekLast();
809 if (lastMainThreadEvent && event.args["stack"] && event.args["stack" ].length)
810 lastMainThreadEvent.stackTrace = event.args["stack"];
811 break;
812
813 case recordTypes.CpuProfile:
814 this._cpuProfile = event.args["data"]["cpuProfile"];
815 break;
816
817 case recordTypes.ResourceSendRequest:
818 this._sendRequestEvents[event.args["data"]["requestId"]] = event;
819 event.imageURL = event.args["data"]["url"];
820 break;
821
822 case recordTypes.ResourceReceiveResponse:
823 case recordTypes.ResourceReceivedData:
824 case recordTypes.ResourceFinish:
825 event.initiator = this._sendRequestEvents[event.args["data"]["reques tId"]];
826 if (event.initiator)
827 event.imageURL = event.initiator.imageURL;
828 break;
829
830 case recordTypes.TimerInstall:
831 this._timerEvents[event.args["data"]["timerId"]] = event;
832 break;
833
834 case recordTypes.TimerFire:
835 event.initiator = this._timerEvents[event.args["data"]["timerId"]];
836 break;
837
838 case recordTypes.RequestAnimationFrame:
839 this._requestAnimationFrameEvents[event.args["data"]["id"]] = event;
840 break;
841
842 case recordTypes.FireAnimationFrame:
843 event.initiator = this._requestAnimationFrameEvents[event.args["data "]["id"]];
844 break;
845
846 case recordTypes.ScheduleStyleRecalculation:
847 this._lastScheduleStyleRecalculation[event.args["frame"]] = event;
848 break;
849
850 case recordTypes.RecalculateStyles:
851 this._invalidationTracker.didRecalcStyle(event);
852 event.initiator = this._lastScheduleStyleRecalculation[event.args["f rame"]];
853 this._lastRecalculateStylesEvent = event;
854 break;
855
856 case recordTypes.StyleRecalcInvalidationTracking:
857 case recordTypes.LayoutInvalidationTracking:
858 case recordTypes.LayerInvalidationTracking:
859 case recordTypes.PaintInvalidationTracking:
860 this._invalidationTracker.addInvalidation(event);
861 break;
862
863 case recordTypes.InvalidateLayout:
864 // Consider style recalculation as a reason for layout invalidation,
865 // but only if we had no earlier layout invalidation records.
866 var layoutInitator = event;
867 var frameId = event.args["frame"];
868 if (!this._layoutInvalidate[frameId] && this._lastRecalculateStylesE vent && this._lastRecalculateStylesEvent.endTime > event.startTime)
869 layoutInitator = this._lastRecalculateStylesEvent.initiator;
870 this._layoutInvalidate[frameId] = layoutInitator;
871 break;
872
873 case recordTypes.Layout:
874 this._invalidationTracker.didLayout(event);
875 var frameId = event.args["beginData"]["frame"];
876 event.initiator = this._layoutInvalidate[frameId];
877 // In case we have no closing Layout event, endData is not available .
878 if (event.args["endData"]) {
879 event.backendNodeId = event.args["endData"]["rootNode"];
880 event.highlightQuad = event.args["endData"]["root"];
881 }
882 this._layoutInvalidate[frameId] = null;
883 if (this._currentScriptEvent)
884 event.warning = WebInspector.UIString("Forced synchronous layout is a possible performance bottleneck.");
885 break;
886
887 case recordTypes.WebSocketCreate:
888 this._webSocketCreateEvents[event.args["data"]["identifier"]] = even t;
889 break;
890
891 case recordTypes.WebSocketSendHandshakeRequest:
892 case recordTypes.WebSocketReceiveHandshakeResponse:
893 case recordTypes.WebSocketDestroy:
894 event.initiator = this._webSocketCreateEvents[event.args["data"]["id entifier"]];
895 break;
896
897 case recordTypes.EvaluateScript:
898 case recordTypes.FunctionCall:
899 if (!this._currentScriptEvent)
900 this._currentScriptEvent = event;
901 break;
902
903 case recordTypes.SetLayerTreeId:
904 this._inspectedTargetLayerTreeId = event.args["layerTreeId"];
905 break;
906
907 case recordTypes.Paint:
908 this._invalidationTracker.didPaint(event);
909 event.highlightQuad = event.args["data"]["clip"];
910 event.backendNodeId = event.args["data"]["nodeId"];
911 var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLay er);
912 if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== th is._inspectedTargetLayerTreeId)
913 break;
914 // Only keep layer paint events, skip paints for subframes that get painted to the same layer as parent.
915 if (!event.args["data"]["layerId"])
916 break;
917 this._lastPaintForLayer[layerUpdateEvent.args["layerId"]] = event;
918 break;
919
920 case recordTypes.PictureSnapshot:
921 var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLay er);
922 if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== th is._inspectedTargetLayerTreeId)
923 break;
924 var paintEvent = this._lastPaintForLayer[layerUpdateEvent.args["laye rId"]];
925 if (paintEvent)
926 paintEvent.picture = event;
927 break;
928
929 case recordTypes.ScrollLayer:
930 event.backendNodeId = event.args["data"]["nodeId"];
931 break;
932
933 case recordTypes.PaintImage:
934 event.backendNodeId = event.args["data"]["nodeId"];
935 event.imageURL = event.args["data"]["url"];
936 break;
937
938 case recordTypes.DecodeImage:
939 case recordTypes.ResizeImage:
940 var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage );
941 if (!paintImageEvent) {
942 var decodeLazyPixelRefEvent = this._findAncestorEvent(recordType s.DecodeLazyPixelRef);
943 paintImageEvent = decodeLazyPixelRefEvent && this._paintImageEve ntByPixelRefId[decodeLazyPixelRefEvent.args["LazyPixelRef"]];
944 }
945 if (!paintImageEvent)
946 break;
947 event.backendNodeId = paintImageEvent.backendNodeId;
948 event.imageURL = paintImageEvent.imageURL;
949 break;
950
951 case recordTypes.DrawLazyPixelRef:
952 var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage );
953 if (!paintImageEvent)
954 break;
955 this._paintImageEventByPixelRefId[event.args["LazyPixelRef"]] = pain tImageEvent;
956 event.backendNodeId = paintImageEvent.backendNodeId;
957 event.imageURL = paintImageEvent.imageURL;
958 break;
959 }
960 },
961
962 /**
963 * @param {string} name
964 * @return {?WebInspector.TracingModel.Event}
965 */
966 _findAncestorEvent: function(name)
967 {
968 for (var i = this._eventStack.length - 1; i >= 0; --i) {
969 var event = this._eventStack[i];
970 if (event.name === name)
971 return event;
972 }
973 return null;
974 },
975
976 /**
233 * @param {!Blob} file 977 * @param {!Blob} file
234 * @param {!WebInspector.Progress} progress 978 * @param {!WebInspector.Progress} progress
235 */ 979 */
236 loadFromFile: function(file, progress) 980 loadFromFile: function(file, progress)
237 { 981 {
238 var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this, progress); 982 var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this, progress);
239 var fileReader = this._createFileReader(file, delegate); 983 var fileReader = this._createFileReader(file, delegate);
240 var loader = this.createLoader(fileReader, progress); 984 var loader = this.createLoader(fileReader, progress);
241 fileReader.start(loader); 985 fileReader.start(loader);
242 }, 986 },
243 987
244 /**
245 * @param {!WebInspector.ChunkedFileReader} fileReader
246 * @param {!WebInspector.Progress} progress
247 * @return {!WebInspector.OutputStream}
248 */
249 createLoader: function(fileReader, progress)
250 {
251 throw new Error("Not implemented.");
252 },
253
254 _createFileReader: function(file, delegate) 988 _createFileReader: function(file, delegate)
255 { 989 {
256 return new WebInspector.ChunkedFileReader(file, WebInspector.TimelineMod el.TransferChunkLengthBytes, delegate); 990 return new WebInspector.ChunkedFileReader(file, WebInspector.TimelineMod el.TransferChunkLengthBytes, delegate);
257 }, 991 },
258 992
259 _createFileWriter: function() 993 _createFileWriter: function()
260 { 994 {
261 return new WebInspector.FileOutputStream(); 995 return new WebInspector.FileOutputStream();
262 }, 996 },
263 997
264 saveToFile: function() 998 saveToFile: function()
265 { 999 {
266 var now = new Date(); 1000 var now = new Date();
267 var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json"; 1001 var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json";
268 var stream = this._createFileWriter(); 1002 var stream = this._createFileWriter();
269 1003
270 /** 1004 /**
271 * @param {boolean} accepted 1005 * @param {boolean} accepted
272 * @this {WebInspector.TimelineModel} 1006 * @this {WebInspector.TimelineModel}
273 */ 1007 */
274 function callback(accepted) 1008 function callback(accepted)
275 { 1009 {
276 if (!accepted) 1010 if (!accepted)
277 return; 1011 return;
278 this.writeToStream(stream); 1012 this.writeToStream(stream);
279 } 1013 }
280 stream.open(fileName, callback.bind(this)); 1014 stream.open(fileName, callback.bind(this));
281 }, 1015 },
282 1016
283 /**
284 * @param {!WebInspector.OutputStream} stream
285 */
286 writeToStream: function(stream)
287 {
288 throw new Error("Not implemented.");
289 },
290
291 reset: function() 1017 reset: function()
292 { 1018 {
1019 this._virtualThreads = [];
1020 this._mainThreadEvents = [];
1021 this._mainThreadAsyncEvents = [];
1022 this._inspectedTargetEvents = [];
1023
293 this._records = []; 1024 this._records = [];
294 this._minimumRecordTime = 0;
295 this._maximumRecordTime = 0;
296 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ 1025 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */
297 this._mainThreadTasks = []; 1026 this._mainThreadTasks = [];
298 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ 1027 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */
299 this._gpuThreadTasks = []; 1028 this._gpuThreadTasks = [];
300 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ 1029 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */
301 this._eventDividerRecords = []; 1030 this._eventDividerRecords = [];
302 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsC leared); 1031 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsC leared);
303 }, 1032 },
304 1033
305 /** 1034 /**
306 * @return {number} 1035 * @return {number}
307 */ 1036 */
308 minimumRecordTime: function() 1037 minimumRecordTime: function()
309 { 1038 {
310 throw new Error("Not implemented."); 1039 return this._tracingModel.minimumRecordTime();
311 }, 1040 },
312 1041
313 /** 1042 /**
314 * @return {number} 1043 * @return {number}
315 */ 1044 */
316 maximumRecordTime: function() 1045 maximumRecordTime: function()
317 { 1046 {
318 throw new Error("Not implemented."); 1047 return this._tracingModel.maximumRecordTime();
1048 },
1049
1050 /**
1051 * @return {!Array.<!WebInspector.TracingModel.Event>}
1052 */
1053 inspectedTargetEvents: function()
1054 {
1055 return this._inspectedTargetEvents;
1056 },
1057
1058 /**
1059 * @return {!Array.<!WebInspector.TracingModel.Event>}
1060 */
1061 mainThreadEvents: function()
1062 {
1063 return this._mainThreadEvents;
1064 },
1065
1066 /**
1067 * @param {!Array.<!WebInspector.TracingModel.Event>} events
1068 */
1069 _setMainThreadEvents: function(events)
1070 {
1071 this._mainThreadEvents = events;
1072 },
1073
1074 /**
1075 * @return {!Array.<!Array.<!WebInspector.TracingModel.Event>>}
1076 */
1077 mainThreadAsyncEvents: function()
1078 {
1079 return this._mainThreadAsyncEvents;
1080 },
1081
1082 /**
1083 * @return {!Array.<!WebInspector.TimelineModel.VirtualThread>}
1084 */
1085 virtualThreads: function()
1086 {
1087 return this._virtualThreads;
1088 },
1089
1090 /**
1091 * @param {!WebInspector.ChunkedFileReader} fileReader
1092 * @param {!WebInspector.Progress} progress
1093 * @return {!WebInspector.OutputStream}
1094 */
1095 createLoader: function(fileReader, progress)
1096 {
1097 return new WebInspector.TracingModelLoader(this, fileReader, progress);
1098 },
1099
1100 /**
1101 * @param {!WebInspector.OutputStream} stream
1102 */
1103 writeToStream: function(stream)
1104 {
1105 var saver = new WebInspector.TracingTimelineSaver(stream);
1106 this._tracingModel.writeToStream(stream, saver);
319 }, 1107 },
320 1108
321 /** 1109 /**
322 * @return {boolean} 1110 * @return {boolean}
323 */ 1111 */
324 isEmpty: function() 1112 isEmpty: function()
325 { 1113 {
326 return this.minimumRecordTime() === 0 && this.maximumRecordTime() === 0; 1114 return this.minimumRecordTime() === 0 && this.maximumRecordTime() === 0;
327 }, 1115 },
328 1116
(...skipping 14 matching lines...) Expand all
343 }, 1131 },
344 1132
345 /** 1133 /**
346 * @return {!Array.<!WebInspector.TimelineModel.Record>} 1134 * @return {!Array.<!WebInspector.TimelineModel.Record>}
347 */ 1135 */
348 eventDividerRecords: function() 1136 eventDividerRecords: function()
349 { 1137 {
350 return this._eventDividerRecords; 1138 return this._eventDividerRecords;
351 }, 1139 },
352 1140
1141
353 __proto__: WebInspector.Object.prototype 1142 __proto__: WebInspector.Object.prototype
354 } 1143 }
355 1144
356 /** 1145 /**
357 * @interface
358 */
359 WebInspector.TimelineModel.Record = function()
360 {
361 }
362
363 WebInspector.TimelineModel.Record.prototype = {
364 /**
365 * @return {?Array.<!ConsoleAgent.CallFrame>}
366 */
367 callSiteStackTrace: function() { },
368
369 /**
370 * @return {?WebInspector.TimelineModel.Record}
371 */
372 initiator: function() { },
373
374 /**
375 * @return {?WebInspector.Target}
376 */
377 target: function() { },
378
379 /**
380 * @return {number}
381 */
382 selfTime: function() { },
383
384 /**
385 * @return {!Array.<!WebInspector.TimelineModel.Record>}
386 */
387 children: function() { },
388
389 /**
390 * @return {number}
391 */
392 startTime: function() { },
393
394 /**
395 * @return {string}
396 */
397 thread: function() { },
398
399 /**
400 * @return {number}
401 */
402 endTime: function() { },
403
404 /**
405 * @param {number} endTime
406 */
407 setEndTime: function(endTime) { },
408
409 /**
410 * @return {!Object}
411 */
412 data: function() { },
413
414 /**
415 * @return {string}
416 */
417 type: function() { },
418
419 /**
420 * @return {string}
421 */
422 frameId: function() { },
423
424 /**
425 * @return {?Array.<!ConsoleAgent.CallFrame>}
426 */
427 stackTrace: function() { },
428
429 /**
430 * @param {string} key
431 * @return {?Object}
432 */
433 getUserObject: function(key) { },
434
435 /**
436 * @param {string} key
437 * @param {?Object|undefined} value
438 */
439 setUserObject: function(key, value) { },
440
441 /**
442 * @return {?Array.<string>}
443 */
444 warnings: function() { }
445 }
446
447 /**
448 * @constructor 1146 * @constructor
449 */ 1147 */
450 WebInspector.TimelineModel.Filter = function() 1148 WebInspector.TimelineModel.Filter = function()
451 { 1149 {
452 /** @type {!WebInspector.TimelineModel} */ 1150 /** @type {!WebInspector.TimelineModel} */
453 this._model; 1151 this._model;
454 } 1152 }
455 1153
456 WebInspector.TimelineModel.Filter.prototype = { 1154 WebInspector.TimelineModel.Filter.prototype = {
457 /** 1155 /**
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 case FileError.NOT_READABLE_ERR: 1308 case FileError.NOT_READABLE_ERR:
611 WebInspector.console.error(WebInspector.UIString("File \"%s\" is not readable", reader.fileName())); 1309 WebInspector.console.error(WebInspector.UIString("File \"%s\" is not readable", reader.fileName()));
612 break; 1310 break;
613 case FileError.ABORT_ERR: 1311 case FileError.ABORT_ERR:
614 break; 1312 break;
615 default: 1313 default:
616 WebInspector.console.error(WebInspector.UIString("An error occurred while reading the file \"%s\"", reader.fileName())); 1314 WebInspector.console.error(WebInspector.UIString("An error occurred while reading the file \"%s\"", reader.fileName()));
617 } 1315 }
618 } 1316 }
619 } 1317 }
1318
1319
1320 /**
1321 * @interface
1322 */
1323 WebInspector.TraceEventFilter = function() { }
1324
1325 WebInspector.TraceEventFilter.prototype = {
1326 /**
1327 * @param {!WebInspector.TracingModel.Event} event
1328 * @return {boolean}
1329 */
1330 accept: function(event) { }
1331 }
1332
1333 /**
1334 * @constructor
1335 * @implements {WebInspector.TraceEventFilter}
1336 * @param {!Array.<string>} eventNames
1337 */
1338 WebInspector.TraceEventNameFilter = function(eventNames)
1339 {
1340 this._eventNames = eventNames.keySet();
1341 }
1342
1343 WebInspector.TraceEventNameFilter.prototype = {
1344 /**
1345 * @param {!WebInspector.TracingModel.Event} event
1346 * @return {boolean}
1347 */
1348 accept: function(event)
1349 {
1350 throw new Error("Not implemented.");
1351 }
1352 }
1353
1354 /**
1355 * @constructor
1356 * @extends {WebInspector.TraceEventNameFilter}
1357 * @param {!Array.<string>} includeNames
1358 */
1359 WebInspector.InclusiveTraceEventNameFilter = function(includeNames)
1360 {
1361 WebInspector.TraceEventNameFilter.call(this, includeNames)
1362 }
1363
1364 WebInspector.InclusiveTraceEventNameFilter.prototype = {
1365 /**
1366 * @override
1367 * @param {!WebInspector.TracingModel.Event} event
1368 * @return {boolean}
1369 */
1370 accept: function(event)
1371 {
1372 return event.category === WebInspector.TracingModel.ConsoleEventCategory || !!this._eventNames[event.name];
1373 },
1374 __proto__: WebInspector.TraceEventNameFilter.prototype
1375 }
1376
1377 /**
1378 * @constructor
1379 * @extends {WebInspector.TraceEventNameFilter}
1380 * @param {!Array.<string>} excludeNames
1381 */
1382 WebInspector.ExclusiveTraceEventNameFilter = function(excludeNames)
1383 {
1384 WebInspector.TraceEventNameFilter.call(this, excludeNames)
1385 }
1386
1387 WebInspector.ExclusiveTraceEventNameFilter.prototype = {
1388 /**
1389 * @override
1390 * @param {!WebInspector.TracingModel.Event} event
1391 * @return {boolean}
1392 */
1393 accept: function(event)
1394 {
1395 return !this._eventNames[event.name];
1396 },
1397 __proto__: WebInspector.TraceEventNameFilter.prototype
1398 }
1399
1400 /**
1401 * @constructor
1402 * @implements {WebInspector.OutputStream}
1403 * @param {!WebInspector.TimelineModel} model
1404 * @param {!{cancel: function()}} reader
1405 * @param {!WebInspector.Progress} progress
1406 */
1407 WebInspector.TracingModelLoader = function(model, reader, progress)
1408 {
1409 this._model = model;
1410 this._reader = reader;
1411 this._progress = progress;
1412 this._buffer = "";
1413 this._firstChunk = true;
1414 this._loader = new WebInspector.TracingModel.Loader(model._tracingModel);
1415 }
1416
1417 WebInspector.TracingModelLoader.prototype = {
1418 /**
1419 * @param {string} chunk
1420 */
1421 write: function(chunk)
1422 {
1423 var data = this._buffer + chunk;
1424 var lastIndex = 0;
1425 var index;
1426 do {
1427 index = lastIndex;
1428 lastIndex = WebInspector.TextUtils.findBalancedCurlyBrackets(data, i ndex);
1429 } while (lastIndex !== -1)
1430
1431 var json = data.slice(0, index) + "]";
1432 this._buffer = data.slice(index);
1433
1434 if (!index)
1435 return;
1436
1437 if (this._firstChunk) {
1438 this._model._startCollectingTraceEvents(true);
1439 } else {
1440 var commaIndex = json.indexOf(",");
1441 if (commaIndex !== -1)
1442 json = json.slice(commaIndex + 1);
1443 json = "[" + json;
1444 }
1445
1446 var items;
1447 try {
1448 items = /** @type {!Array.<!WebInspector.TracingManager.EventPayload >} */ (JSON.parse(json));
1449 } catch (e) {
1450 this._reportErrorAndCancelLoading("Malformed timeline data: " + e);
1451 return;
1452 }
1453
1454 if (this._firstChunk) {
1455 this._firstChunk = false;
1456 if (this._looksLikeAppVersion(items[0])) {
1457 this._reportErrorAndCancelLoading("Old Timeline format is not su pported.");
1458 return;
1459 }
1460 }
1461
1462 try {
1463 this._loader.loadNextChunk(items);
1464 } catch(e) {
1465 this._reportErrorAndCancelLoading("Malformed timeline data: " + e);
1466 return;
1467 }
1468 },
1469
1470 _reportErrorAndCancelLoading: function(messsage)
1471 {
1472 WebInspector.console.error(messsage);
1473 this._model._onTracingComplete();
1474 this._model.reset();
1475 this._reader.cancel();
1476 this._progress.done();
1477 },
1478
1479 _looksLikeAppVersion: function(item)
1480 {
1481 return typeof item === "string" && item.indexOf("Chrome") !== -1;
1482 },
1483
1484 close: function()
1485 {
1486 this._loader.finish();
1487 this._model._onTracingComplete();
1488 }
1489 }
1490
1491 /**
1492 * @constructor
1493 * @param {!WebInspector.OutputStream} stream
1494 * @implements {WebInspector.OutputStreamDelegate}
1495 */
1496 WebInspector.TracingTimelineSaver = function(stream)
1497 {
1498 this._stream = stream;
1499 }
1500
1501 WebInspector.TracingTimelineSaver.prototype = {
1502 onTransferStarted: function()
1503 {
1504 this._stream.write("[");
1505 },
1506
1507 onTransferFinished: function()
1508 {
1509 this._stream.write("]");
1510 },
1511
1512 /**
1513 * @param {!WebInspector.ChunkedReader} reader
1514 */
1515 onChunkTransferred: function(reader) { },
1516
1517 /**
1518 * @param {!WebInspector.ChunkedReader} reader
1519 * @param {!Event} event
1520 */
1521 onError: function(reader, event) { },
1522 }
1523
1524 /**
1525 * @constructor
1526 * @param {!WebInspector.TracingModel.Event} event
1527 */
1528 WebInspector.InvalidationTrackingEvent = function(event)
1529 {
1530 this.type = event.name;
1531 this.frameId = event.args["data"]["frame"];
1532 this.nodeId = event.args["data"]["nodeId"];
1533 this.nodeName = event.args["data"]["nodeName"];
1534 this.paintId = event.args["data"]["paintId"];
1535 this.reason = event.args["data"]["reason"];
1536 this.stackTrace = event.args["data"]["stackTrace"];
1537 }
1538
1539 /**
1540 * @constructor
1541 */
1542 WebInspector.InvalidationTracker = function()
1543 {
1544 this._initializePerFrameState();
1545 }
1546
1547 WebInspector.InvalidationTracker.prototype = {
1548 /**
1549 * @param {!WebInspector.TracingModel.Event} event
1550 */
1551 addInvalidation: function(event)
1552 {
1553 var invalidation = new WebInspector.InvalidationTrackingEvent(event);
1554
1555 this._startNewFrameIfNeeded();
1556 if (!invalidation.nodeId && !invalidation.paintId) {
1557 console.error("Invalidation lacks node information.");
1558 console.error(invalidation);
1559 }
1560
1561 // Record the paintIds for style recalc or layout invalidations.
1562 // FIXME: This O(n^2) loop could be optimized with a map.
1563 var recordTypes = WebInspector.TimelineModel.RecordType;
1564 if (invalidation.type == recordTypes.PaintInvalidationTracking)
1565 this._invalidationEvents.forEach(updatePaintId);
1566 else
1567 this._invalidationEvents.push(invalidation);
1568
1569 function updatePaintId(invalidationToUpdate)
1570 {
1571 if (invalidationToUpdate.nodeId !== invalidation.nodeId)
1572 return;
1573 if (invalidationToUpdate.type === recordTypes.StyleRecalcInvalidatio nTracking
1574 || invalidationToUpdate.type === recordTypes.LayoutInvalidat ionTracking) {
1575 invalidationToUpdate.paintId = invalidation.paintId;
1576 }
1577 }
1578 },
1579
1580 /**
1581 * @param {!WebInspector.TracingModel.Event} styleRecalcEvent
1582 */
1583 didRecalcStyle: function(styleRecalcEvent)
1584 {
1585 var recalcFrameId = styleRecalcEvent.args["frame"];
1586 var index = this._lastStyleRecalcEventIndex;
1587 var invalidationCount = this._invalidationEvents.length;
1588 for (; index < invalidationCount; index++) {
1589 var invalidation = this._invalidationEvents[index];
1590 if (invalidation.type !== WebInspector.TimelineModel.RecordType.Styl eRecalcInvalidationTracking)
1591 continue;
1592 if (invalidation.frameId === recalcFrameId)
1593 this._addInvalidationTrackingEvent(styleRecalcEvent, invalidatio n);
1594 }
1595
1596 this._lastStyleRecalcEventIndex = invalidationCount;
1597 },
1598
1599 /**
1600 * @param {!WebInspector.TracingModel.Event} layoutEvent
1601 */
1602 didLayout: function(layoutEvent)
1603 {
1604 var layoutFrameId = layoutEvent.args["beginData"]["frame"];
1605 var index = this._lastLayoutEventIndex;
1606 var invalidationCount = this._invalidationEvents.length;
1607 for (; index < invalidationCount; index++) {
1608 var invalidation = this._invalidationEvents[index];
1609 if (invalidation.type !== WebInspector.TimelineModel.RecordType.Layo utInvalidationTracking)
1610 continue;
1611 if (invalidation.frameId === layoutFrameId)
1612 this._addInvalidationTrackingEvent(layoutEvent, invalidation);
1613 }
1614
1615 this._lastLayoutEventIndex = invalidationCount;
1616 },
1617
1618 /**
1619 * @param {!WebInspector.TracingModel.Event} paintEvent
1620 */
1621 didPaint: function(paintEvent)
1622 {
1623 this._didPaint = true;
1624
1625 // If a paint doesn't have a corresponding graphics layer id, it paints
1626 // into its parent so add an effectivePaintId to these events.
1627 var layerId = paintEvent.args["data"]["layerId"];
1628 if (layerId)
1629 this._lastPaintWithLayer = paintEvent;
1630 if (!this._lastPaintWithLayer) {
1631 console.error("Failed to find the paint container for a paint event. ");
1632 return;
1633 }
1634
1635 var effectivePaintId = this._lastPaintWithLayer.args["data"]["nodeId"];
1636 var frameId = paintEvent.args["data"]["frame"];
1637 this._invalidationEvents.forEach(recordInvalidationForPaint.bind(this));
1638
1639 /**
1640 * @param {!WebInspector.InvalidationTrackingEvent} invalidation
1641 * @this {WebInspector.InvalidationTracker}
1642 */
1643 function recordInvalidationForPaint(invalidation)
1644 {
1645 if (invalidation.paintId === effectivePaintId && invalidation.frameI d === frameId)
1646 this._addInvalidationTrackingEvent(paintEvent, invalidation);
1647 }
1648 },
1649
1650 /**
1651 * @param {!WebInspector.TracingModel.Event} event
1652 * @param {!WebInspector.InvalidationTrackingEvent} invalidation
1653 */
1654 _addInvalidationTrackingEvent: function(event, invalidation)
1655 {
1656 if (!event.invalidationTrackingEvents)
1657 event.invalidationTrackingEvents = [ invalidation ];
1658 else
1659 event.invalidationTrackingEvents.push(invalidation);
1660 },
1661
1662 _startNewFrameIfNeeded: function()
1663 {
1664 if (!this._didPaint)
1665 return;
1666
1667 this._initializePerFrameState();
1668 },
1669
1670 _initializePerFrameState: function()
1671 {
1672 /** @type {!Array.<!WebInspector.InvalidationTrackingEvent>} */
1673 this._invalidationEvents = [];
1674 this._lastStyleRecalcEventIndex = 0;
1675 this._lastLayoutEventIndex = 0;
1676 this._lastPaintWithLayer = undefined;
1677 this._didPaint = false;
1678 }
1679 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698