| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2014 The Chromium Authors. All rights reserved. | |
| 3 * Use of this source code is governed by a BSD-style license that can be | |
| 4 * found in the LICENSE file. | |
| 5 */ | |
| 6 | |
| 7 /** | |
| 8 * @constructor | |
| 9 * @extends {WebInspector.Object} | |
| 10 * @implements {WebInspector.TargetManager.Observer} | |
| 11 */ | |
| 12 WebInspector.TracingManager = function() | |
| 13 { | |
| 14 WebInspector.Object.call(this); | |
| 15 this._active = false; | |
| 16 WebInspector.targetManager.observeTargets(this); | |
| 17 } | |
| 18 | |
| 19 WebInspector.TracingManager.Events = { | |
| 20 "BufferUsage": "BufferUsage", | |
| 21 "TracingStarted": "TracingStarted", | |
| 22 "EventsCollected": "EventsCollected", | |
| 23 "TracingStopped": "TracingStopped", | |
| 24 "TracingComplete": "TracingComplete" | |
| 25 } | |
| 26 | |
| 27 /** @typedef {!{ | |
| 28 cat: string, | |
| 29 pid: number, | |
| 30 tid: number, | |
| 31 ts: number, | |
| 32 ph: string, | |
| 33 name: string, | |
| 34 args: !Object, | |
| 35 dur: number, | |
| 36 id: number, | |
| 37 s: string | |
| 38 }} | |
| 39 */ | |
| 40 WebInspector.TracingManager.EventPayload; | |
| 41 | |
| 42 | |
| 43 WebInspector.TracingManager.prototype = { | |
| 44 /** | |
| 45 * @param {!WebInspector.Target} target | |
| 46 */ | |
| 47 targetAdded: function(target) | |
| 48 { | |
| 49 if (this._target) | |
| 50 return; | |
| 51 this._target = target; | |
| 52 InspectorBackend.registerTracingDispatcher(new WebInspector.TracingDispa
tcher(this)); | |
| 53 }, | |
| 54 | |
| 55 /** | |
| 56 * @param {!WebInspector.Target} target | |
| 57 */ | |
| 58 targetRemoved: function(target) | |
| 59 { | |
| 60 if (this._target !== target) | |
| 61 return; | |
| 62 delete this._target; | |
| 63 }, | |
| 64 | |
| 65 /** | |
| 66 * @param {number} usage | |
| 67 */ | |
| 68 _bufferUsage: function(usage) | |
| 69 { | |
| 70 this.dispatchEventToListeners(WebInspector.TracingManager.Events.BufferU
sage, usage); | |
| 71 }, | |
| 72 | |
| 73 /** | |
| 74 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
| 75 */ | |
| 76 _eventsCollected: function(events) | |
| 77 { | |
| 78 this.dispatchEventToListeners(WebInspector.TracingManager.Events.EventsC
ollected, events); | |
| 79 }, | |
| 80 | |
| 81 _tracingComplete: function() | |
| 82 { | |
| 83 this.dispatchEventToListeners(WebInspector.TracingManager.Events.Tracing
Complete); | |
| 84 }, | |
| 85 | |
| 86 _tracingStarted: function() | |
| 87 { | |
| 88 if (this._active) | |
| 89 return; | |
| 90 this._active = true; | |
| 91 this.dispatchEventToListeners(WebInspector.TracingManager.Events.Tracing
Started); | |
| 92 }, | |
| 93 | |
| 94 /** | |
| 95 * @param {string} categoryFilter | |
| 96 * @param {string} options | |
| 97 * @param {function(?string)=} callback | |
| 98 */ | |
| 99 start: function(categoryFilter, options, callback) | |
| 100 { | |
| 101 if (this._active) | |
| 102 return; | |
| 103 WebInspector.profilingLock().acquire(); | |
| 104 this._shouldReleaseLock = true; | |
| 105 var bufferUsageReportingIntervalMs = 500; | |
| 106 TracingAgent.start(categoryFilter, options, bufferUsageReportingInterval
Ms, callback); | |
| 107 this._tracingStarted(); | |
| 108 this._active = true; | |
| 109 }, | |
| 110 | |
| 111 stop: function() | |
| 112 { | |
| 113 if (!this._active) | |
| 114 return; | |
| 115 TracingAgent.end(this._onStop.bind(this)); | |
| 116 if (this._shouldReleaseLock) { | |
| 117 this._shouldReleaseLock = false; | |
| 118 WebInspector.profilingLock().release(); | |
| 119 } | |
| 120 }, | |
| 121 | |
| 122 _onStop: function() | |
| 123 { | |
| 124 if (!this._active) | |
| 125 return; | |
| 126 this.dispatchEventToListeners(WebInspector.TracingManager.Events.Tracing
Stopped); | |
| 127 this._active = false; | |
| 128 }, | |
| 129 | |
| 130 __proto__: WebInspector.Object.prototype | |
| 131 } | |
| 132 | |
| 133 /** | |
| 134 * @constructor | |
| 135 */ | |
| 136 WebInspector.TracingModel = function() | |
| 137 { | |
| 138 this.reset(); | |
| 139 } | |
| 140 | |
| 141 /** | |
| 142 * @enum {string} | |
| 143 */ | |
| 144 WebInspector.TracingModel.Phase = { | |
| 145 Begin: "B", | |
| 146 End: "E", | |
| 147 Complete: "X", | |
| 148 Instant: "I", | |
| 149 AsyncBegin: "S", | |
| 150 AsyncStepInto: "T", | |
| 151 AsyncStepPast: "p", | |
| 152 AsyncEnd: "F", | |
| 153 FlowBegin: "s", | |
| 154 FlowStep: "t", | |
| 155 FlowEnd: "f", | |
| 156 Metadata: "M", | |
| 157 Counter: "C", | |
| 158 Sample: "P", | |
| 159 CreateObject: "N", | |
| 160 SnapshotObject: "O", | |
| 161 DeleteObject: "D" | |
| 162 }; | |
| 163 | |
| 164 WebInspector.TracingModel.MetadataEvent = { | |
| 165 ProcessSortIndex: "process_sort_index", | |
| 166 ProcessName: "process_name", | |
| 167 ThreadSortIndex: "thread_sort_index", | |
| 168 ThreadName: "thread_name" | |
| 169 } | |
| 170 | |
| 171 WebInspector.TracingModel.DevToolsMetadataEventCategory = "disabled-by-default-d
evtools.timeline"; | |
| 172 | |
| 173 WebInspector.TracingModel.ConsoleEventCategory = "blink.console"; | |
| 174 | |
| 175 WebInspector.TracingModel.FrameLifecycleEventCategory = "cc,devtools"; | |
| 176 | |
| 177 WebInspector.TracingModel.DevToolsMetadataEvent = { | |
| 178 TracingStartedInPage: "TracingStartedInPage", | |
| 179 TracingStartedInWorker: "TracingStartedInWorker", | |
| 180 }; | |
| 181 | |
| 182 /** | |
| 183 * @param {string} phase | |
| 184 * @return {boolean} | |
| 185 */ | |
| 186 WebInspector.TracingModel.isAsyncPhase = function(phase) | |
| 187 { | |
| 188 return phase === WebInspector.TracingModel.Phase.AsyncBegin || phase === Web
Inspector.TracingModel.Phase.AsyncEnd || | |
| 189 phase === WebInspector.TracingModel.Phase.AsyncStepInto || phase === Web
Inspector.TracingModel.Phase.AsyncStepPast; | |
| 190 } | |
| 191 | |
| 192 WebInspector.TracingModel.prototype = { | |
| 193 /** | |
| 194 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
| 195 */ | |
| 196 devtoolsPageMetadataEvents: function() | |
| 197 { | |
| 198 return this._devtoolsPageMetadataEvents; | |
| 199 }, | |
| 200 | |
| 201 /** | |
| 202 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
| 203 */ | |
| 204 devtoolsWorkerMetadataEvents: function() | |
| 205 { | |
| 206 return this._devtoolsWorkerMetadataEvents; | |
| 207 }, | |
| 208 | |
| 209 /** | |
| 210 * @return {?string} | |
| 211 */ | |
| 212 sessionId: function() | |
| 213 { | |
| 214 return this._sessionId; | |
| 215 }, | |
| 216 | |
| 217 /** | |
| 218 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
| 219 */ | |
| 220 setEventsForTest: function(events) | |
| 221 { | |
| 222 this.reset(); | |
| 223 this.addEvents(events); | |
| 224 this.tracingComplete(); | |
| 225 }, | |
| 226 | |
| 227 /** | |
| 228 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
| 229 */ | |
| 230 addEvents: function(events) | |
| 231 { | |
| 232 for (var i = 0; i < events.length; ++i) { | |
| 233 this._addEvent(events[i]); | |
| 234 this._rawEvents.push(events[i]); | |
| 235 } | |
| 236 }, | |
| 237 | |
| 238 tracingComplete: function() | |
| 239 { | |
| 240 this._processMetadataEvents(); | |
| 241 for (var process in this._processById) | |
| 242 this._processById[process]._tracingComplete(this._maximumRecordTime)
; | |
| 243 }, | |
| 244 | |
| 245 reset: function() | |
| 246 { | |
| 247 this._processById = {}; | |
| 248 this._minimumRecordTime = 0; | |
| 249 this._maximumRecordTime = 0; | |
| 250 this._sessionId = null; | |
| 251 this._devtoolsPageMetadataEvents = []; | |
| 252 this._devtoolsWorkerMetadataEvents = []; | |
| 253 this._rawEvents = []; | |
| 254 }, | |
| 255 | |
| 256 /** | |
| 257 * @return {!Array.<!WebInspector.TracingManager.EventPayload>} | |
| 258 */ | |
| 259 rawEvents: function() | |
| 260 { | |
| 261 return this._rawEvents; | |
| 262 }, | |
| 263 | |
| 264 /** | |
| 265 * @param {!WebInspector.TracingManager.EventPayload} payload | |
| 266 */ | |
| 267 _addEvent: function(payload) | |
| 268 { | |
| 269 var process = this._processById[payload.pid]; | |
| 270 if (!process) { | |
| 271 process = new WebInspector.TracingModel.Process(payload.pid); | |
| 272 this._processById[payload.pid] = process; | |
| 273 } | |
| 274 if (payload.ph !== WebInspector.TracingModel.Phase.Metadata) { | |
| 275 var timestamp = payload.ts / 1000; | |
| 276 // We do allow records for unrelated threads to arrive out-of-order, | |
| 277 // so there's a chance we're getting records from the past. | |
| 278 if (timestamp && (!this._minimumRecordTime || timestamp < this._mini
mumRecordTime)) | |
| 279 this._minimumRecordTime = timestamp; | |
| 280 var endTimeStamp = (payload.ts + (payload.dur || 0)) / 1000; | |
| 281 this._maximumRecordTime = Math.max(this._maximumRecordTime, endTimeS
tamp); | |
| 282 var event = process._addEvent(payload); | |
| 283 if (event && event.name === WebInspector.TracingModel.DevToolsMetada
taEvent.TracingStartedInPage && | |
| 284 event.category === WebInspector.TracingModel.DevToolsMetadataEve
ntCategory) { | |
| 285 this._devtoolsPageMetadataEvents.push(event); | |
| 286 } | |
| 287 if (event && event.name === WebInspector.TracingModel.DevToolsMetada
taEvent.TracingStartedInWorker && | |
| 288 event.category === WebInspector.TracingModel.DevToolsMetadataEve
ntCategory) { | |
| 289 this._devtoolsWorkerMetadataEvents.push(event); | |
| 290 } | |
| 291 return; | |
| 292 } | |
| 293 switch (payload.name) { | |
| 294 case WebInspector.TracingModel.MetadataEvent.ProcessSortIndex: | |
| 295 process._setSortIndex(payload.args["sort_index"]); | |
| 296 break; | |
| 297 case WebInspector.TracingModel.MetadataEvent.ProcessName: | |
| 298 process._setName(payload.args["name"]); | |
| 299 break; | |
| 300 case WebInspector.TracingModel.MetadataEvent.ThreadSortIndex: | |
| 301 process.threadById(payload.tid)._setSortIndex(payload.args["sort_ind
ex"]); | |
| 302 break; | |
| 303 case WebInspector.TracingModel.MetadataEvent.ThreadName: | |
| 304 process.threadById(payload.tid)._setName(payload.args["name"]); | |
| 305 break; | |
| 306 } | |
| 307 }, | |
| 308 | |
| 309 _processMetadataEvents: function() | |
| 310 { | |
| 311 this._devtoolsPageMetadataEvents.sort(WebInspector.TracingModel.Event.co
mpareStartTime); | |
| 312 if (!this._devtoolsPageMetadataEvents.length) { | |
| 313 WebInspector.console.error(WebInspector.TracingModel.DevToolsMetadat
aEvent.TracingStartedInPage + " event not found."); | |
| 314 return; | |
| 315 } | |
| 316 var sessionId = this._devtoolsPageMetadataEvents[0].args["sessionId"]; | |
| 317 this._sessionId = sessionId; | |
| 318 | |
| 319 var mismatchingIds = {}; | |
| 320 function checkSessionId(event) | |
| 321 { | |
| 322 var id = event.args["sessionId"]; | |
| 323 if (id === sessionId) | |
| 324 return true; | |
| 325 mismatchingIds[id] = true; | |
| 326 return false; | |
| 327 } | |
| 328 this._devtoolsPageMetadataEvents = this._devtoolsPageMetadataEvents.filt
er(checkSessionId); | |
| 329 this._devtoolsWorkerMetadataEvents = this._devtoolsWorkerMetadataEvents.
filter(checkSessionId); | |
| 330 | |
| 331 var idList = Object.keys(mismatchingIds); | |
| 332 if (idList.length) | |
| 333 WebInspector.console.error("Timeline recording was started in more t
han one page simulaniously. Session id mismatch: " + this._sessionId + " and " +
idList + "."); | |
| 334 }, | |
| 335 | |
| 336 /** | |
| 337 * @return {number} | |
| 338 */ | |
| 339 minimumRecordTime: function() | |
| 340 { | |
| 341 return this._minimumRecordTime; | |
| 342 }, | |
| 343 | |
| 344 /** | |
| 345 * @return {number} | |
| 346 */ | |
| 347 maximumRecordTime: function() | |
| 348 { | |
| 349 return this._maximumRecordTime; | |
| 350 }, | |
| 351 | |
| 352 /** | |
| 353 * @return {!Array.<!WebInspector.TracingModel.Process>} | |
| 354 */ | |
| 355 sortedProcesses: function() | |
| 356 { | |
| 357 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._p
rocessById)); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 | |
| 362 /** | |
| 363 * @constructor | |
| 364 * @param {!WebInspector.TracingModel} tracingModel | |
| 365 */ | |
| 366 WebInspector.TracingModel.Loader = function(tracingModel) | |
| 367 { | |
| 368 this._tracingModel = tracingModel; | |
| 369 this._firstChunkReceived = false; | |
| 370 } | |
| 371 | |
| 372 WebInspector.TracingModel.Loader.prototype = { | |
| 373 /** | |
| 374 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} events | |
| 375 */ | |
| 376 loadNextChunk: function(events) | |
| 377 { | |
| 378 if (!this._firstChunkReceived) { | |
| 379 this._tracingModel.reset(); | |
| 380 this._firstChunkReceived = true; | |
| 381 } | |
| 382 this._tracingModel.addEvents(events); | |
| 383 }, | |
| 384 | |
| 385 finish: function() | |
| 386 { | |
| 387 this._tracingModel.tracingComplete(); | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 | |
| 392 /** | |
| 393 * @constructor | |
| 394 * @param {string} category | |
| 395 * @param {string} name | |
| 396 * @param {string} phase | |
| 397 * @param {number} startTime | |
| 398 * @param {?WebInspector.TracingModel.Thread} thread | |
| 399 */ | |
| 400 WebInspector.TracingModel.Event = function(category, name, phase, startTime, thr
ead) | |
| 401 { | |
| 402 this.category = category; | |
| 403 this.name = name; | |
| 404 this.phase = phase; | |
| 405 this.startTime = startTime; | |
| 406 this.thread = thread; | |
| 407 this.args = {}; | |
| 408 | |
| 409 /** @type {?string} */ | |
| 410 this.warning = null; | |
| 411 /** @type {?WebInspector.TracingModel.Event} */ | |
| 412 this.initiator = null; | |
| 413 /** @type {?Array.<!ConsoleAgent.CallFrame>} */ | |
| 414 this.stackTrace = null; | |
| 415 /** @type {?Element} */ | |
| 416 this.previewElement = null; | |
| 417 /** @type {?string} */ | |
| 418 this.imageURL = null; | |
| 419 /** @type {number} */ | |
| 420 this.backendNodeId = 0; | |
| 421 | |
| 422 /** @type {number} */ | |
| 423 this.selfTime = 0; | |
| 424 } | |
| 425 | |
| 426 /** | |
| 427 * @param {!WebInspector.TracingManager.EventPayload} payload | |
| 428 * @param {?WebInspector.TracingModel.Thread} thread | |
| 429 * @return {!WebInspector.TracingModel.Event} | |
| 430 */ | |
| 431 WebInspector.TracingModel.Event.fromPayload = function(payload, thread) | |
| 432 { | |
| 433 var event = new WebInspector.TracingModel.Event(payload.cat, payload.name, p
ayload.ph, payload.ts / 1000, thread); | |
| 434 if (payload.args) | |
| 435 event.addArgs(payload.args); | |
| 436 else | |
| 437 console.error("Missing mandatory event argument 'args' at " + payload.ts
/ 1000); | |
| 438 if (typeof payload.dur === "number") | |
| 439 event.setEndTime((payload.ts + payload.dur) / 1000); | |
| 440 if (payload.id) | |
| 441 event.id = payload.id; | |
| 442 return event; | |
| 443 } | |
| 444 | |
| 445 WebInspector.TracingModel.Event.prototype = { | |
| 446 /** | |
| 447 * @param {number} endTime | |
| 448 */ | |
| 449 setEndTime: function(endTime) | |
| 450 { | |
| 451 if (endTime < this.startTime) { | |
| 452 console.assert(false, "Event out of order: " + this.name); | |
| 453 return; | |
| 454 } | |
| 455 this.endTime = endTime; | |
| 456 this.duration = endTime - this.startTime; | |
| 457 }, | |
| 458 | |
| 459 /** | |
| 460 * @param {!Object} args | |
| 461 */ | |
| 462 addArgs: function(args) | |
| 463 { | |
| 464 // Shallow copy args to avoid modifying original payload which may be sa
ved to file. | |
| 465 for (var name in args) { | |
| 466 if (name in this.args) | |
| 467 console.error("Same argument name (" + name + ") is used for be
gin and end phases of " + this.name); | |
| 468 this.args[name] = args[name]; | |
| 469 } | |
| 470 }, | |
| 471 | |
| 472 /** | |
| 473 * @param {!WebInspector.TracingManager.EventPayload} payload | |
| 474 */ | |
| 475 _complete: function(payload) | |
| 476 { | |
| 477 if (payload.args) | |
| 478 this.addArgs(payload.args); | |
| 479 else | |
| 480 console.error("Missing mandatory event argument 'args' at " + payloa
d.ts / 1000); | |
| 481 this.setEndTime(payload.ts / 1000); | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 /** | |
| 486 * @param {!WebInspector.TracingModel.Event} a | |
| 487 * @param {!WebInspector.TracingModel.Event} b | |
| 488 * @return {number} | |
| 489 */ | |
| 490 WebInspector.TracingModel.Event.compareStartTime = function (a, b) | |
| 491 { | |
| 492 return a.startTime - b.startTime; | |
| 493 } | |
| 494 | |
| 495 /** | |
| 496 * @param {!WebInspector.TracingModel.Event} a | |
| 497 * @param {!WebInspector.TracingModel.Event} b | |
| 498 * @return {number} | |
| 499 */ | |
| 500 WebInspector.TracingModel.Event.orderedCompareStartTime = function (a, b) | |
| 501 { | |
| 502 // Array.mergeOrdered coalesces objects if comparator returns 0. | |
| 503 // To change this behavior this comparator return -1 in the case events | |
| 504 // startTime's are equal, so both events got placed into the result array. | |
| 505 return a.startTime - b.startTime || -1; | |
| 506 } | |
| 507 | |
| 508 /** | |
| 509 * @constructor | |
| 510 */ | |
| 511 WebInspector.TracingModel.NamedObject = function() | |
| 512 { | |
| 513 } | |
| 514 | |
| 515 WebInspector.TracingModel.NamedObject.prototype = | |
| 516 { | |
| 517 /** | |
| 518 * @param {string} name | |
| 519 */ | |
| 520 _setName: function(name) | |
| 521 { | |
| 522 this._name = name; | |
| 523 }, | |
| 524 | |
| 525 /** | |
| 526 * @return {string} | |
| 527 */ | |
| 528 name: function() | |
| 529 { | |
| 530 return this._name; | |
| 531 }, | |
| 532 | |
| 533 /** | |
| 534 * @param {number} sortIndex | |
| 535 */ | |
| 536 _setSortIndex: function(sortIndex) | |
| 537 { | |
| 538 this._sortIndex = sortIndex; | |
| 539 }, | |
| 540 } | |
| 541 | |
| 542 /** | |
| 543 * @param {!Array.<!WebInspector.TracingModel.NamedObject>} array | |
| 544 */ | |
| 545 WebInspector.TracingModel.NamedObject._sort = function(array) | |
| 546 { | |
| 547 /** | |
| 548 * @param {!WebInspector.TracingModel.NamedObject} a | |
| 549 * @param {!WebInspector.TracingModel.NamedObject} b | |
| 550 */ | |
| 551 function comparator(a, b) | |
| 552 { | |
| 553 return a._sortIndex !== b._sortIndex ? a._sortIndex - b._sortIndex : a.n
ame().localeCompare(b.name()); | |
| 554 } | |
| 555 return array.sort(comparator); | |
| 556 } | |
| 557 | |
| 558 /** | |
| 559 * @constructor | |
| 560 * @extends {WebInspector.TracingModel.NamedObject} | |
| 561 * @param {number} id | |
| 562 */ | |
| 563 WebInspector.TracingModel.Process = function(id) | |
| 564 { | |
| 565 WebInspector.TracingModel.NamedObject.call(this); | |
| 566 this._setName("Process " + id); | |
| 567 this._threads = {}; | |
| 568 this._objects = {}; | |
| 569 /** @type {!Array.<!WebInspector.TracingManager.EventPayload>} */ | |
| 570 this._asyncEvents = []; | |
| 571 /** @type {!Object.<string, ?Array.<!WebInspector.TracingModel.Event>>} */ | |
| 572 this._openAsyncEvents = []; | |
| 573 } | |
| 574 | |
| 575 WebInspector.TracingModel.Process.prototype = { | |
| 576 /** | |
| 577 * @param {number} id | |
| 578 * @return {!WebInspector.TracingModel.Thread} | |
| 579 */ | |
| 580 threadById: function(id) | |
| 581 { | |
| 582 var thread = this._threads[id]; | |
| 583 if (!thread) { | |
| 584 thread = new WebInspector.TracingModel.Thread(this, id); | |
| 585 this._threads[id] = thread; | |
| 586 } | |
| 587 return thread; | |
| 588 }, | |
| 589 | |
| 590 /** | |
| 591 * @param {!WebInspector.TracingManager.EventPayload} payload | |
| 592 * @return {?WebInspector.TracingModel.Event} event | |
| 593 */ | |
| 594 _addEvent: function(payload) | |
| 595 { | |
| 596 var phase = WebInspector.TracingModel.Phase; | |
| 597 // Build async event when we've got events from all threads, so we can s
ort them and process in the chronological order. | |
| 598 // However, also add individual async events to the thread flow, so we c
an easily display them on the same chart as | |
| 599 // other events, should we choose so. | |
| 600 if (WebInspector.TracingModel.isAsyncPhase(payload.ph)) | |
| 601 this._asyncEvents.push(payload); | |
| 602 | |
| 603 var event = this.threadById(payload.tid)._addEvent(payload); | |
| 604 if (event && payload.ph === phase.SnapshotObject) | |
| 605 this.objectsByName(event.name).push(event); | |
| 606 return event; | |
| 607 }, | |
| 608 | |
| 609 /** | |
| 610 * @param {!number} lastEventTime | |
| 611 */ | |
| 612 _tracingComplete: function(lastEventTime) | |
| 613 { | |
| 614 /** | |
| 615 * @param {!WebInspector.TracingManager.EventPayload} a | |
| 616 * @param {!WebInspector.TracingManager.EventPayload} b | |
| 617 */ | |
| 618 function comparePayloadTimestamp(a, b) | |
| 619 { | |
| 620 return a.ts - b.ts; | |
| 621 } | |
| 622 this._asyncEvents.sort(comparePayloadTimestamp).forEach(this._addAsyncEv
ent, this); | |
| 623 for (var key in this._openAsyncEvents) { | |
| 624 var steps = this._openAsyncEvents[key]; | |
| 625 if (!steps) | |
| 626 continue; | |
| 627 var startEvent = steps[0]; | |
| 628 var syntheticEndEvent = new WebInspector.TracingModel.Event(startEve
nt.category, startEvent.name, WebInspector.TracingModel.Phase.AsyncEnd, lastEven
tTime, startEvent.thread); | |
| 629 steps.push(syntheticEndEvent); | |
| 630 } | |
| 631 this._asyncEvents = []; | |
| 632 this._openAsyncEvents = []; | |
| 633 }, | |
| 634 | |
| 635 /** | |
| 636 * @param {!WebInspector.TracingManager.EventPayload} payload | |
| 637 */ | |
| 638 _addAsyncEvent: function(payload) | |
| 639 { | |
| 640 var phase = WebInspector.TracingModel.Phase; | |
| 641 var timestamp = payload.ts / 1000; | |
| 642 var key = payload.name + "." + payload.id; | |
| 643 var steps = this._openAsyncEvents[key]; | |
| 644 | |
| 645 var thread = this.threadById(payload.tid); | |
| 646 if (payload.ph === phase.AsyncBegin) { | |
| 647 if (steps) { | |
| 648 console.error("Event " + key + " at " + timestamp + " was alread
y started at " + steps[0].startTime); | |
| 649 return; | |
| 650 } | |
| 651 steps = [WebInspector.TracingModel.Event.fromPayload(payload, thread
)]; | |
| 652 this._openAsyncEvents[key] = steps; | |
| 653 thread._addAsyncEventSteps(steps); | |
| 654 return; | |
| 655 } | |
| 656 if (!steps) { | |
| 657 console.error("Unexpected async event, phase " + payload.ph + " at "
+ timestamp); | |
| 658 return; | |
| 659 } | |
| 660 var newEvent = WebInspector.TracingModel.Event.fromPayload(payload, thre
ad); | |
| 661 if (payload.ph === phase.AsyncEnd) { | |
| 662 steps.push(newEvent); | |
| 663 delete this._openAsyncEvents[key]; | |
| 664 } else if (payload.ph === phase.AsyncStepInto || payload.ph === phase.As
yncStepPast) { | |
| 665 var lastPhase = steps.peekLast().phase; | |
| 666 if (lastPhase !== phase.AsyncBegin && lastPhase !== payload.ph) { | |
| 667 console.assert(false, "Async event step phase mismatch: " + last
Phase + " at " + steps.peekLast().startTime + " vs. " + payload.ph + " at " + ti
mestamp); | |
| 668 return; | |
| 669 } | |
| 670 steps.push(newEvent); | |
| 671 } else { | |
| 672 console.assert(false, "Invalid async event phase"); | |
| 673 } | |
| 674 }, | |
| 675 | |
| 676 /** | |
| 677 * @param {string} name | |
| 678 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
| 679 */ | |
| 680 objectsByName: function(name) | |
| 681 { | |
| 682 var objects = this._objects[name]; | |
| 683 if (!objects) { | |
| 684 objects = []; | |
| 685 this._objects[name] = objects; | |
| 686 } | |
| 687 return objects; | |
| 688 }, | |
| 689 | |
| 690 /** | |
| 691 * @return {!Array.<string>} | |
| 692 */ | |
| 693 sortedObjectNames: function() | |
| 694 { | |
| 695 return Object.keys(this._objects).sort(); | |
| 696 }, | |
| 697 | |
| 698 /** | |
| 699 * @return {!Array.<!WebInspector.TracingModel.Thread>} | |
| 700 */ | |
| 701 sortedThreads: function() | |
| 702 { | |
| 703 return WebInspector.TracingModel.NamedObject._sort(Object.values(this._t
hreads)); | |
| 704 }, | |
| 705 | |
| 706 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
| 707 } | |
| 708 | |
| 709 /** | |
| 710 * @constructor | |
| 711 * @extends {WebInspector.TracingModel.NamedObject} | |
| 712 * @param {!WebInspector.TracingModel.Process} process | |
| 713 * @param {number} id | |
| 714 */ | |
| 715 WebInspector.TracingModel.Thread = function(process, id) | |
| 716 { | |
| 717 WebInspector.TracingModel.NamedObject.call(this); | |
| 718 this._process = process; | |
| 719 this._setName("Thread " + id); | |
| 720 this._events = []; | |
| 721 this._asyncEvents = []; | |
| 722 | |
| 723 this._stack = []; | |
| 724 } | |
| 725 | |
| 726 WebInspector.TracingModel.Thread.prototype = { | |
| 727 | |
| 728 /** | |
| 729 * @return {?WebInspector.Target} | |
| 730 */ | |
| 731 target: function() | |
| 732 { | |
| 733 //FIXME: correctly specify target | |
| 734 return WebInspector.targetManager.targets()[0]; | |
| 735 }, | |
| 736 | |
| 737 /** | |
| 738 * @param {!WebInspector.TracingManager.EventPayload} payload | |
| 739 * @return {?WebInspector.TracingModel.Event} event | |
| 740 */ | |
| 741 _addEvent: function(payload) | |
| 742 { | |
| 743 var timestamp = payload.ts / 1000; | |
| 744 if (payload.ph === WebInspector.TracingModel.Phase.End) { | |
| 745 // Quietly ignore unbalanced close events, they're legit (we could h
ave missed start one). | |
| 746 if (!this._stack.length) | |
| 747 return null; | |
| 748 var top = this._stack.pop(); | |
| 749 if (top.name !== payload.name || top.category !== payload.cat) | |
| 750 console.error("B/E events mismatch at " + top.startTime + " (" +
top.name + ") vs. " + timestamp + " (" + payload.name + ")"); | |
| 751 else | |
| 752 top._complete(payload); | |
| 753 return null; | |
| 754 } | |
| 755 var event = WebInspector.TracingModel.Event.fromPayload(payload, this); | |
| 756 if (payload.ph === WebInspector.TracingModel.Phase.Begin) | |
| 757 this._stack.push(event); | |
| 758 if (this._events.length && this._events.peekLast().startTime > event.sta
rtTime) | |
| 759 console.assert(false, "Event is our of order: " + event.name); | |
| 760 this._events.push(event); | |
| 761 return event; | |
| 762 }, | |
| 763 | |
| 764 /** | |
| 765 * @param {!Array.<!WebInspector.TracingModel.Event>} eventSteps | |
| 766 */ | |
| 767 _addAsyncEventSteps: function(eventSteps) | |
| 768 { | |
| 769 this._asyncEvents.push(eventSteps); | |
| 770 }, | |
| 771 | |
| 772 /** | |
| 773 * @return {!WebInspector.TracingModel.Process} | |
| 774 */ | |
| 775 process: function() | |
| 776 { | |
| 777 return this._process; | |
| 778 }, | |
| 779 | |
| 780 /** | |
| 781 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
| 782 */ | |
| 783 events: function() | |
| 784 { | |
| 785 return this._events; | |
| 786 }, | |
| 787 | |
| 788 /** | |
| 789 * @return {!Array.<!WebInspector.TracingModel.Event>} | |
| 790 */ | |
| 791 asyncEvents: function() | |
| 792 { | |
| 793 return this._asyncEvents; | |
| 794 }, | |
| 795 | |
| 796 __proto__: WebInspector.TracingModel.NamedObject.prototype | |
| 797 } | |
| 798 | |
| 799 | |
| 800 /** | |
| 801 * @constructor | |
| 802 * @implements {TracingAgent.Dispatcher} | |
| 803 * @param {!WebInspector.TracingManager} tracingManager | |
| 804 */ | |
| 805 WebInspector.TracingDispatcher = function(tracingManager) | |
| 806 { | |
| 807 this._tracingManager = tracingManager; | |
| 808 } | |
| 809 | |
| 810 WebInspector.TracingDispatcher.prototype = { | |
| 811 /** | |
| 812 * @param {number} usage | |
| 813 */ | |
| 814 bufferUsage: function(usage) | |
| 815 { | |
| 816 this._tracingManager._bufferUsage(usage); | |
| 817 }, | |
| 818 | |
| 819 /** | |
| 820 * @param {!Array.<!WebInspector.TracingManager.EventPayload>} data | |
| 821 */ | |
| 822 dataCollected: function(data) | |
| 823 { | |
| 824 this._tracingManager._eventsCollected(data); | |
| 825 }, | |
| 826 | |
| 827 tracingComplete: function() | |
| 828 { | |
| 829 this._tracingManager._tracingComplete(); | |
| 830 }, | |
| 831 | |
| 832 started: function() | |
| 833 { | |
| 834 this._tracingManager._tracingStarted(); | |
| 835 } | |
| 836 } | |
| OLD | NEW |