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