| 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 |