OLD | NEW |
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 13 matching lines...) Expand all Loading... |
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 * @extends {WebInspector.Object} | 33 * @extends {WebInspector.Object} |
34 * @param {!WebInspector.TimelineManager} timelineManager | 34 * @param {!WebInspector.Target} target |
35 */ | 35 */ |
36 WebInspector.TimelineModel = function(timelineManager) | 36 WebInspector.TimelineModel = function(target) |
37 { | 37 { |
38 this._timelineManager = timelineManager; | |
39 this._filters = []; | 38 this._filters = []; |
40 this._bindings = new WebInspector.TimelineModel.InterRecordBindings(); | 39 this._target = target; |
41 | |
42 this.reset(); | |
43 | |
44 this._timelineManager.addEventListener(WebInspector.TimelineManager.EventTyp
es.TimelineEventRecorded, this._onRecordAdded, this); | |
45 this._timelineManager.addEventListener(WebInspector.TimelineManager.EventTyp
es.TimelineStarted, this._onStarted, this); | |
46 this._timelineManager.addEventListener(WebInspector.TimelineManager.EventTyp
es.TimelineStopped, this._onStopped, this); | |
47 this._timelineManager.addEventListener(WebInspector.TimelineManager.EventTyp
es.TimelineProgress, this._onProgress, this); | |
48 } | 40 } |
49 | 41 |
50 WebInspector.TimelineModel.TransferChunkLengthBytes = 5000000; | |
51 | |
52 WebInspector.TimelineModel.RecordType = { | 42 WebInspector.TimelineModel.RecordType = { |
53 Root: "Root", | 43 Root: "Root", |
54 Program: "Program", | 44 Program: "Program", |
55 EventDispatch: "EventDispatch", | 45 EventDispatch: "EventDispatch", |
56 | 46 |
57 GPUTask: "GPUTask", | 47 GPUTask: "GPUTask", |
58 | 48 |
59 RequestMainThreadFrame: "RequestMainThreadFrame", | 49 RequestMainThreadFrame: "RequestMainThreadFrame", |
60 BeginFrame: "BeginFrame", | 50 BeginFrame: "BeginFrame", |
61 ActivateLayerTree: "ActivateLayerTree", | 51 ActivateLayerTree: "ActivateLayerTree", |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 } | 140 } |
151 return processRecords(recordsArray, 0); | 141 return processRecords(recordsArray, 0); |
152 } | 142 } |
153 | 143 |
154 WebInspector.TimelineModel.prototype = { | 144 WebInspector.TimelineModel.prototype = { |
155 /** | 145 /** |
156 * @return {!WebInspector.Target} | 146 * @return {!WebInspector.Target} |
157 */ | 147 */ |
158 target: function() | 148 target: function() |
159 { | 149 { |
160 return this._timelineManager.target(); | 150 return this._target; |
161 }, | 151 }, |
162 | 152 |
163 /** | 153 /** |
164 * @return {boolean} | 154 * @return {boolean} |
165 */ | 155 */ |
166 loadedFromFile: function() | 156 loadedFromFile: function() |
167 { | 157 { |
168 return this._loadedFromFile; | 158 return false; |
169 }, | 159 }, |
170 | 160 |
171 /** | 161 /** |
172 * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspe
ctor.TimelineModel.Record,number)} preOrderCallback | 162 * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspe
ctor.TimelineModel.Record,number)} preOrderCallback |
173 * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspect
or.TimelineModel.Record,number)=} postOrderCallback | 163 * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspect
or.TimelineModel.Record,number)=} postOrderCallback |
174 */ | 164 */ |
175 forAllRecords: function(preOrderCallback, postOrderCallback) | 165 forAllRecords: function(preOrderCallback, postOrderCallback) |
176 { | 166 { |
177 WebInspector.TimelineModel.forAllRecords(this._records, preOrderCallback
, postOrderCallback); | 167 WebInspector.TimelineModel.forAllRecords(this._records, preOrderCallback
, postOrderCallback); |
178 }, | 168 }, |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 return false; | 217 return false; |
228 } | 218 } |
229 return true; | 219 return true; |
230 }, | 220 }, |
231 | 221 |
232 _filterChanged: function() | 222 _filterChanged: function() |
233 { | 223 { |
234 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordFi
lterChanged); | 224 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordFi
lterChanged); |
235 }, | 225 }, |
236 | 226 |
237 /** | |
238 * @param {boolean} captureStacks | |
239 * @param {boolean} captureMemory | |
240 */ | |
241 startRecording: function(captureStacks, captureMemory) | |
242 { | |
243 this._clientInitiatedRecording = true; | |
244 this.reset(); | |
245 var maxStackFrames = captureStacks ? 30 : 0; | |
246 this._bufferEvents = WebInspector.experimentsSettings.timelineNoLiveUpda
te.isEnabled(); | |
247 var includeGPUEvents = WebInspector.experimentsSettings.gpuTimeline.isEn
abled(); | |
248 var liveEvents = [ WebInspector.TimelineModel.RecordType.BeginFrame, | |
249 WebInspector.TimelineModel.RecordType.DrawFrame, | |
250 WebInspector.TimelineModel.RecordType.RequestMainThre
adFrame, | |
251 WebInspector.TimelineModel.RecordType.ActivateLayerTr
ee ]; | |
252 this._timelineManager.start(maxStackFrames, this._bufferEvents, liveEven
ts.join(","), captureMemory, includeGPUEvents, this._fireRecordingStarted.bind(t
his)); | |
253 }, | |
254 | |
255 stopRecording: function() | |
256 { | |
257 if (!this._clientInitiatedRecording) { | |
258 this._timelineManager.start(undefined, undefined, undefined, undefin
ed, undefined, stopTimeline.bind(this)); | |
259 return; | |
260 } | |
261 | |
262 /** | |
263 * Console started this one and we are just sniffing it. Initiate record
ing so that we | |
264 * could stop it. | |
265 * @this {WebInspector.TimelineModel} | |
266 */ | |
267 function stopTimeline() | |
268 { | |
269 this._timelineManager.stop(this._fireRecordingStopped.bind(this)); | |
270 } | |
271 | |
272 this._clientInitiatedRecording = false; | |
273 this._timelineManager.stop(this._fireRecordingStopped.bind(this)); | |
274 }, | |
275 | |
276 willStartRecordingTraceEvents: function() | 227 willStartRecordingTraceEvents: function() |
277 { | 228 { |
278 this.reset(); | 229 this.reset(); |
279 this._fireRecordingStarted(); | 230 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin
gStarted); |
280 }, | 231 }, |
281 | 232 |
282 /** | 233 /** |
283 * @param {!Array.<!WebInspector.TracingModel.Event>} mainThreadEvents | 234 * @param {!Array.<!WebInspector.TracingModel.Event>} mainThreadEvents |
284 */ | 235 */ |
285 didStopRecordingTraceEvents: function(mainThreadEvents) | 236 didStopRecordingTraceEvents: function(mainThreadEvents) |
286 { | 237 { |
287 var recordStack = []; | 238 var recordStack = []; |
288 for (var i = 0, size = mainThreadEvents.length; i < size; ++i) { | 239 for (var i = 0, size = mainThreadEvents.length; i < size; ++i) { |
289 var event = mainThreadEvents[i]; | 240 var event = mainThreadEvents[i]; |
290 while (recordStack.length) { | 241 while (recordStack.length) { |
291 var top = recordStack.peekLast(); | 242 var top = recordStack.peekLast(); |
292 if (top._event.endTime >= event.startTime) | 243 if (top._event.endTime >= event.startTime) |
293 break; | 244 break; |
294 recordStack.pop(); | 245 recordStack.pop(); |
295 } | 246 } |
296 var parentRecord = recordStack.peekLast() || null; | 247 var parentRecord = recordStack.peekLast() || null; |
297 var record = new WebInspector.TimelineModel.TraceEventRecord(this, e
vent, parentRecord); | 248 var record = new WebInspector.TimelineModel.TraceEventRecord(this, e
vent, parentRecord); |
298 if (WebInspector.TimelineUIUtils.isEventDivider(record)) | 249 if (WebInspector.TimelineUIUtils.isEventDivider(record)) |
299 this._eventDividerRecords.push(record); | 250 this._eventDividerRecords.push(record); |
300 if (!recordStack.length) | 251 if (!recordStack.length) |
301 this._addTopLevelRecord(record); | 252 this._addTopLevelRecord(record); |
302 if (event.endTime) | 253 if (event.endTime) |
303 recordStack.push(record); | 254 recordStack.push(record); |
304 } | 255 } |
305 this._fireRecordingStopped(null, null); | 256 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin
gStopped); |
306 }, | 257 }, |
307 | 258 |
308 /** | 259 /** |
309 * @param {!WebInspector.TimelineModel.TraceEventRecord} record | 260 * @param {!WebInspector.TimelineModel.TraceEventRecord} record |
310 */ | 261 */ |
311 _addTopLevelRecord: function(record) | 262 _addTopLevelRecord: function(record) |
312 { | 263 { |
313 this._updateBoundaries(record); | 264 this._updateBoundaries(record); |
314 this._records.push(record); | 265 this._records.push(record); |
315 if (record.type() === WebInspector.TimelineModel.RecordType.Program) | 266 if (record.type() === WebInspector.TimelineModel.RecordType.Program) |
316 this._mainThreadTasks.push(record); | 267 this._mainThreadTasks.push(record); |
317 if (record.type() === WebInspector.TimelineModel.RecordType.GPUTask) | 268 if (record.type() === WebInspector.TimelineModel.RecordType.GPUTask) |
318 this._gpuThreadTasks.push(record); | 269 this._gpuThreadTasks.push(record); |
319 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordAd
ded, record); | 270 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordAd
ded, record); |
320 }, | 271 }, |
321 | 272 |
322 /** | 273 /** |
323 * @return {!Array.<!WebInspector.TimelineModel.Record>} | 274 * @return {!Array.<!WebInspector.TimelineModel.Record>} |
324 */ | 275 */ |
325 records: function() | 276 records: function() |
326 { | 277 { |
327 return this._records; | 278 return this._records; |
328 }, | 279 }, |
329 | 280 |
330 /** | 281 /** |
331 * @param {!WebInspector.Event} event | |
332 */ | |
333 _onRecordAdded: function(event) | |
334 { | |
335 if (this._collectionEnabled) | |
336 this._addRecord(/** @type {!TimelineAgent.TimelineEvent} */(event.da
ta)); | |
337 }, | |
338 | |
339 /** | |
340 * @param {!WebInspector.Event} event | |
341 */ | |
342 _onStarted: function(event) | |
343 { | |
344 if (event.data) { | |
345 // Started from console. | |
346 this._fireRecordingStarted(); | |
347 } | |
348 }, | |
349 | |
350 /** | |
351 * @param {!WebInspector.Event} event | |
352 */ | |
353 _onStopped: function(event) | |
354 { | |
355 if (event.data) { | |
356 // Stopped from console. | |
357 this._fireRecordingStopped(null, null); | |
358 } | |
359 }, | |
360 | |
361 /** | |
362 * @param {!WebInspector.Event} event | |
363 */ | |
364 _onProgress: function(event) | |
365 { | |
366 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin
gProgress, event.data); | |
367 }, | |
368 | |
369 _fireRecordingStarted: function() | |
370 { | |
371 this._collectionEnabled = true; | |
372 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin
gStarted); | |
373 }, | |
374 | |
375 /** | |
376 * @param {?Protocol.Error} error | |
377 * @param {?ProfilerAgent.CPUProfile} cpuProfile | |
378 */ | |
379 _fireRecordingStopped: function(error, cpuProfile) | |
380 { | |
381 this._bufferEvents = false; | |
382 this._collectionEnabled = false; | |
383 if (cpuProfile) | |
384 WebInspector.TimelineJSProfileProcessor.mergeJSProfileIntoTimeline(t
his, cpuProfile); | |
385 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.Recordin
gStopped); | |
386 }, | |
387 | |
388 /** | |
389 * @return {boolean} | 282 * @return {boolean} |
390 */ | 283 */ |
391 bufferEvents: function() | 284 bufferEvents: function() |
392 { | 285 { |
393 return this._bufferEvents; | 286 return false; |
394 }, | 287 }, |
395 | 288 |
396 /** | 289 /** |
397 * @param {!TimelineAgent.TimelineEvent} payload | |
398 */ | |
399 _addRecord: function(payload) | |
400 { | |
401 this._internStrings(payload); | |
402 this._payloads.push(payload); | |
403 | |
404 var record = this._innerAddRecord(payload, null); | |
405 this._updateBoundaries(record); | |
406 this._records.push(record); | |
407 if (record.type() === WebInspector.TimelineModel.RecordType.Program) | |
408 this._mainThreadTasks.push(record); | |
409 if (record.type() === WebInspector.TimelineModel.RecordType.GPUTask) | |
410 this._gpuThreadTasks.push(record); | |
411 | |
412 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordAd
ded, record); | |
413 }, | |
414 | |
415 /** | |
416 * @param {!TimelineAgent.TimelineEvent} payload | |
417 * @param {?WebInspector.TimelineModel.Record} parentRecord | |
418 * @return {!WebInspector.TimelineModel.Record} | |
419 * @this {!WebInspector.TimelineModel} | |
420 */ | |
421 _innerAddRecord: function(payload, parentRecord) | |
422 { | |
423 var record = new WebInspector.TimelineModel.RecordImpl(this, payload, pa
rentRecord); | |
424 if (WebInspector.TimelineUIUtils.isEventDivider(record)) | |
425 this._eventDividerRecords.push(record); | |
426 | |
427 for (var i = 0; payload.children && i < payload.children.length; ++i) | |
428 this._innerAddRecord.call(this, payload.children[i], record); | |
429 | |
430 record._calculateAggregatedStats(); | |
431 if (parentRecord) | |
432 parentRecord._selfTime -= record.endTime() - record.startTime(); | |
433 return record; | |
434 }, | |
435 | |
436 /** | |
437 * @param {!Blob} file | 290 * @param {!Blob} file |
438 * @param {!WebInspector.Progress} progress | 291 * @param {!WebInspector.Progress} progress |
439 */ | 292 */ |
440 loadFromFile: function(file, progress) | 293 loadFromFile: function(file, progress) |
441 { | 294 { |
442 var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this,
progress); | 295 throw new Error("Not implemented"); |
443 var fileReader = this._createFileReader(file, delegate); | |
444 var loader = new WebInspector.TimelineModelLoader(this, fileReader, prog
ress); | |
445 fileReader.start(loader); | |
446 }, | 296 }, |
447 | 297 |
448 /** | 298 /** |
449 * @param {string} url | 299 * @param {string} url |
450 * @param {!WebInspector.Progress} progress | 300 * @param {!WebInspector.Progress} progress |
451 */ | 301 */ |
452 loadFromURL: function(url, progress) | 302 loadFromURL: function(url, progress) |
453 { | 303 { |
454 var delegate = new WebInspector.TimelineModelLoadFromFileDelegate(this,
progress); | 304 throw new Error("Not implemented"); |
455 var urlReader = new WebInspector.ChunkedXHRReader(url, delegate); | |
456 var loader = new WebInspector.TimelineModelLoader(this, urlReader, progr
ess); | |
457 urlReader.start(loader); | |
458 }, | |
459 | |
460 _createFileReader: function(file, delegate) | |
461 { | |
462 return new WebInspector.ChunkedFileReader(file, WebInspector.TimelineMod
el.TransferChunkLengthBytes, delegate); | |
463 }, | |
464 | |
465 _createFileWriter: function() | |
466 { | |
467 return new WebInspector.FileOutputStream(); | |
468 }, | 305 }, |
469 | 306 |
470 saveToFile: function() | 307 saveToFile: function() |
471 { | 308 { |
472 var now = new Date(); | 309 throw new Error("Not implemented"); |
473 var fileName = "TimelineRawData-" + now.toISO8601Compact() + ".json"; | |
474 var stream = this._createFileWriter(); | |
475 | |
476 /** | |
477 * @param {boolean} accepted | |
478 * @this {WebInspector.TimelineModel} | |
479 */ | |
480 function callback(accepted) | |
481 { | |
482 if (!accepted) | |
483 return; | |
484 var saver = new WebInspector.TimelineSaver(stream); | |
485 saver.save(this._payloads, window.navigator.appVersion); | |
486 } | |
487 stream.open(fileName, callback.bind(this)); | |
488 }, | 310 }, |
489 | 311 |
490 reset: function() | 312 reset: function() |
491 { | 313 { |
492 this._loadedFromFile = false; | 314 this._loadedFromFile = false; |
493 this._records = []; | 315 this._records = []; |
494 this._payloads = []; | |
495 this._stringPool = {}; | |
496 this._minimumRecordTime = -1; | 316 this._minimumRecordTime = -1; |
497 this._maximumRecordTime = -1; | 317 this._maximumRecordTime = -1; |
498 this._bindings._reset(); | |
499 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ | 318 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ |
500 this._mainThreadTasks = []; | 319 this._mainThreadTasks = []; |
501 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ | 320 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ |
502 this._gpuThreadTasks = []; | 321 this._gpuThreadTasks = []; |
503 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ | 322 /** @type {!Array.<!WebInspector.TimelineModel.Record>} */ |
504 this._eventDividerRecords = []; | 323 this._eventDividerRecords = []; |
505 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsC
leared); | 324 this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordsC
leared); |
506 }, | 325 }, |
507 | 326 |
508 /** | 327 /** |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 }, | 371 }, |
553 | 372 |
554 /** | 373 /** |
555 * @return {!Array.<!WebInspector.TimelineModel.Record>} | 374 * @return {!Array.<!WebInspector.TimelineModel.Record>} |
556 */ | 375 */ |
557 eventDividerRecords: function() | 376 eventDividerRecords: function() |
558 { | 377 { |
559 return this._eventDividerRecords; | 378 return this._eventDividerRecords; |
560 }, | 379 }, |
561 | 380 |
562 /** | |
563 * @param {!TimelineAgent.TimelineEvent} record | |
564 */ | |
565 _internStrings: function(record) | |
566 { | |
567 for (var name in record) { | |
568 var value = record[name]; | |
569 if (typeof value !== "string") | |
570 continue; | |
571 | |
572 var interned = this._stringPool[value]; | |
573 if (typeof interned === "string") | |
574 record[name] = interned; | |
575 else | |
576 this._stringPool[value] = value; | |
577 } | |
578 | |
579 var children = record.children; | |
580 for (var i = 0; children && i < children.length; ++i) | |
581 this._internStrings(children[i]); | |
582 }, | |
583 | |
584 __proto__: WebInspector.Object.prototype | 381 __proto__: WebInspector.Object.prototype |
585 } | 382 } |
586 | 383 |
587 | |
588 /** | |
589 * @constructor | |
590 */ | |
591 WebInspector.TimelineModel.InterRecordBindings = function() { | |
592 this._reset(); | |
593 } | |
594 | |
595 WebInspector.TimelineModel.InterRecordBindings.prototype = { | |
596 _reset: function() | |
597 { | |
598 this._sendRequestRecords = {}; | |
599 this._timerRecords = {}; | |
600 this._requestAnimationFrameRecords = {}; | |
601 this._layoutInvalidate = {}; | |
602 this._lastScheduleStyleRecalculation = {}; | |
603 this._webSocketCreateRecords = {}; | |
604 } | |
605 } | |
606 | |
607 /** | 384 /** |
608 * @interface | 385 * @interface |
609 */ | 386 */ |
610 WebInspector.TimelineModel.Record = function() | 387 WebInspector.TimelineModel.Record = function() |
611 { | 388 { |
612 } | 389 } |
613 | 390 |
614 WebInspector.TimelineModel.Record.prototype = { | 391 WebInspector.TimelineModel.Record.prototype = { |
615 /** | 392 /** |
616 * @return {?Array.<!ConsoleAgent.CallFrame>} | 393 * @return {?Array.<!ConsoleAgent.CallFrame>} |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
921 if (data) { | 698 if (data) { |
922 for (var key in data) | 699 for (var key in data) |
923 tokens.push(data[key]); | 700 tokens.push(data[key]); |
924 } | 701 } |
925 return regExp.test(tokens.join("|")); | 702 return regExp.test(tokens.join("|")); |
926 } | 703 } |
927 } | 704 } |
928 | 705 |
929 /** | 706 /** |
930 * @constructor | 707 * @constructor |
931 * @implements {WebInspector.TimelineModel.Record} | |
932 * @param {!WebInspector.TimelineModel} model | |
933 * @param {!TimelineAgent.TimelineEvent} timelineEvent | |
934 * @param {?WebInspector.TimelineModel.Record} parentRecord | |
935 */ | |
936 WebInspector.TimelineModel.RecordImpl = function(model, timelineEvent, parentRec
ord) | |
937 { | |
938 this._model = model; | |
939 var bindings = this._model._bindings; | |
940 this._aggregatedStats = {}; | |
941 this._record = timelineEvent; | |
942 this._children = []; | |
943 if (parentRecord) { | |
944 this.parent = parentRecord; | |
945 parentRecord.children().push(this); | |
946 } | |
947 | |
948 this._selfTime = this.endTime() - this.startTime(); | |
949 | |
950 var recordTypes = WebInspector.TimelineModel.RecordType; | |
951 switch (timelineEvent.type) { | |
952 case recordTypes.ResourceSendRequest: | |
953 // Make resource receive record last since request was sent; make finish
record last since response received. | |
954 bindings._sendRequestRecords[timelineEvent.data["requestId"]] = this; | |
955 break; | |
956 | |
957 case recordTypes.ResourceReceiveResponse: | |
958 case recordTypes.ResourceReceivedData: | |
959 case recordTypes.ResourceFinish: | |
960 this._initiator = bindings._sendRequestRecords[timelineEvent.data["reque
stId"]]; | |
961 break; | |
962 | |
963 case recordTypes.TimerInstall: | |
964 bindings._timerRecords[timelineEvent.data["timerId"]] = this; | |
965 break; | |
966 | |
967 case recordTypes.TimerFire: | |
968 this._initiator = bindings._timerRecords[timelineEvent.data["timerId"]]; | |
969 break; | |
970 | |
971 case recordTypes.RequestAnimationFrame: | |
972 bindings._requestAnimationFrameRecords[timelineEvent.data["id"]] = this; | |
973 break; | |
974 | |
975 case recordTypes.FireAnimationFrame: | |
976 this._initiator = bindings._requestAnimationFrameRecords[timelineEvent.d
ata["id"]]; | |
977 break; | |
978 | |
979 case recordTypes.ScheduleStyleRecalculation: | |
980 bindings._lastScheduleStyleRecalculation[this.frameId()] = this; | |
981 break; | |
982 | |
983 case recordTypes.RecalculateStyles: | |
984 this._initiator = bindings._lastScheduleStyleRecalculation[this.frameId(
)]; | |
985 break; | |
986 | |
987 case recordTypes.InvalidateLayout: | |
988 // Consider style recalculation as a reason for layout invalidation, | |
989 // but only if we had no earlier layout invalidation records. | |
990 var layoutInitator = this; | |
991 if (!bindings._layoutInvalidate[this.frameId()] && parentRecord.type() =
== recordTypes.RecalculateStyles) | |
992 layoutInitator = parentRecord._initiator; | |
993 bindings._layoutInvalidate[this.frameId()] = layoutInitator; | |
994 break; | |
995 | |
996 case recordTypes.Layout: | |
997 this._initiator = bindings._layoutInvalidate[this.frameId()]; | |
998 bindings._layoutInvalidate[this.frameId()] = null; | |
999 if (this.stackTrace()) | |
1000 this.addWarning(WebInspector.UIString("Forced synchronous layout is
a possible performance bottleneck.")); | |
1001 break; | |
1002 | |
1003 case recordTypes.WebSocketCreate: | |
1004 bindings._webSocketCreateRecords[timelineEvent.data["identifier"]] = thi
s; | |
1005 break; | |
1006 | |
1007 case recordTypes.WebSocketSendHandshakeRequest: | |
1008 case recordTypes.WebSocketReceiveHandshakeResponse: | |
1009 case recordTypes.WebSocketDestroy: | |
1010 this._initiator = bindings._webSocketCreateRecords[timelineEvent.data["i
dentifier"]]; | |
1011 break; | |
1012 } | |
1013 } | |
1014 | |
1015 WebInspector.TimelineModel.RecordImpl.prototype = { | |
1016 /** | |
1017 * @return {?Array.<!ConsoleAgent.CallFrame>} | |
1018 */ | |
1019 callSiteStackTrace: function() | |
1020 { | |
1021 return this._initiator ? this._initiator.stackTrace() : null; | |
1022 }, | |
1023 | |
1024 /** | |
1025 * @return {?WebInspector.TimelineModel.Record} | |
1026 */ | |
1027 initiator: function() | |
1028 { | |
1029 return this._initiator; | |
1030 }, | |
1031 | |
1032 /** | |
1033 * @return {!WebInspector.Target} | |
1034 */ | |
1035 target: function() | |
1036 { | |
1037 return this._model.target(); | |
1038 }, | |
1039 | |
1040 /** | |
1041 * @return {number} | |
1042 */ | |
1043 selfTime: function() | |
1044 { | |
1045 return this._selfTime; | |
1046 }, | |
1047 | |
1048 /** | |
1049 * @return {!Array.<!WebInspector.TimelineModel.Record>} | |
1050 */ | |
1051 children: function() | |
1052 { | |
1053 return this._children; | |
1054 }, | |
1055 | |
1056 /** | |
1057 * @return {!WebInspector.TimelineCategory} | |
1058 */ | |
1059 category: function() | |
1060 { | |
1061 return WebInspector.TimelineUIUtils.categoryForRecord(this); | |
1062 }, | |
1063 | |
1064 /** | |
1065 * @return {string} | |
1066 */ | |
1067 title: function() | |
1068 { | |
1069 return WebInspector.TimelineUIUtils.recordTitle(this, this._model); | |
1070 }, | |
1071 | |
1072 /** | |
1073 * @return {number} | |
1074 */ | |
1075 startTime: function() | |
1076 { | |
1077 return this._record.startTime; | |
1078 }, | |
1079 | |
1080 /** | |
1081 * @return {string|undefined} | |
1082 */ | |
1083 thread: function() | |
1084 { | |
1085 return this._record.thread; | |
1086 }, | |
1087 | |
1088 /** | |
1089 * @return {number} | |
1090 */ | |
1091 endTime: function() | |
1092 { | |
1093 return this._endTime || this._record.endTime || this._record.startTime; | |
1094 }, | |
1095 | |
1096 /** | |
1097 * @param {number} endTime | |
1098 */ | |
1099 setEndTime: function(endTime) | |
1100 { | |
1101 this._endTime = endTime; | |
1102 }, | |
1103 | |
1104 /** | |
1105 * @return {!Object} | |
1106 */ | |
1107 data: function() | |
1108 { | |
1109 return this._record.data; | |
1110 }, | |
1111 | |
1112 /** | |
1113 * @return {string} | |
1114 */ | |
1115 type: function() | |
1116 { | |
1117 return this._record.type; | |
1118 }, | |
1119 | |
1120 /** | |
1121 * @return {string} | |
1122 */ | |
1123 frameId: function() | |
1124 { | |
1125 return this._record.frameId || ""; | |
1126 }, | |
1127 | |
1128 /** | |
1129 * @return {?Array.<!ConsoleAgent.CallFrame>} | |
1130 */ | |
1131 stackTrace: function() | |
1132 { | |
1133 if (this._record.stackTrace && this._record.stackTrace.length) | |
1134 return this._record.stackTrace; | |
1135 return null; | |
1136 }, | |
1137 | |
1138 /** | |
1139 * @param {string} key | |
1140 * @return {?Object} | |
1141 */ | |
1142 getUserObject: function(key) | |
1143 { | |
1144 if (!this._userObjects) | |
1145 return null; | |
1146 return this._userObjects.get(key); | |
1147 }, | |
1148 | |
1149 /** | |
1150 * @param {string} key | |
1151 * @param {?Object|undefined} value | |
1152 */ | |
1153 setUserObject: function(key, value) | |
1154 { | |
1155 if (!this._userObjects) | |
1156 this._userObjects = new StringMap(); | |
1157 this._userObjects.put(key, value); | |
1158 }, | |
1159 | |
1160 _calculateAggregatedStats: function() | |
1161 { | |
1162 this._aggregatedStats = {}; | |
1163 | |
1164 for (var index = this._children.length; index; --index) { | |
1165 var child = this._children[index - 1]; | |
1166 for (var category in child._aggregatedStats) | |
1167 this._aggregatedStats[category] = (this._aggregatedStats[categor
y] || 0) + child._aggregatedStats[category]; | |
1168 } | |
1169 this._aggregatedStats[this.category().name] = (this._aggregatedStats[thi
s.category().name] || 0) + this._selfTime; | |
1170 }, | |
1171 | |
1172 /** | |
1173 * @return {!Object.<string, number>} | |
1174 */ | |
1175 aggregatedStats: function() | |
1176 { | |
1177 return this._aggregatedStats; | |
1178 }, | |
1179 | |
1180 /** | |
1181 * @param {string} message | |
1182 */ | |
1183 addWarning: function(message) | |
1184 { | |
1185 if (!this._warnings) | |
1186 this._warnings = []; | |
1187 this._warnings.push(message); | |
1188 }, | |
1189 | |
1190 /** | |
1191 * @return {?Array.<string>} | |
1192 */ | |
1193 warnings: function() | |
1194 { | |
1195 return this._warnings; | |
1196 }, | |
1197 | |
1198 /** | |
1199 * @param {!RegExp} regExp | |
1200 * @return {boolean} | |
1201 */ | |
1202 testContentMatching: function(regExp) | |
1203 { | |
1204 var tokens = [this.title()]; | |
1205 for (var key in this._record.data) | |
1206 tokens.push(this._record.data[key]) | |
1207 return regExp.test(tokens.join("|")); | |
1208 } | |
1209 } | |
1210 | |
1211 /** | |
1212 * @constructor | |
1213 */ | 708 */ |
1214 WebInspector.TimelineModel.Filter = function() | 709 WebInspector.TimelineModel.Filter = function() |
1215 { | 710 { |
1216 /** @type {!WebInspector.TimelineModel} */ | 711 /** @type {!WebInspector.TimelineModel} */ |
1217 this._model; | 712 this._model; |
1218 } | 713 } |
1219 | 714 |
1220 WebInspector.TimelineModel.Filter.prototype = { | 715 WebInspector.TimelineModel.Filter.prototype = { |
1221 /** | 716 /** |
1222 * @param {!WebInspector.TimelineModel.Record} record | 717 * @param {!WebInspector.TimelineModel.Record} record |
1223 * @return {boolean} | 718 * @return {boolean} |
1224 */ | 719 */ |
1225 accept: function(record) | 720 accept: function(record) |
1226 { | 721 { |
1227 return true; | 722 return true; |
1228 }, | 723 }, |
1229 | 724 |
1230 notifyFilterChanged: function() | 725 notifyFilterChanged: function() |
1231 { | 726 { |
1232 this._model._filterChanged(); | 727 this._model._filterChanged(); |
1233 } | 728 } |
1234 } | 729 } |
1235 | 730 |
1236 /** | 731 /** |
1237 * @constructor | 732 * @constructor |
1238 * @implements {WebInspector.OutputStream} | |
1239 * @param {!WebInspector.TimelineModel} model | |
1240 * @param {!{cancel: function()}} reader | |
1241 * @param {!WebInspector.Progress} progress | |
1242 */ | |
1243 WebInspector.TimelineModelLoader = function(model, reader, progress) | |
1244 { | |
1245 this._model = model; | |
1246 this._reader = reader; | |
1247 this._progress = progress; | |
1248 this._buffer = ""; | |
1249 this._firstChunk = true; | |
1250 } | |
1251 | |
1252 WebInspector.TimelineModelLoader.prototype = { | |
1253 /** | |
1254 * @param {string} chunk | |
1255 */ | |
1256 write: function(chunk) | |
1257 { | |
1258 var data = this._buffer + chunk; | |
1259 var lastIndex = 0; | |
1260 var index; | |
1261 do { | |
1262 index = lastIndex; | |
1263 lastIndex = WebInspector.TextUtils.findBalancedCurlyBrackets(data, i
ndex); | |
1264 } while (lastIndex !== -1) | |
1265 | |
1266 var json = data.slice(0, index) + "]"; | |
1267 this._buffer = data.slice(index); | |
1268 | |
1269 if (!index) | |
1270 return; | |
1271 | |
1272 // Prepending "0" to turn string into valid JSON. | |
1273 if (!this._firstChunk) | |
1274 json = "[0" + json; | |
1275 | |
1276 var items; | |
1277 try { | |
1278 items = /** @type {!Array.<!TimelineAgent.TimelineEvent>} */ (JSON.p
arse(json)); | |
1279 } catch (e) { | |
1280 WebInspector.messageSink.addErrorMessage("Malformed timeline data.",
true); | |
1281 this._model.reset(); | |
1282 this._reader.cancel(); | |
1283 this._progress.done(); | |
1284 return; | |
1285 } | |
1286 | |
1287 if (this._firstChunk) { | |
1288 this._version = items[0]; | |
1289 this._firstChunk = false; | |
1290 this._model.reset(); | |
1291 } | |
1292 | |
1293 // Skip 0-th element - it is either version or 0. | |
1294 for (var i = 1, size = items.length; i < size; ++i) | |
1295 this._model._addRecord(items[i]); | |
1296 }, | |
1297 | |
1298 close: function() | |
1299 { | |
1300 this._model._loadedFromFile = true; | |
1301 } | |
1302 } | |
1303 | |
1304 /** | |
1305 * @constructor | |
1306 * @implements {WebInspector.OutputStreamDelegate} | |
1307 * @param {!WebInspector.TimelineModel} model | |
1308 * @param {!WebInspector.Progress} progress | |
1309 */ | |
1310 WebInspector.TimelineModelLoadFromFileDelegate = function(model, progress) | |
1311 { | |
1312 this._model = model; | |
1313 this._progress = progress; | |
1314 } | |
1315 | |
1316 WebInspector.TimelineModelLoadFromFileDelegate.prototype = { | |
1317 onTransferStarted: function() | |
1318 { | |
1319 this._progress.setTitle(WebInspector.UIString("Loading\u2026")); | |
1320 }, | |
1321 | |
1322 /** | |
1323 * @param {!WebInspector.ChunkedReader} reader | |
1324 */ | |
1325 onChunkTransferred: function(reader) | |
1326 { | |
1327 if (this._progress.isCanceled()) { | |
1328 reader.cancel(); | |
1329 this._progress.done(); | |
1330 this._model.reset(); | |
1331 return; | |
1332 } | |
1333 | |
1334 var totalSize = reader.fileSize(); | |
1335 if (totalSize) { | |
1336 this._progress.setTotalWork(totalSize); | |
1337 this._progress.setWorked(reader.loadedSize()); | |
1338 } | |
1339 }, | |
1340 | |
1341 onTransferFinished: function() | |
1342 { | |
1343 this._progress.done(); | |
1344 }, | |
1345 | |
1346 /** | |
1347 * @param {!WebInspector.ChunkedReader} reader | |
1348 * @param {!Event} event | |
1349 */ | |
1350 onError: function(reader, event) | |
1351 { | |
1352 this._progress.done(); | |
1353 this._model.reset(); | |
1354 switch (event.target.error.code) { | |
1355 case FileError.NOT_FOUND_ERR: | |
1356 WebInspector.messageSink.addErrorMessage(WebInspector.UIString("File
\"%s\" not found.", reader.fileName()), true); | |
1357 break; | |
1358 case FileError.NOT_READABLE_ERR: | |
1359 WebInspector.messageSink.addErrorMessage(WebInspector.UIString("File
\"%s\" is not readable", reader.fileName()), true); | |
1360 break; | |
1361 case FileError.ABORT_ERR: | |
1362 break; | |
1363 default: | |
1364 WebInspector.messageSink.addErrorMessage(WebInspector.UIString("An e
rror occurred while reading the file \"%s\"", reader.fileName()), true); | |
1365 } | |
1366 } | |
1367 } | |
1368 | |
1369 /** | |
1370 * @constructor | |
1371 * @param {!WebInspector.OutputStream} stream | |
1372 */ | |
1373 WebInspector.TimelineSaver = function(stream) | |
1374 { | |
1375 this._stream = stream; | |
1376 } | |
1377 | |
1378 WebInspector.TimelineSaver.prototype = { | |
1379 /** | |
1380 * @param {!Array.<*>} payloads | |
1381 * @param {string} version | |
1382 */ | |
1383 save: function(payloads, version) | |
1384 { | |
1385 this._payloads = payloads; | |
1386 this._recordIndex = 0; | |
1387 this._prologue = "[" + JSON.stringify(version); | |
1388 | |
1389 this._writeNextChunk(this._stream); | |
1390 }, | |
1391 | |
1392 _writeNextChunk: function(stream) | |
1393 { | |
1394 const separator = ",\n"; | |
1395 var data = []; | |
1396 var length = 0; | |
1397 | |
1398 if (this._prologue) { | |
1399 data.push(this._prologue); | |
1400 length += this._prologue.length; | |
1401 delete this._prologue; | |
1402 } else { | |
1403 if (this._recordIndex === this._payloads.length) { | |
1404 stream.close(); | |
1405 return; | |
1406 } | |
1407 data.push(""); | |
1408 } | |
1409 while (this._recordIndex < this._payloads.length) { | |
1410 var item = JSON.stringify(this._payloads[this._recordIndex]); | |
1411 var itemLength = item.length + separator.length; | |
1412 if (length + itemLength > WebInspector.TimelineModel.TransferChunkLe
ngthBytes) | |
1413 break; | |
1414 length += itemLength; | |
1415 data.push(item); | |
1416 ++this._recordIndex; | |
1417 } | |
1418 if (this._recordIndex === this._payloads.length) | |
1419 data.push(data.pop() + "]"); | |
1420 stream.write(data.join(separator), this._writeNextChunk.bind(this)); | |
1421 } | |
1422 } | |
1423 | |
1424 /** | |
1425 * @constructor | |
1426 */ | 733 */ |
1427 WebInspector.TimelineMergingRecordBuffer = function() | 734 WebInspector.TimelineMergingRecordBuffer = function() |
1428 { | 735 { |
1429 this._backgroundRecordsBuffer = []; | 736 this._backgroundRecordsBuffer = []; |
1430 } | 737 } |
1431 | 738 |
1432 /** | 739 /** |
1433 * @constructor | 740 * @constructor |
1434 */ | 741 */ |
1435 WebInspector.TimelineMergingRecordBuffer.prototype = { | 742 WebInspector.TimelineMergingRecordBuffer.prototype = { |
(...skipping 15 matching lines...) Expand all Loading... |
1451 function recordTimestampComparator(a, b) | 758 function recordTimestampComparator(a, b) |
1452 { | 759 { |
1453 // Never return 0, as the merge function will squash identical entri
es. | 760 // Never return 0, as the merge function will squash identical entri
es. |
1454 return a.startTime() < b.startTime() ? -1 : 1; | 761 return a.startTime() < b.startTime() ? -1 : 1; |
1455 } | 762 } |
1456 var result = this._backgroundRecordsBuffer.mergeOrdered(records, recordT
imestampComparator); | 763 var result = this._backgroundRecordsBuffer.mergeOrdered(records, recordT
imestampComparator); |
1457 this._backgroundRecordsBuffer = []; | 764 this._backgroundRecordsBuffer = []; |
1458 return result; | 765 return result; |
1459 } | 766 } |
1460 } | 767 } |
OLD | NEW |