Index: third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js |
index 0eaef64a1ed603f7494606ea0b28cff1343c6ac6..035973201d59e5d000f496efb3a61b7bd7f07011 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js |
+++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js |
@@ -27,1477 +27,1431 @@ |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
- |
/** |
- * @constructor |
- * @param {!WebInspector.TimelineModel.Filter} eventFilter |
+ * @unrestricted |
*/ |
-WebInspector.TimelineModel = function(eventFilter) |
-{ |
+WebInspector.TimelineModel = class { |
+ /** |
+ * @param {!WebInspector.TimelineModel.Filter} eventFilter |
+ */ |
+ constructor(eventFilter) { |
this._eventFilter = eventFilter; |
this.reset(); |
-}; |
- |
-/** |
- * @enum {string} |
- */ |
-WebInspector.TimelineModel.RecordType = { |
- Task: "Task", |
- Program: "Program", |
- EventDispatch: "EventDispatch", |
- |
- GPUTask: "GPUTask", |
- |
- Animation: "Animation", |
- RequestMainThreadFrame: "RequestMainThreadFrame", |
- BeginFrame: "BeginFrame", |
- NeedsBeginFrameChanged: "NeedsBeginFrameChanged", |
- BeginMainThreadFrame: "BeginMainThreadFrame", |
- ActivateLayerTree: "ActivateLayerTree", |
- DrawFrame: "DrawFrame", |
- HitTest: "HitTest", |
- ScheduleStyleRecalculation: "ScheduleStyleRecalculation", |
- RecalculateStyles: "RecalculateStyles", // For backwards compatibility only, now replaced by UpdateLayoutTree. |
- UpdateLayoutTree: "UpdateLayoutTree", |
- InvalidateLayout: "InvalidateLayout", |
- Layout: "Layout", |
- UpdateLayer: "UpdateLayer", |
- UpdateLayerTree: "UpdateLayerTree", |
- PaintSetup: "PaintSetup", |
- Paint: "Paint", |
- PaintImage: "PaintImage", |
- Rasterize: "Rasterize", |
- RasterTask: "RasterTask", |
- ScrollLayer: "ScrollLayer", |
- CompositeLayers: "CompositeLayers", |
- |
- ScheduleStyleInvalidationTracking: "ScheduleStyleInvalidationTracking", |
- StyleRecalcInvalidationTracking: "StyleRecalcInvalidationTracking", |
- StyleInvalidatorInvalidationTracking: "StyleInvalidatorInvalidationTracking", |
- LayoutInvalidationTracking: "LayoutInvalidationTracking", |
- LayerInvalidationTracking: "LayerInvalidationTracking", |
- PaintInvalidationTracking: "PaintInvalidationTracking", |
- ScrollInvalidationTracking: "ScrollInvalidationTracking", |
- |
- ParseHTML: "ParseHTML", |
- ParseAuthorStyleSheet: "ParseAuthorStyleSheet", |
- |
- TimerInstall: "TimerInstall", |
- TimerRemove: "TimerRemove", |
- TimerFire: "TimerFire", |
- |
- XHRReadyStateChange: "XHRReadyStateChange", |
- XHRLoad: "XHRLoad", |
- CompileScript: "v8.compile", |
- EvaluateScript: "EvaluateScript", |
- |
- CommitLoad: "CommitLoad", |
- MarkLoad: "MarkLoad", |
- MarkDOMContent: "MarkDOMContent", |
- MarkFirstPaint: "MarkFirstPaint", |
- |
- TimeStamp: "TimeStamp", |
- ConsoleTime: "ConsoleTime", |
- UserTiming: "UserTiming", |
- |
- ResourceSendRequest: "ResourceSendRequest", |
- ResourceReceiveResponse: "ResourceReceiveResponse", |
- ResourceReceivedData: "ResourceReceivedData", |
- ResourceFinish: "ResourceFinish", |
- |
- RunMicrotasks: "RunMicrotasks", |
- FunctionCall: "FunctionCall", |
- GCEvent: "GCEvent", // For backwards compatibility only, now replaced by MinorGC/MajorGC. |
- MajorGC: "MajorGC", |
- MinorGC: "MinorGC", |
- JSFrame: "JSFrame", |
- JSSample: "JSSample", |
- // V8Sample events are coming from tracing and contain raw stacks with function addresses. |
- // After being processed with help of JitCodeAdded and JitCodeMoved events they |
- // get translated into function infos and stored as stacks in JSSample events. |
- V8Sample: "V8Sample", |
- JitCodeAdded: "JitCodeAdded", |
- JitCodeMoved: "JitCodeMoved", |
- ParseScriptOnBackground: "v8.parseOnBackground", |
- |
- UpdateCounters: "UpdateCounters", |
- |
- RequestAnimationFrame: "RequestAnimationFrame", |
- CancelAnimationFrame: "CancelAnimationFrame", |
- FireAnimationFrame: "FireAnimationFrame", |
- |
- RequestIdleCallback: "RequestIdleCallback", |
- CancelIdleCallback: "CancelIdleCallback", |
- FireIdleCallback: "FireIdleCallback", |
- |
- WebSocketCreate : "WebSocketCreate", |
- WebSocketSendHandshakeRequest : "WebSocketSendHandshakeRequest", |
- WebSocketReceiveHandshakeResponse : "WebSocketReceiveHandshakeResponse", |
- WebSocketDestroy : "WebSocketDestroy", |
- |
- EmbedderCallback : "EmbedderCallback", |
- |
- SetLayerTreeId: "SetLayerTreeId", |
- TracingStartedInPage: "TracingStartedInPage", |
- TracingSessionIdForWorker: "TracingSessionIdForWorker", |
- |
- DecodeImage: "Decode Image", |
- ResizeImage: "Resize Image", |
- DrawLazyPixelRef: "Draw LazyPixelRef", |
- DecodeLazyPixelRef: "Decode LazyPixelRef", |
- |
- LazyPixelRef: "LazyPixelRef", |
- LayerTreeHostImplSnapshot: "cc::LayerTreeHostImpl", |
- PictureSnapshot: "cc::Picture", |
- DisplayItemListSnapshot: "cc::DisplayItemList", |
- LatencyInfo: "LatencyInfo", |
- LatencyInfoFlow: "LatencyInfo.Flow", |
- InputLatencyMouseMove: "InputLatency::MouseMove", |
- InputLatencyMouseWheel: "InputLatency::MouseWheel", |
- ImplSideFling: "InputHandlerProxy::HandleGestureFling::started", |
- GCIdleLazySweep: "ThreadState::performIdleLazySweep", |
- GCCompleteSweep: "ThreadState::completeSweep", |
- GCCollectGarbage: "BlinkGCMarking", |
- |
- // CpuProfile is a virtual event created on frontend to support |
- // serialization of CPU Profiles within tracing timeline data. |
- CpuProfile: "CpuProfile", |
- Profile: "Profile" |
-}; |
- |
-WebInspector.TimelineModel.Category = { |
- Console: "blink.console", |
- UserTiming: "blink.user_timing", |
- LatencyInfo: "latencyInfo" |
-}; |
- |
-/** |
- * @enum {string} |
- */ |
-WebInspector.TimelineModel.WarningType = { |
- ForcedStyle: "ForcedStyle", |
- ForcedLayout: "ForcedLayout", |
- IdleDeadlineExceeded: "IdleDeadlineExceeded", |
- V8Deopt: "V8Deopt" |
-}; |
- |
-WebInspector.TimelineModel.MainThreadName = "main"; |
-WebInspector.TimelineModel.WorkerThreadName = "DedicatedWorker Thread"; |
-WebInspector.TimelineModel.RendererMainThreadName = "CrRendererMain"; |
- |
-/** |
- * @enum {symbol} |
- */ |
-WebInspector.TimelineModel.AsyncEventGroup = { |
- animation: Symbol("animation"), |
- console: Symbol("console"), |
- userTiming: Symbol("userTiming"), |
- input: Symbol("input") |
-}; |
- |
-/** |
- * @param {!Array.<!WebInspector.TracingModel.Event>} events |
- * @param {function(!WebInspector.TracingModel.Event)} onStartEvent |
- * @param {function(!WebInspector.TracingModel.Event)} onEndEvent |
- * @param {function(!WebInspector.TracingModel.Event,?WebInspector.TracingModel.Event)|undefined=} onInstantEvent |
- * @param {number=} startTime |
- * @param {number=} endTime |
- */ |
-WebInspector.TimelineModel.forEachEvent = function(events, onStartEvent, onEndEvent, onInstantEvent, startTime, endTime) |
-{ |
+ } |
+ |
+ /** |
+ * @param {!Array.<!WebInspector.TracingModel.Event>} events |
+ * @param {function(!WebInspector.TracingModel.Event)} onStartEvent |
+ * @param {function(!WebInspector.TracingModel.Event)} onEndEvent |
+ * @param {function(!WebInspector.TracingModel.Event,?WebInspector.TracingModel.Event)|undefined=} onInstantEvent |
+ * @param {number=} startTime |
+ * @param {number=} endTime |
+ */ |
+ static forEachEvent(events, onStartEvent, onEndEvent, onInstantEvent, startTime, endTime) { |
startTime = startTime || 0; |
endTime = endTime || Infinity; |
var stack = []; |
for (var i = 0; i < events.length; ++i) { |
- var e = events[i]; |
- if ((e.endTime || e.startTime) < startTime) |
- continue; |
- if (e.startTime >= endTime) |
- break; |
- if (WebInspector.TracingModel.isAsyncPhase(e.phase) || WebInspector.TracingModel.isFlowPhase(e.phase)) |
- continue; |
- while (stack.length && stack.peekLast().endTime <= e.startTime) |
- onEndEvent(stack.pop()); |
- if (e.duration) { |
- onStartEvent(e); |
- stack.push(e); |
- } else { |
- onInstantEvent && onInstantEvent(e, stack.peekLast() || null); |
- } |
- } |
- while (stack.length) |
+ var e = events[i]; |
+ if ((e.endTime || e.startTime) < startTime) |
+ continue; |
+ if (e.startTime >= endTime) |
+ break; |
+ if (WebInspector.TracingModel.isAsyncPhase(e.phase) || WebInspector.TracingModel.isFlowPhase(e.phase)) |
+ continue; |
+ while (stack.length && stack.peekLast().endTime <= e.startTime) |
onEndEvent(stack.pop()); |
-}; |
- |
-WebInspector.TimelineModel.DevToolsMetadataEvent = { |
- TracingStartedInBrowser: "TracingStartedInBrowser", |
- TracingStartedInPage: "TracingStartedInPage", |
- TracingSessionIdForWorker: "TracingSessionIdForWorker", |
-}; |
- |
-/** |
- * @constructor |
- * @param {string} name |
- */ |
-WebInspector.TimelineModel.VirtualThread = function(name) |
-{ |
- this.name = name; |
- /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
- this.events = []; |
- /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */ |
- this.asyncEventsByGroup = new Map(); |
-}; |
- |
-WebInspector.TimelineModel.VirtualThread.prototype = { |
- /** |
- * @return {boolean} |
- */ |
- isWorker: function() |
- { |
- return this.name === WebInspector.TimelineModel.WorkerThreadName; |
- } |
-}; |
- |
-/** |
- * @constructor |
- * @param {!WebInspector.TracingModel.Event} traceEvent |
- */ |
-WebInspector.TimelineModel.Record = function(traceEvent) |
-{ |
- this._event = traceEvent; |
- this._children = []; |
-}; |
- |
-/** |
- * @param {!WebInspector.TimelineModel.Record} a |
- * @param {!WebInspector.TimelineModel.Record} b |
- * @return {number} |
- */ |
-WebInspector.TimelineModel.Record._compareStartTime = function(a, b) |
-{ |
- // Never return 0 as otherwise equal records would be merged. |
- return a.startTime() <= b.startTime() ? -1 : 1; |
-}; |
- |
-WebInspector.TimelineModel.Record.prototype = { |
- /** |
- * @return {?WebInspector.Target} |
- */ |
- target: function() |
- { |
- var threadName = this._event.thread.name(); |
- // FIXME: correctly specify target |
- return threadName === WebInspector.TimelineModel.RendererMainThreadName ? WebInspector.targetManager.targets()[0] || null : null; |
- }, |
- |
- /** |
- * @return {!Array.<!WebInspector.TimelineModel.Record>} |
- */ |
- children: function() |
- { |
- return this._children; |
- }, |
- |
- /** |
- * @return {number} |
- */ |
- startTime: function() |
- { |
- return this._event.startTime; |
- }, |
- |
- /** |
- * @return {number} |
- */ |
- endTime: function() |
- { |
- return this._event.endTime || this._event.startTime; |
- }, |
- |
- /** |
- * @return {string} |
- */ |
- thread: function() |
- { |
- if (this._event.thread.name() === WebInspector.TimelineModel.RendererMainThreadName) |
- return WebInspector.TimelineModel.MainThreadName; |
- return this._event.thread.name(); |
- }, |
- |
- /** |
- * @return {!WebInspector.TimelineModel.RecordType} |
- */ |
- type: function() |
- { |
- return WebInspector.TimelineModel._eventType(this._event); |
- }, |
- |
- /** |
- * @param {string} key |
- * @return {?Object} |
- */ |
- getUserObject: function(key) |
- { |
- if (key === "TimelineUIUtils::preview-element") |
- return this._event.previewElement; |
- throw new Error("Unexpected key: " + key); |
- }, |
- |
- /** |
- * @param {string} key |
- * @param {?Object|undefined} value |
- */ |
- setUserObject: function(key, value) |
- { |
- if (key !== "TimelineUIUtils::preview-element") |
- throw new Error("Unexpected key: " + key); |
- this._event.previewElement = /** @type {?Element} */ (value); |
- }, |
- |
- /** |
- * @return {!WebInspector.TracingModel.Event} |
- */ |
- traceEvent: function() |
- { |
- return this._event; |
- }, |
- |
- /** |
- * @param {!WebInspector.TimelineModel.Record} child |
- */ |
- _addChild: function(child) |
- { |
- this._children.push(child); |
- child.parent = this; |
+ if (e.duration) { |
+ onStartEvent(e); |
+ stack.push(e); |
+ } else { |
+ onInstantEvent && onInstantEvent(e, stack.peekLast() || null); |
+ } |
} |
-}; |
- |
-/** @typedef {!{page: !Array<!WebInspector.TracingModel.Event>, workers: !Array<!WebInspector.TracingModel.Event>}} */ |
-WebInspector.TimelineModel.MetadataEvents; |
+ while (stack.length) |
+ onEndEvent(stack.pop()); |
+ } |
-/** |
- * @return {!WebInspector.TimelineModel.RecordType} |
- */ |
-WebInspector.TimelineModel._eventType = function(event) |
-{ |
+ /** |
+ * @return {!WebInspector.TimelineModel.RecordType} |
+ */ |
+ static _eventType(event) { |
if (event.hasCategory(WebInspector.TimelineModel.Category.Console)) |
- return WebInspector.TimelineModel.RecordType.ConsoleTime; |
+ return WebInspector.TimelineModel.RecordType.ConsoleTime; |
if (event.hasCategory(WebInspector.TimelineModel.Category.UserTiming)) |
- return WebInspector.TimelineModel.RecordType.UserTiming; |
+ return WebInspector.TimelineModel.RecordType.UserTiming; |
if (event.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo)) |
- return WebInspector.TimelineModel.RecordType.LatencyInfo; |
+ return WebInspector.TimelineModel.RecordType.LatencyInfo; |
return /** @type !WebInspector.TimelineModel.RecordType */ (event.name); |
-}; |
+ } |
+ |
+ /** |
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ static isVisible(filters, event) { |
+ for (var i = 0; i < filters.length; ++i) { |
+ if (!filters[i].accept(event)) |
+ return false; |
+ } |
+ return true; |
+ } |
-WebInspector.TimelineModel.prototype = { |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ static isMarkerEvent(event) { |
+ var recordTypes = WebInspector.TimelineModel.RecordType; |
+ switch (event.name) { |
+ case recordTypes.TimeStamp: |
+ case recordTypes.MarkFirstPaint: |
+ return true; |
+ case recordTypes.MarkDOMContent: |
+ case recordTypes.MarkLoad: |
+ return event.args['data']['isMainFrame']; |
+ default: |
+ return false; |
+ } |
+ } |
+ |
+ /** |
+ * @deprecated Test use only! |
+ * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspector.TimelineModel.Record,number)} preOrderCallback |
+ * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)=} postOrderCallback |
+ * @return {boolean} |
+ */ |
+ forAllRecords(preOrderCallback, postOrderCallback) { |
/** |
- * @deprecated Test use only! |
- * @param {?function(!WebInspector.TimelineModel.Record)|?function(!WebInspector.TimelineModel.Record,number)} preOrderCallback |
- * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)=} postOrderCallback |
+ * @param {!Array.<!WebInspector.TimelineModel.Record>} records |
+ * @param {number} depth |
* @return {boolean} |
*/ |
- forAllRecords: function(preOrderCallback, postOrderCallback) |
- { |
- /** |
- * @param {!Array.<!WebInspector.TimelineModel.Record>} records |
- * @param {number} depth |
- * @return {boolean} |
- */ |
- function processRecords(records, depth) |
- { |
- for (var i = 0; i < records.length; ++i) { |
- var record = records[i]; |
- if (preOrderCallback && preOrderCallback(record, depth)) |
- return true; |
- if (processRecords(record.children(), depth + 1)) |
- return true; |
- if (postOrderCallback && postOrderCallback(record, depth)) |
- return true; |
- } |
- return false; |
- } |
- return processRecords(this._records, 0); |
- }, |
- |
- /** |
- * @param {!Array<!WebInspector.TimelineModel.Filter>} filters |
- * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)} callback |
- */ |
- forAllFilteredRecords: function(filters, callback) |
- { |
- /** |
- * @param {!WebInspector.TimelineModel.Record} record |
- * @param {number} depth |
- * @this {WebInspector.TimelineModel} |
- * @return {boolean} |
- */ |
- function processRecord(record, depth) |
- { |
- var visible = WebInspector.TimelineModel.isVisible(filters, record.traceEvent()); |
- if (visible && callback(record, depth)) |
- return true; |
- |
- for (var i = 0; i < record.children().length; ++i) { |
- if (processRecord.call(this, record.children()[i], visible ? depth + 1 : depth)) |
- return true; |
- } |
- return false; |
- } |
- |
- for (var i = 0; i < this._records.length; ++i) |
- processRecord.call(this, this._records[i], 0); |
- }, |
- |
- /** |
- * @return {!Array.<!WebInspector.TimelineModel.Record>} |
- */ |
- records: function() |
- { |
- return this._records; |
- }, |
- |
- /** |
- * @return {!Array<!WebInspector.CPUProfileDataModel>} |
- */ |
- cpuProfiles: function() |
- { |
- return this._cpuProfiles; |
- }, |
- |
- /** |
- * @return {?string} |
- */ |
- sessionId: function() |
- { |
- return this._sessionId; |
- }, |
- |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {?WebInspector.Target} |
- */ |
- targetByEvent: function(event) |
- { |
- // FIXME: Consider returning null for loaded traces. |
- var workerId = this._workerIdByThread.get(event.thread); |
- var mainTarget = WebInspector.targetManager.mainTarget(); |
- return workerId ? mainTarget.subTargetsManager.targetForId(workerId) : mainTarget; |
- }, |
- |
- /** |
- * @param {!WebInspector.TracingModel} tracingModel |
- * @param {boolean=} produceTraceStartedInPage |
- */ |
- setEvents: function(tracingModel, produceTraceStartedInPage) |
- { |
- this.reset(); |
- this._resetProcessingState(); |
- |
- this._minimumRecordTime = tracingModel.minimumRecordTime(); |
- this._maximumRecordTime = tracingModel.maximumRecordTime(); |
- |
- var metadataEvents = this._processMetadataEvents(tracingModel, !!produceTraceStartedInPage); |
- if (Runtime.experiments.isEnabled("timelineShowAllProcesses")) { |
- var lastPageMetaEvent = metadataEvents.page.peekLast(); |
- for (var process of tracingModel.sortedProcesses()) { |
- for (var thread of process.sortedThreads()) |
- this._processThreadEvents(tracingModel, 0, Infinity, thread, thread === lastPageMetaEvent.thread); |
- } |
- } else { |
- var startTime = 0; |
- for (var i = 0, length = metadataEvents.page.length; i < length; i++) { |
- var metaEvent = metadataEvents.page[i]; |
- var process = metaEvent.thread.process(); |
- var endTime = i + 1 < length ? metadataEvents.page[i + 1].startTime : Infinity; |
- this._currentPage = metaEvent.args["data"] && metaEvent.args["data"]["page"]; |
- for (var thread of process.sortedThreads()) { |
- if (thread.name() === WebInspector.TimelineModel.WorkerThreadName) { |
- var workerMetaEvent = metadataEvents.workers.find(e => e.args["data"]["workerThreadId"] === thread.id()); |
- if (!workerMetaEvent) |
- continue; |
- var workerId = workerMetaEvent.args["data"]["workerId"]; |
- if (workerId) |
- this._workerIdByThread.set(thread, workerId); |
- } |
- this._processThreadEvents(tracingModel, startTime, endTime, thread, thread === metaEvent.thread); |
- } |
- startTime = endTime; |
- } |
- } |
- this._inspectedTargetEvents.sort(WebInspector.TracingModel.Event.compareStartTime); |
- |
- this._processBrowserEvents(tracingModel); |
- this._buildTimelineRecords(); |
- this._buildGPUEvents(tracingModel); |
- this._insertFirstPaintEvent(); |
- this._resetProcessingState(); |
- }, |
- |
- /** |
- * @param {!WebInspector.TracingModel} tracingModel |
- * @param {boolean} produceTraceStartedInPage |
- * @return {!WebInspector.TimelineModel.MetadataEvents} |
- */ |
- _processMetadataEvents: function(tracingModel, produceTraceStartedInPage) |
- { |
- var metadataEvents = tracingModel.devToolsMetadataEvents(); |
- |
- var pageDevToolsMetadataEvents = []; |
- var workersDevToolsMetadataEvents = []; |
- for (var event of metadataEvents) { |
- if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage) { |
- pageDevToolsMetadataEvents.push(event); |
- } else if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingSessionIdForWorker) { |
- workersDevToolsMetadataEvents.push(event); |
- } else if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInBrowser) { |
- console.assert(!this._mainFrameNodeId, "Multiple sessions in trace"); |
- this._mainFrameNodeId = event.args["frameTreeNodeId"]; |
- } |
- } |
- if (!pageDevToolsMetadataEvents.length) { |
- // The trace is probably coming not from DevTools. Make a mock Metadata event. |
- var pageMetaEvent = produceTraceStartedInPage ? this._makeMockPageMetadataEvent(tracingModel) : null; |
- if (!pageMetaEvent) { |
- console.error(WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage + " event not found."); |
- return {page: [], workers: []}; |
- } |
- pageDevToolsMetadataEvents.push(pageMetaEvent); |
- } |
- var sessionId = pageDevToolsMetadataEvents[0].args["sessionId"] || pageDevToolsMetadataEvents[0].args["data"]["sessionId"]; |
- this._sessionId = sessionId; |
- |
- var mismatchingIds = new Set(); |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- function checkSessionId(event) |
- { |
- var args = event.args; |
- // FIXME: put sessionId into args["data"] for TracingStartedInPage event. |
- if (args["data"]) |
- args = args["data"]; |
- var id = args["sessionId"]; |
- if (id === sessionId) |
- return true; |
- mismatchingIds.add(id); |
- return false; |
- } |
- var result = { |
- page: pageDevToolsMetadataEvents.filter(checkSessionId).sort(WebInspector.TracingModel.Event.compareStartTime), |
- workers: workersDevToolsMetadataEvents.filter(checkSessionId).sort(WebInspector.TracingModel.Event.compareStartTime) |
- }; |
- if (mismatchingIds.size) |
- WebInspector.console.error("Timeline recording was started in more than one page simultaneously. Session id mismatch: " + this._sessionId + " and " + mismatchingIds.valuesArray() + "."); |
- return result; |
- }, |
- |
+ function processRecords(records, depth) { |
+ for (var i = 0; i < records.length; ++i) { |
+ var record = records[i]; |
+ if (preOrderCallback && preOrderCallback(record, depth)) |
+ return true; |
+ if (processRecords(record.children(), depth + 1)) |
+ return true; |
+ if (postOrderCallback && postOrderCallback(record, depth)) |
+ return true; |
+ } |
+ return false; |
+ } |
+ return processRecords(this._records, 0); |
+ } |
+ |
+ /** |
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters |
+ * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)} callback |
+ */ |
+ forAllFilteredRecords(filters, callback) { |
/** |
- * @param {!WebInspector.TracingModel} tracingModel |
- * @return {?WebInspector.TracingModel.Event} |
+ * @param {!WebInspector.TimelineModel.Record} record |
+ * @param {number} depth |
+ * @this {WebInspector.TimelineModel} |
+ * @return {boolean} |
*/ |
- _makeMockPageMetadataEvent: function(tracingModel) |
- { |
- var rendererMainThreadName = WebInspector.TimelineModel.RendererMainThreadName; |
- // FIXME: pick up the first renderer process for now. |
- var process = tracingModel.sortedProcesses().filter(function(p) { return p.threadByName(rendererMainThreadName); })[0]; |
- var thread = process && process.threadByName(rendererMainThreadName); |
- if (!thread) |
- return null; |
- var pageMetaEvent = new WebInspector.TracingModel.Event( |
- WebInspector.TracingModel.DevToolsMetadataEventCategory, |
- WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage, |
- WebInspector.TracingModel.Phase.Metadata, |
- tracingModel.minimumRecordTime(), thread); |
- pageMetaEvent.addArgs({"data": {"sessionId": "mockSessionId"}}); |
- return pageMetaEvent; |
- }, |
- |
- _insertFirstPaintEvent: function() |
- { |
- if (!this._firstCompositeLayers) |
- return; |
- |
- // First Paint is actually a DrawFrame that happened after first CompositeLayers following last CommitLoadEvent. |
- var recordTypes = WebInspector.TimelineModel.RecordType; |
- var i = this._inspectedTargetEvents.lowerBound(this._firstCompositeLayers, WebInspector.TracingModel.Event.compareStartTime); |
- for (; i < this._inspectedTargetEvents.length && this._inspectedTargetEvents[i].name !== recordTypes.DrawFrame; ++i) { } |
- if (i >= this._inspectedTargetEvents.length) |
- return; |
- var drawFrameEvent = this._inspectedTargetEvents[i]; |
- var firstPaintEvent = new WebInspector.TracingModel.Event(drawFrameEvent.categoriesString, recordTypes.MarkFirstPaint, WebInspector.TracingModel.Phase.Instant, drawFrameEvent.startTime, drawFrameEvent.thread); |
- this._mainThreadEvents.splice(this._mainThreadEvents.lowerBound(firstPaintEvent, WebInspector.TracingModel.Event.compareStartTime), 0, firstPaintEvent); |
- var firstPaintRecord = new WebInspector.TimelineModel.Record(firstPaintEvent); |
- this._eventDividerRecords.splice(this._eventDividerRecords.lowerBound(firstPaintRecord, WebInspector.TimelineModel.Record._compareStartTime), 0, firstPaintRecord); |
- }, |
+ function processRecord(record, depth) { |
+ var visible = WebInspector.TimelineModel.isVisible(filters, record.traceEvent()); |
+ if (visible && callback(record, depth)) |
+ return true; |
- /** |
- * @param {!WebInspector.TracingModel} tracingModel |
- */ |
- _processBrowserEvents: function(tracingModel) |
- { |
- var browserMain = WebInspector.TracingModel.browserMainThread(tracingModel); |
- if (!browserMain) |
- return; |
- |
- // Disregard regular events, we don't need them yet, but still process to get proper metadata. |
- browserMain.events().forEach(this._processBrowserEvent, this); |
- /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */ |
- var asyncEventsByGroup = new Map(); |
- this._processAsyncEvents(asyncEventsByGroup, browserMain.asyncEvents()); |
- this._mergeAsyncEvents(this._mainThreadAsyncEventsByGroup, asyncEventsByGroup); |
- }, |
- |
- _buildTimelineRecords: function() |
- { |
- var topLevelRecords = this._buildTimelineRecordsForThread(this.mainThreadEvents()); |
- for (var i = 0; i < topLevelRecords.length; i++) { |
- var record = topLevelRecords[i]; |
- if (WebInspector.TracingModel.isTopLevelEvent(record.traceEvent())) |
- this._mainThreadTasks.push(record); |
- } |
+ for (var i = 0; i < record.children().length; ++i) { |
+ if (processRecord.call(this, record.children()[i], visible ? depth + 1 : depth)) |
+ return true; |
+ } |
+ return false; |
+ } |
- /** |
- * @param {!WebInspector.TimelineModel.VirtualThread} virtualThread |
- * @this {!WebInspector.TimelineModel} |
- */ |
- function processVirtualThreadEvents(virtualThread) |
- { |
- var threadRecords = this._buildTimelineRecordsForThread(virtualThread.events); |
- topLevelRecords = topLevelRecords.mergeOrdered(threadRecords, WebInspector.TimelineModel.Record._compareStartTime); |
+ for (var i = 0; i < this._records.length; ++i) |
+ processRecord.call(this, this._records[i], 0); |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TimelineModel.Record>} |
+ */ |
+ records() { |
+ return this._records; |
+ } |
+ |
+ /** |
+ * @return {!Array<!WebInspector.CPUProfileDataModel>} |
+ */ |
+ cpuProfiles() { |
+ return this._cpuProfiles; |
+ } |
+ |
+ /** |
+ * @return {?string} |
+ */ |
+ sessionId() { |
+ return this._sessionId; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {?WebInspector.Target} |
+ */ |
+ targetByEvent(event) { |
+ // FIXME: Consider returning null for loaded traces. |
+ var workerId = this._workerIdByThread.get(event.thread); |
+ var mainTarget = WebInspector.targetManager.mainTarget(); |
+ return workerId ? mainTarget.subTargetsManager.targetForId(workerId) : mainTarget; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ * @param {boolean=} produceTraceStartedInPage |
+ */ |
+ setEvents(tracingModel, produceTraceStartedInPage) { |
+ this.reset(); |
+ this._resetProcessingState(); |
+ |
+ this._minimumRecordTime = tracingModel.minimumRecordTime(); |
+ this._maximumRecordTime = tracingModel.maximumRecordTime(); |
+ |
+ var metadataEvents = this._processMetadataEvents(tracingModel, !!produceTraceStartedInPage); |
+ if (Runtime.experiments.isEnabled('timelineShowAllProcesses')) { |
+ var lastPageMetaEvent = metadataEvents.page.peekLast(); |
+ for (var process of tracingModel.sortedProcesses()) { |
+ for (var thread of process.sortedThreads()) |
+ this._processThreadEvents(tracingModel, 0, Infinity, thread, thread === lastPageMetaEvent.thread); |
+ } |
+ } else { |
+ var startTime = 0; |
+ for (var i = 0, length = metadataEvents.page.length; i < length; i++) { |
+ var metaEvent = metadataEvents.page[i]; |
+ var process = metaEvent.thread.process(); |
+ var endTime = i + 1 < length ? metadataEvents.page[i + 1].startTime : Infinity; |
+ this._currentPage = metaEvent.args['data'] && metaEvent.args['data']['page']; |
+ for (var thread of process.sortedThreads()) { |
+ if (thread.name() === WebInspector.TimelineModel.WorkerThreadName) { |
+ var workerMetaEvent = metadataEvents.workers.find(e => e.args['data']['workerThreadId'] === thread.id()); |
+ if (!workerMetaEvent) |
+ continue; |
+ var workerId = workerMetaEvent.args['data']['workerId']; |
+ if (workerId) |
+ this._workerIdByThread.set(thread, workerId); |
+ } |
+ this._processThreadEvents(tracingModel, startTime, endTime, thread, thread === metaEvent.thread); |
} |
- this.virtualThreads().forEach(processVirtualThreadEvents.bind(this)); |
- this._records = topLevelRecords; |
- }, |
- |
- /** |
- * @param {!WebInspector.TracingModel} tracingModel |
- */ |
- _buildGPUEvents: function(tracingModel) |
- { |
- var thread = tracingModel.threadByName("GPU Process", "CrGpuMain"); |
- if (!thread) |
- return; |
- var gpuEventName = WebInspector.TimelineModel.RecordType.GPUTask; |
- this._gpuEvents = thread.events().filter(event => event.name === gpuEventName); |
- }, |
+ startTime = endTime; |
+ } |
+ } |
+ this._inspectedTargetEvents.sort(WebInspector.TracingModel.Event.compareStartTime); |
+ |
+ this._processBrowserEvents(tracingModel); |
+ this._buildTimelineRecords(); |
+ this._buildGPUEvents(tracingModel); |
+ this._insertFirstPaintEvent(); |
+ this._resetProcessingState(); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ * @param {boolean} produceTraceStartedInPage |
+ * @return {!WebInspector.TimelineModel.MetadataEvents} |
+ */ |
+ _processMetadataEvents(tracingModel, produceTraceStartedInPage) { |
+ var metadataEvents = tracingModel.devToolsMetadataEvents(); |
+ |
+ var pageDevToolsMetadataEvents = []; |
+ var workersDevToolsMetadataEvents = []; |
+ for (var event of metadataEvents) { |
+ if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage) { |
+ pageDevToolsMetadataEvents.push(event); |
+ } else if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingSessionIdForWorker) { |
+ workersDevToolsMetadataEvents.push(event); |
+ } else if (event.name === WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInBrowser) { |
+ console.assert(!this._mainFrameNodeId, 'Multiple sessions in trace'); |
+ this._mainFrameNodeId = event.args['frameTreeNodeId']; |
+ } |
+ } |
+ if (!pageDevToolsMetadataEvents.length) { |
+ // The trace is probably coming not from DevTools. Make a mock Metadata event. |
+ var pageMetaEvent = produceTraceStartedInPage ? this._makeMockPageMetadataEvent(tracingModel) : null; |
+ if (!pageMetaEvent) { |
+ console.error(WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage + ' event not found.'); |
+ return {page: [], workers: []}; |
+ } |
+ pageDevToolsMetadataEvents.push(pageMetaEvent); |
+ } |
+ var sessionId = |
+ pageDevToolsMetadataEvents[0].args['sessionId'] || pageDevToolsMetadataEvents[0].args['data']['sessionId']; |
+ this._sessionId = sessionId; |
+ var mismatchingIds = new Set(); |
/** |
- * @param {!Array.<!WebInspector.TracingModel.Event>} threadEvents |
- * @return {!Array.<!WebInspector.TimelineModel.Record>} |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
*/ |
- _buildTimelineRecordsForThread: function(threadEvents) |
- { |
- var recordStack = []; |
- var topLevelRecords = []; |
- |
- for (var i = 0, size = threadEvents.length; i < size; ++i) { |
- var event = threadEvents[i]; |
- for (var top = recordStack.peekLast(); top && top._event.endTime <= event.startTime; top = recordStack.peekLast()) |
- recordStack.pop(); |
- if (event.phase === WebInspector.TracingModel.Phase.AsyncEnd || event.phase === WebInspector.TracingModel.Phase.NestableAsyncEnd) |
- continue; |
- var parentRecord = recordStack.peekLast(); |
- // Maintain the back-end logic of old timeline, skip console.time() / console.timeEnd() that are not properly nested. |
- if (WebInspector.TracingModel.isAsyncBeginPhase(event.phase) && parentRecord && event.endTime > parentRecord._event.endTime) |
- continue; |
- var record = new WebInspector.TimelineModel.Record(event); |
- if (WebInspector.TimelineModel.isMarkerEvent(event)) |
- this._eventDividerRecords.push(record); |
- if (!this._eventFilter.accept(event) && !WebInspector.TracingModel.isTopLevelEvent(event)) |
- continue; |
- if (parentRecord) |
- parentRecord._addChild(record); |
- else |
- topLevelRecords.push(record); |
- if (event.endTime) |
- recordStack.push(record); |
- } |
- |
- return topLevelRecords; |
- }, |
- |
- _resetProcessingState: function() |
- { |
- this._asyncEventTracker = new WebInspector.TimelineAsyncEventTracker(); |
- this._invalidationTracker = new WebInspector.InvalidationTracker(); |
- this._layoutInvalidate = {}; |
- this._lastScheduleStyleRecalculation = {}; |
- this._paintImageEventByPixelRefId = {}; |
- this._lastPaintForLayer = {}; |
- this._lastRecalculateStylesEvent = null; |
- this._currentScriptEvent = null; |
- this._eventStack = []; |
- this._hadCommitLoad = false; |
- this._firstCompositeLayers = null; |
- /** @type {!Set<string>} */ |
- this._knownInputEvents = new Set(); |
- this._currentPage = null; |
- }, |
+ function checkSessionId(event) { |
+ var args = event.args; |
+ // FIXME: put sessionId into args["data"] for TracingStartedInPage event. |
+ if (args['data']) |
+ args = args['data']; |
+ var id = args['sessionId']; |
+ if (id === sessionId) |
+ return true; |
+ mismatchingIds.add(id); |
+ return false; |
+ } |
+ var result = { |
+ page: pageDevToolsMetadataEvents.filter(checkSessionId).sort(WebInspector.TracingModel.Event.compareStartTime), |
+ workers: |
+ workersDevToolsMetadataEvents.filter(checkSessionId).sort(WebInspector.TracingModel.Event.compareStartTime) |
+ }; |
+ if (mismatchingIds.size) |
+ WebInspector.console.error( |
+ 'Timeline recording was started in more than one page simultaneously. Session id mismatch: ' + |
+ this._sessionId + ' and ' + mismatchingIds.valuesArray() + '.'); |
+ return result; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ * @return {?WebInspector.TracingModel.Event} |
+ */ |
+ _makeMockPageMetadataEvent(tracingModel) { |
+ var rendererMainThreadName = WebInspector.TimelineModel.RendererMainThreadName; |
+ // FIXME: pick up the first renderer process for now. |
+ var process = tracingModel.sortedProcesses().filter(function(p) { |
+ return p.threadByName(rendererMainThreadName); |
+ })[0]; |
+ var thread = process && process.threadByName(rendererMainThreadName); |
+ if (!thread) |
+ return null; |
+ var pageMetaEvent = new WebInspector.TracingModel.Event( |
+ WebInspector.TracingModel.DevToolsMetadataEventCategory, |
+ WebInspector.TimelineModel.DevToolsMetadataEvent.TracingStartedInPage, WebInspector.TracingModel.Phase.Metadata, |
+ tracingModel.minimumRecordTime(), thread); |
+ pageMetaEvent.addArgs({'data': {'sessionId': 'mockSessionId'}}); |
+ return pageMetaEvent; |
+ } |
+ |
+ _insertFirstPaintEvent() { |
+ if (!this._firstCompositeLayers) |
+ return; |
+ |
+ // First Paint is actually a DrawFrame that happened after first CompositeLayers following last CommitLoadEvent. |
+ var recordTypes = WebInspector.TimelineModel.RecordType; |
+ var i = this._inspectedTargetEvents.lowerBound( |
+ this._firstCompositeLayers, WebInspector.TracingModel.Event.compareStartTime); |
+ for (; i < this._inspectedTargetEvents.length && this._inspectedTargetEvents[i].name !== recordTypes.DrawFrame; |
+ ++i) { |
+ } |
+ if (i >= this._inspectedTargetEvents.length) |
+ return; |
+ var drawFrameEvent = this._inspectedTargetEvents[i]; |
+ var firstPaintEvent = new WebInspector.TracingModel.Event( |
+ drawFrameEvent.categoriesString, recordTypes.MarkFirstPaint, WebInspector.TracingModel.Phase.Instant, |
+ drawFrameEvent.startTime, drawFrameEvent.thread); |
+ this._mainThreadEvents.splice( |
+ this._mainThreadEvents.lowerBound(firstPaintEvent, WebInspector.TracingModel.Event.compareStartTime), 0, |
+ firstPaintEvent); |
+ var firstPaintRecord = new WebInspector.TimelineModel.Record(firstPaintEvent); |
+ this._eventDividerRecords.splice( |
+ this._eventDividerRecords.lowerBound(firstPaintRecord, WebInspector.TimelineModel.Record._compareStartTime), 0, |
+ firstPaintRecord); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ */ |
+ _processBrowserEvents(tracingModel) { |
+ var browserMain = WebInspector.TracingModel.browserMainThread(tracingModel); |
+ if (!browserMain) |
+ return; |
+ |
+ // Disregard regular events, we don't need them yet, but still process to get proper metadata. |
+ browserMain.events().forEach(this._processBrowserEvent, this); |
+ /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */ |
+ var asyncEventsByGroup = new Map(); |
+ this._processAsyncEvents(asyncEventsByGroup, browserMain.asyncEvents()); |
+ this._mergeAsyncEvents(this._mainThreadAsyncEventsByGroup, asyncEventsByGroup); |
+ } |
+ |
+ _buildTimelineRecords() { |
+ var topLevelRecords = this._buildTimelineRecordsForThread(this.mainThreadEvents()); |
+ for (var i = 0; i < topLevelRecords.length; i++) { |
+ var record = topLevelRecords[i]; |
+ if (WebInspector.TracingModel.isTopLevelEvent(record.traceEvent())) |
+ this._mainThreadTasks.push(record); |
+ } |
/** |
- * @param {!WebInspector.TracingModel} tracingModel |
- * @param {!WebInspector.TracingModel.Thread} thread |
- * @return {?WebInspector.CPUProfileDataModel} |
+ * @param {!WebInspector.TimelineModel.VirtualThread} virtualThread |
+ * @this {!WebInspector.TimelineModel} |
*/ |
- _extractCpuProfile: function(tracingModel, thread) |
- { |
- var events = thread.events(); |
- var cpuProfile; |
- |
- // Check for legacy CpuProfile event format first. |
- var cpuProfileEvent = events.peekLast(); |
- if (cpuProfileEvent && cpuProfileEvent.name === WebInspector.TimelineModel.RecordType.CpuProfile) { |
- var eventData = cpuProfileEvent.args["data"]; |
- cpuProfile = /** @type {?ProfilerAgent.Profile} */ (eventData && eventData["cpuProfile"]); |
- } |
+ function processVirtualThreadEvents(virtualThread) { |
+ var threadRecords = this._buildTimelineRecordsForThread(virtualThread.events); |
+ topLevelRecords = |
+ topLevelRecords.mergeOrdered(threadRecords, WebInspector.TimelineModel.Record._compareStartTime); |
+ } |
+ this.virtualThreads().forEach(processVirtualThreadEvents.bind(this)); |
+ this._records = topLevelRecords; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ */ |
+ _buildGPUEvents(tracingModel) { |
+ var thread = tracingModel.threadByName('GPU Process', 'CrGpuMain'); |
+ if (!thread) |
+ return; |
+ var gpuEventName = WebInspector.TimelineModel.RecordType.GPUTask; |
+ this._gpuEvents = thread.events().filter(event => event.name === gpuEventName); |
+ } |
+ |
+ /** |
+ * @param {!Array.<!WebInspector.TracingModel.Event>} threadEvents |
+ * @return {!Array.<!WebInspector.TimelineModel.Record>} |
+ */ |
+ _buildTimelineRecordsForThread(threadEvents) { |
+ var recordStack = []; |
+ var topLevelRecords = []; |
+ |
+ for (var i = 0, size = threadEvents.length; i < size; ++i) { |
+ var event = threadEvents[i]; |
+ for (var top = recordStack.peekLast(); top && top._event.endTime <= event.startTime; top = recordStack.peekLast()) |
+ recordStack.pop(); |
+ if (event.phase === WebInspector.TracingModel.Phase.AsyncEnd || |
+ event.phase === WebInspector.TracingModel.Phase.NestableAsyncEnd) |
+ continue; |
+ var parentRecord = recordStack.peekLast(); |
+ // Maintain the back-end logic of old timeline, skip console.time() / console.timeEnd() that are not properly nested. |
+ if (WebInspector.TracingModel.isAsyncBeginPhase(event.phase) && parentRecord && |
+ event.endTime > parentRecord._event.endTime) |
+ continue; |
+ var record = new WebInspector.TimelineModel.Record(event); |
+ if (WebInspector.TimelineModel.isMarkerEvent(event)) |
+ this._eventDividerRecords.push(record); |
+ if (!this._eventFilter.accept(event) && !WebInspector.TracingModel.isTopLevelEvent(event)) |
+ continue; |
+ if (parentRecord) |
+ parentRecord._addChild(record); |
+ else |
+ topLevelRecords.push(record); |
+ if (event.endTime) |
+ recordStack.push(record); |
+ } |
- if (!cpuProfile) { |
- cpuProfileEvent = events.find(e => e.name === WebInspector.TimelineModel.RecordType.Profile); |
- if (!cpuProfileEvent) |
- return null; |
- var profileGroup = tracingModel.profileGroup(cpuProfileEvent.id); |
- if (!profileGroup) { |
- WebInspector.console.error("Invalid CPU profile format."); |
- return null; |
- } |
- cpuProfile = /** @type {!ProfilerAgent.Profile} */ ({ |
- startTime: cpuProfileEvent.args["data"]["startTime"], |
- endTime: 0, |
- nodes: [], |
- samples: [], |
- timeDeltas: [] |
- }); |
- for (var profileEvent of profileGroup.children) { |
- var eventData = profileEvent.args["data"]; |
- if ("startTime" in eventData) |
- cpuProfile.startTime = eventData["startTime"]; |
- if ("endTime" in eventData) |
- cpuProfile.endTime = eventData["endTime"]; |
- var nodesAndSamples = eventData["cpuProfile"] || {}; |
- cpuProfile.nodes.pushAll(nodesAndSamples["nodes"] || []); |
- cpuProfile.samples.pushAll(nodesAndSamples["samples"] || []); |
- cpuProfile.timeDeltas.pushAll(eventData["timeDeltas"] || []); |
- if (cpuProfile.samples.length !== cpuProfile.timeDeltas.length) { |
- WebInspector.console.error("Failed to parse CPU profile."); |
- return null; |
- } |
- } |
- if (!cpuProfile.endTime) |
- cpuProfile.endTime = cpuProfile.timeDeltas.reduce((x, y) => x + y, cpuProfile.startTime); |
- } |
+ return topLevelRecords; |
+ } |
+ |
+ _resetProcessingState() { |
+ this._asyncEventTracker = new WebInspector.TimelineAsyncEventTracker(); |
+ this._invalidationTracker = new WebInspector.InvalidationTracker(); |
+ this._layoutInvalidate = {}; |
+ this._lastScheduleStyleRecalculation = {}; |
+ this._paintImageEventByPixelRefId = {}; |
+ this._lastPaintForLayer = {}; |
+ this._lastRecalculateStylesEvent = null; |
+ this._currentScriptEvent = null; |
+ this._eventStack = []; |
+ this._hadCommitLoad = false; |
+ this._firstCompositeLayers = null; |
+ /** @type {!Set<string>} */ |
+ this._knownInputEvents = new Set(); |
+ this._currentPage = null; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ * @param {!WebInspector.TracingModel.Thread} thread |
+ * @return {?WebInspector.CPUProfileDataModel} |
+ */ |
+ _extractCpuProfile(tracingModel, thread) { |
+ var events = thread.events(); |
+ var cpuProfile; |
+ |
+ // Check for legacy CpuProfile event format first. |
+ var cpuProfileEvent = events.peekLast(); |
+ if (cpuProfileEvent && cpuProfileEvent.name === WebInspector.TimelineModel.RecordType.CpuProfile) { |
+ var eventData = cpuProfileEvent.args['data']; |
+ cpuProfile = /** @type {?ProfilerAgent.Profile} */ (eventData && eventData['cpuProfile']); |
+ } |
- try { |
- var jsProfileModel = new WebInspector.CPUProfileDataModel(cpuProfile); |
- this._cpuProfiles.push(jsProfileModel); |
- return jsProfileModel; |
- } catch (e) { |
- WebInspector.console.error("Failed to parse CPU profile."); |
- } |
+ if (!cpuProfile) { |
+ cpuProfileEvent = events.find(e => e.name === WebInspector.TimelineModel.RecordType.Profile); |
+ if (!cpuProfileEvent) |
return null; |
- }, |
- |
- /** |
- * @param {!WebInspector.TracingModel} tracingModel |
- * @param {!WebInspector.TracingModel.Thread} thread |
- * @return {!Array<!WebInspector.TracingModel.Event>} |
- */ |
- _injectJSFrameEvents: function(tracingModel, thread) |
- { |
- var jsProfileModel = this._extractCpuProfile(tracingModel, thread); |
- var events = thread.events(); |
- var jsSamples = jsProfileModel ? WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile(jsProfileModel, thread) : null; |
- if (jsSamples && jsSamples.length) |
- events = events.mergeOrdered(jsSamples, WebInspector.TracingModel.Event.orderedCompareStartTime); |
- if (jsSamples || events.some(e => e.name === WebInspector.TimelineModel.RecordType.JSSample)) { |
- var jsFrameEvents = WebInspector.TimelineJSProfileProcessor.generateJSFrameEvents(events); |
- if (jsFrameEvents && jsFrameEvents.length) |
- events = jsFrameEvents.mergeOrdered(events, WebInspector.TracingModel.Event.orderedCompareStartTime); |
+ var profileGroup = tracingModel.profileGroup(cpuProfileEvent.id); |
+ if (!profileGroup) { |
+ WebInspector.console.error('Invalid CPU profile format.'); |
+ return null; |
+ } |
+ cpuProfile = /** @type {!ProfilerAgent.Profile} */ ( |
+ {startTime: cpuProfileEvent.args['data']['startTime'], endTime: 0, nodes: [], samples: [], timeDeltas: []}); |
+ for (var profileEvent of profileGroup.children) { |
+ var eventData = profileEvent.args['data']; |
+ if ('startTime' in eventData) |
+ cpuProfile.startTime = eventData['startTime']; |
+ if ('endTime' in eventData) |
+ cpuProfile.endTime = eventData['endTime']; |
+ var nodesAndSamples = eventData['cpuProfile'] || {}; |
+ cpuProfile.nodes.pushAll(nodesAndSamples['nodes'] || []); |
+ cpuProfile.samples.pushAll(nodesAndSamples['samples'] || []); |
+ cpuProfile.timeDeltas.pushAll(eventData['timeDeltas'] || []); |
+ if (cpuProfile.samples.length !== cpuProfile.timeDeltas.length) { |
+ WebInspector.console.error('Failed to parse CPU profile.'); |
+ return null; |
} |
- return events; |
- }, |
+ } |
+ if (!cpuProfile.endTime) |
+ cpuProfile.endTime = cpuProfile.timeDeltas.reduce((x, y) => x + y, cpuProfile.startTime); |
+ } |
- /** |
- * @param {!WebInspector.TracingModel} tracingModel |
- * @param {number} startTime |
- * @param {number} endTime |
- * @param {!WebInspector.TracingModel.Thread} thread |
- * @param {boolean} isMainThread |
- */ |
- _processThreadEvents: function(tracingModel, startTime, endTime, thread, isMainThread) |
- { |
- var events = this._injectJSFrameEvents(tracingModel, thread); |
- var asyncEvents = thread.asyncEvents(); |
- |
- var threadEvents; |
- var threadAsyncEventsByGroup; |
- if (isMainThread) { |
- threadEvents = this._mainThreadEvents; |
- threadAsyncEventsByGroup = this._mainThreadAsyncEventsByGroup; |
- } else { |
- var virtualThread = new WebInspector.TimelineModel.VirtualThread(thread.name()); |
- this._virtualThreads.push(virtualThread); |
- threadEvents = virtualThread.events; |
- threadAsyncEventsByGroup = virtualThread.asyncEventsByGroup; |
- } |
+ try { |
+ var jsProfileModel = new WebInspector.CPUProfileDataModel(cpuProfile); |
+ this._cpuProfiles.push(jsProfileModel); |
+ return jsProfileModel; |
+ } catch (e) { |
+ WebInspector.console.error('Failed to parse CPU profile.'); |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ * @param {!WebInspector.TracingModel.Thread} thread |
+ * @return {!Array<!WebInspector.TracingModel.Event>} |
+ */ |
+ _injectJSFrameEvents(tracingModel, thread) { |
+ var jsProfileModel = this._extractCpuProfile(tracingModel, thread); |
+ var events = thread.events(); |
+ var jsSamples = jsProfileModel ? |
+ WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile(jsProfileModel, thread) : |
+ null; |
+ if (jsSamples && jsSamples.length) |
+ events = events.mergeOrdered(jsSamples, WebInspector.TracingModel.Event.orderedCompareStartTime); |
+ if (jsSamples || events.some(e => e.name === WebInspector.TimelineModel.RecordType.JSSample)) { |
+ var jsFrameEvents = WebInspector.TimelineJSProfileProcessor.generateJSFrameEvents(events); |
+ if (jsFrameEvents && jsFrameEvents.length) |
+ events = jsFrameEvents.mergeOrdered(events, WebInspector.TracingModel.Event.orderedCompareStartTime); |
+ } |
+ return events; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel} tracingModel |
+ * @param {number} startTime |
+ * @param {number} endTime |
+ * @param {!WebInspector.TracingModel.Thread} thread |
+ * @param {boolean} isMainThread |
+ */ |
+ _processThreadEvents(tracingModel, startTime, endTime, thread, isMainThread) { |
+ var events = this._injectJSFrameEvents(tracingModel, thread); |
+ var asyncEvents = thread.asyncEvents(); |
+ |
+ var threadEvents; |
+ var threadAsyncEventsByGroup; |
+ if (isMainThread) { |
+ threadEvents = this._mainThreadEvents; |
+ threadAsyncEventsByGroup = this._mainThreadAsyncEventsByGroup; |
+ } else { |
+ var virtualThread = new WebInspector.TimelineModel.VirtualThread(thread.name()); |
+ this._virtualThreads.push(virtualThread); |
+ threadEvents = virtualThread.events; |
+ threadAsyncEventsByGroup = virtualThread.asyncEventsByGroup; |
+ } |
- this._eventStack = []; |
- var i = events.lowerBound(startTime, (time, event) => time - event.startTime); |
- var length = events.length; |
- for (; i < length; i++) { |
- var event = events[i]; |
- if (endTime && event.startTime >= endTime) |
- break; |
- if (!this._processEvent(event)) |
- continue; |
- threadEvents.push(event); |
- this._inspectedTargetEvents.push(event); |
- } |
- this._processAsyncEvents(threadAsyncEventsByGroup, asyncEvents, startTime, endTime); |
- // Pretend the compositor's async events are on the main thread. |
- if (thread.name() === "Compositor") { |
- this._mergeAsyncEvents(this._mainThreadAsyncEventsByGroup, threadAsyncEventsByGroup); |
- threadAsyncEventsByGroup.clear(); |
- } |
- }, |
+ this._eventStack = []; |
+ var i = events.lowerBound(startTime, (time, event) => time - event.startTime); |
+ var length = events.length; |
+ for (; i < length; i++) { |
+ var event = events[i]; |
+ if (endTime && event.startTime >= endTime) |
+ break; |
+ if (!this._processEvent(event)) |
+ continue; |
+ threadEvents.push(event); |
+ this._inspectedTargetEvents.push(event); |
+ } |
+ this._processAsyncEvents(threadAsyncEventsByGroup, asyncEvents, startTime, endTime); |
+ // Pretend the compositor's async events are on the main thread. |
+ if (thread.name() === 'Compositor') { |
+ this._mergeAsyncEvents(this._mainThreadAsyncEventsByGroup, threadAsyncEventsByGroup); |
+ threadAsyncEventsByGroup.clear(); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} asyncEventsByGroup |
+ * @param {!Array<!WebInspector.TracingModel.AsyncEvent>} asyncEvents |
+ * @param {number=} startTime |
+ * @param {number=} endTime |
+ */ |
+ _processAsyncEvents(asyncEventsByGroup, asyncEvents, startTime, endTime) { |
+ var i = startTime ? asyncEvents.lowerBound(startTime, function(time, asyncEvent) { |
+ return time - asyncEvent.startTime; |
+ }) : 0; |
+ for (; i < asyncEvents.length; ++i) { |
+ var asyncEvent = asyncEvents[i]; |
+ if (endTime && asyncEvent.startTime >= endTime) |
+ break; |
+ var asyncGroup = this._processAsyncEvent(asyncEvent); |
+ if (!asyncGroup) |
+ continue; |
+ var groupAsyncEvents = asyncEventsByGroup.get(asyncGroup); |
+ if (!groupAsyncEvents) { |
+ groupAsyncEvents = []; |
+ asyncEventsByGroup.set(asyncGroup, groupAsyncEvents); |
+ } |
+ groupAsyncEvents.push(asyncEvent); |
+ } |
+ } |
- /** |
- * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} asyncEventsByGroup |
- * @param {!Array<!WebInspector.TracingModel.AsyncEvent>} asyncEvents |
- * @param {number=} startTime |
- * @param {number=} endTime |
- */ |
- _processAsyncEvents: function(asyncEventsByGroup, asyncEvents, startTime, endTime) |
- { |
- var i = startTime ? asyncEvents.lowerBound(startTime, function(time, asyncEvent) { return time - asyncEvent.startTime; }) : 0; |
- for (; i < asyncEvents.length; ++i) { |
- var asyncEvent = asyncEvents[i]; |
- if (endTime && asyncEvent.startTime >= endTime) |
- break; |
- var asyncGroup = this._processAsyncEvent(asyncEvent); |
- if (!asyncGroup) |
- continue; |
- var groupAsyncEvents = asyncEventsByGroup.get(asyncGroup); |
- if (!groupAsyncEvents) { |
- groupAsyncEvents = []; |
- asyncEventsByGroup.set(asyncGroup, groupAsyncEvents); |
- } |
- groupAsyncEvents.push(asyncEvent); |
- } |
- }, |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ _processEvent(event) { |
+ var eventStack = this._eventStack; |
+ while (eventStack.length && eventStack.peekLast().endTime <= event.startTime) |
+ eventStack.pop(); |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- _processEvent: function(event) |
- { |
- var eventStack = this._eventStack; |
- while (eventStack.length && eventStack.peekLast().endTime <= event.startTime) |
- eventStack.pop(); |
- |
- var recordTypes = WebInspector.TimelineModel.RecordType; |
- |
- if (this._currentScriptEvent && event.startTime > this._currentScriptEvent.endTime) |
- this._currentScriptEvent = null; |
- |
- var eventData = event.args["data"] || event.args["beginData"] || {}; |
- if (eventData["stackTrace"]) |
- event.stackTrace = eventData["stackTrace"]; |
- if (event.stackTrace && event.name !== recordTypes.JSSample) { |
- // TraceEvents come with 1-based line & column numbers. The frontend code |
- // requires 0-based ones. Adjust the values. |
- for (var i = 0; i < event.stackTrace.length; ++i) { |
- --event.stackTrace[i].lineNumber; |
- --event.stackTrace[i].columnNumber; |
- } |
- } |
+ var recordTypes = WebInspector.TimelineModel.RecordType; |
+ |
+ if (this._currentScriptEvent && event.startTime > this._currentScriptEvent.endTime) |
+ this._currentScriptEvent = null; |
+ |
+ var eventData = event.args['data'] || event.args['beginData'] || {}; |
+ if (eventData['stackTrace']) |
+ event.stackTrace = eventData['stackTrace']; |
+ if (event.stackTrace && event.name !== recordTypes.JSSample) { |
+ // TraceEvents come with 1-based line & column numbers. The frontend code |
+ // requires 0-based ones. Adjust the values. |
+ for (var i = 0; i < event.stackTrace.length; ++i) { |
+ --event.stackTrace[i].lineNumber; |
+ --event.stackTrace[i].columnNumber; |
+ } |
+ } |
- if (eventStack.length && eventStack.peekLast().name === recordTypes.EventDispatch) |
- eventStack.peekLast().hasChildren = true; |
- this._asyncEventTracker.processEvent(event); |
- if (event.initiator && event.initiator.url) |
- event.url = event.initiator.url; |
- switch (event.name) { |
- case recordTypes.ResourceSendRequest: |
- case recordTypes.WebSocketCreate: |
- event.url = eventData["url"]; |
- event.initiator = eventStack.peekLast() || null; |
- break; |
- |
- case recordTypes.ScheduleStyleRecalculation: |
- this._lastScheduleStyleRecalculation[eventData["frame"]] = event; |
- break; |
- |
- case recordTypes.UpdateLayoutTree: |
- case recordTypes.RecalculateStyles: |
- this._invalidationTracker.didRecalcStyle(event); |
- if (event.args["beginData"]) |
- event.initiator = this._lastScheduleStyleRecalculation[event.args["beginData"]["frame"]]; |
- this._lastRecalculateStylesEvent = event; |
- if (this._currentScriptEvent) |
- event.warning = WebInspector.TimelineModel.WarningType.ForcedStyle; |
- break; |
- |
- case recordTypes.ScheduleStyleInvalidationTracking: |
- case recordTypes.StyleRecalcInvalidationTracking: |
- case recordTypes.StyleInvalidatorInvalidationTracking: |
- case recordTypes.LayoutInvalidationTracking: |
- case recordTypes.LayerInvalidationTracking: |
- case recordTypes.PaintInvalidationTracking: |
- case recordTypes.ScrollInvalidationTracking: |
- this._invalidationTracker.addInvalidation(new WebInspector.InvalidationTrackingEvent(event)); |
- break; |
- |
- case recordTypes.InvalidateLayout: |
- // Consider style recalculation as a reason for layout invalidation, |
- // but only if we had no earlier layout invalidation records. |
- var layoutInitator = event; |
- var frameId = eventData["frame"]; |
- if (!this._layoutInvalidate[frameId] && this._lastRecalculateStylesEvent && this._lastRecalculateStylesEvent.endTime > event.startTime) |
- layoutInitator = this._lastRecalculateStylesEvent.initiator; |
- this._layoutInvalidate[frameId] = layoutInitator; |
- break; |
- |
- case recordTypes.Layout: |
- this._invalidationTracker.didLayout(event); |
- var frameId = event.args["beginData"]["frame"]; |
- event.initiator = this._layoutInvalidate[frameId]; |
- // In case we have no closing Layout event, endData is not available. |
- if (event.args["endData"]) { |
- event.backendNodeId = event.args["endData"]["rootNode"]; |
- event.highlightQuad = event.args["endData"]["root"]; |
- } |
- this._layoutInvalidate[frameId] = null; |
- if (this._currentScriptEvent) |
- event.warning = WebInspector.TimelineModel.WarningType.ForcedLayout; |
- break; |
- |
- case recordTypes.FunctionCall: |
- // Compatibility with old format. |
- if (typeof eventData["scriptName"] === "string") |
- eventData["url"] = eventData["scriptName"]; |
- if (typeof eventData["scriptLine"] === "number") |
- eventData["lineNumber"] = eventData["scriptLine"]; |
- // Fallthrough. |
- case recordTypes.EvaluateScript: |
- case recordTypes.CompileScript: |
- if (typeof eventData["lineNumber"] === "number") |
- --eventData["lineNumber"]; |
- if (typeof eventData["columnNumber"] === "number") |
- --eventData["columnNumber"]; |
- // Fallthrough intended. |
- case recordTypes.RunMicrotasks: |
- // Microtasks technically are not necessarily scripts, but for purpose of |
- // forced sync style recalc or layout detection they are. |
- if (!this._currentScriptEvent) |
- this._currentScriptEvent = event; |
- break; |
- |
- case recordTypes.SetLayerTreeId: |
- this._inspectedTargetLayerTreeId = event.args["layerTreeId"] || event.args["data"]["layerTreeId"]; |
- break; |
- |
- case recordTypes.Paint: |
- this._invalidationTracker.didPaint(event); |
- event.highlightQuad = eventData["clip"]; |
- event.backendNodeId = eventData["nodeId"]; |
- // Only keep layer paint events, skip paints for subframes that get painted to the same layer as parent. |
- if (!eventData["layerId"]) |
- break; |
- var layerId = eventData["layerId"]; |
- this._lastPaintForLayer[layerId] = event; |
- break; |
- |
- case recordTypes.DisplayItemListSnapshot: |
- case recordTypes.PictureSnapshot: |
- var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer); |
- if (!layerUpdateEvent || layerUpdateEvent.args["layerTreeId"] !== this._inspectedTargetLayerTreeId) |
- break; |
- var paintEvent = this._lastPaintForLayer[layerUpdateEvent.args["layerId"]]; |
- if (paintEvent) |
- paintEvent.picture = event; |
- break; |
- |
- case recordTypes.ScrollLayer: |
- event.backendNodeId = eventData["nodeId"]; |
- break; |
- |
- case recordTypes.PaintImage: |
- event.backendNodeId = eventData["nodeId"]; |
- event.url = eventData["url"]; |
- break; |
- |
- case recordTypes.DecodeImage: |
- case recordTypes.ResizeImage: |
- var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage); |
- if (!paintImageEvent) { |
- var decodeLazyPixelRefEvent = this._findAncestorEvent(recordTypes.DecodeLazyPixelRef); |
- paintImageEvent = decodeLazyPixelRefEvent && this._paintImageEventByPixelRefId[decodeLazyPixelRefEvent.args["LazyPixelRef"]]; |
- } |
- if (!paintImageEvent) |
- break; |
- event.backendNodeId = paintImageEvent.backendNodeId; |
- event.url = paintImageEvent.url; |
- break; |
- |
- case recordTypes.DrawLazyPixelRef: |
- var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage); |
- if (!paintImageEvent) |
- break; |
- this._paintImageEventByPixelRefId[event.args["LazyPixelRef"]] = paintImageEvent; |
- event.backendNodeId = paintImageEvent.backendNodeId; |
- event.url = paintImageEvent.url; |
- break; |
- |
- case recordTypes.MarkDOMContent: |
- case recordTypes.MarkLoad: |
- var page = eventData["page"]; |
- if (page && page !== this._currentPage) |
- return false; |
- break; |
- |
- case recordTypes.CommitLoad: |
- var page = eventData["page"]; |
- if (page && page !== this._currentPage) |
- return false; |
- if (!eventData["isMainFrame"]) |
- break; |
- this._hadCommitLoad = true; |
- this._firstCompositeLayers = null; |
- break; |
- |
- case recordTypes.CompositeLayers: |
- if (!this._firstCompositeLayers && this._hadCommitLoad) |
- this._firstCompositeLayers = event; |
- break; |
- |
- case recordTypes.FireIdleCallback: |
- if (event.duration > eventData["allottedMilliseconds"]) { |
- event.warning = WebInspector.TimelineModel.WarningType.IdleDeadlineExceeded; |
- } |
- break; |
+ if (eventStack.length && eventStack.peekLast().name === recordTypes.EventDispatch) |
+ eventStack.peekLast().hasChildren = true; |
+ this._asyncEventTracker.processEvent(event); |
+ if (event.initiator && event.initiator.url) |
+ event.url = event.initiator.url; |
+ switch (event.name) { |
+ case recordTypes.ResourceSendRequest: |
+ case recordTypes.WebSocketCreate: |
+ event.url = eventData['url']; |
+ event.initiator = eventStack.peekLast() || null; |
+ break; |
+ |
+ case recordTypes.ScheduleStyleRecalculation: |
+ this._lastScheduleStyleRecalculation[eventData['frame']] = event; |
+ break; |
+ |
+ case recordTypes.UpdateLayoutTree: |
+ case recordTypes.RecalculateStyles: |
+ this._invalidationTracker.didRecalcStyle(event); |
+ if (event.args['beginData']) |
+ event.initiator = this._lastScheduleStyleRecalculation[event.args['beginData']['frame']]; |
+ this._lastRecalculateStylesEvent = event; |
+ if (this._currentScriptEvent) |
+ event.warning = WebInspector.TimelineModel.WarningType.ForcedStyle; |
+ break; |
+ |
+ case recordTypes.ScheduleStyleInvalidationTracking: |
+ case recordTypes.StyleRecalcInvalidationTracking: |
+ case recordTypes.StyleInvalidatorInvalidationTracking: |
+ case recordTypes.LayoutInvalidationTracking: |
+ case recordTypes.LayerInvalidationTracking: |
+ case recordTypes.PaintInvalidationTracking: |
+ case recordTypes.ScrollInvalidationTracking: |
+ this._invalidationTracker.addInvalidation(new WebInspector.InvalidationTrackingEvent(event)); |
+ break; |
+ |
+ case recordTypes.InvalidateLayout: |
+ // Consider style recalculation as a reason for layout invalidation, |
+ // but only if we had no earlier layout invalidation records. |
+ var layoutInitator = event; |
+ var frameId = eventData['frame']; |
+ if (!this._layoutInvalidate[frameId] && this._lastRecalculateStylesEvent && |
+ this._lastRecalculateStylesEvent.endTime > event.startTime) |
+ layoutInitator = this._lastRecalculateStylesEvent.initiator; |
+ this._layoutInvalidate[frameId] = layoutInitator; |
+ break; |
+ |
+ case recordTypes.Layout: |
+ this._invalidationTracker.didLayout(event); |
+ var frameId = event.args['beginData']['frame']; |
+ event.initiator = this._layoutInvalidate[frameId]; |
+ // In case we have no closing Layout event, endData is not available. |
+ if (event.args['endData']) { |
+ event.backendNodeId = event.args['endData']['rootNode']; |
+ event.highlightQuad = event.args['endData']['root']; |
} |
- if (WebInspector.TracingModel.isAsyncPhase(event.phase)) |
- return true; |
- var duration = event.duration; |
- if (!duration) |
- return true; |
- if (eventStack.length) { |
- var parent = eventStack.peekLast(); |
- parent.selfTime -= duration; |
- if (parent.selfTime < 0) { |
- var epsilon = 1e-3; |
- if (parent.selfTime < -epsilon) |
- console.error("Children are longer than parent at " + event.startTime + " (" + (event.startTime - this.minimumRecordTime()).toFixed(3) + ") by " + parent.selfTime.toFixed(3)); |
- parent.selfTime = 0; |
- } |
+ this._layoutInvalidate[frameId] = null; |
+ if (this._currentScriptEvent) |
+ event.warning = WebInspector.TimelineModel.WarningType.ForcedLayout; |
+ break; |
+ |
+ case recordTypes.FunctionCall: |
+ // Compatibility with old format. |
+ if (typeof eventData['scriptName'] === 'string') |
+ eventData['url'] = eventData['scriptName']; |
+ if (typeof eventData['scriptLine'] === 'number') |
+ eventData['lineNumber'] = eventData['scriptLine']; |
+ // Fallthrough. |
+ case recordTypes.EvaluateScript: |
+ case recordTypes.CompileScript: |
+ if (typeof eventData['lineNumber'] === 'number') |
+ --eventData['lineNumber']; |
+ if (typeof eventData['columnNumber'] === 'number') |
+ --eventData['columnNumber']; |
+ // Fallthrough intended. |
+ case recordTypes.RunMicrotasks: |
+ // Microtasks technically are not necessarily scripts, but for purpose of |
+ // forced sync style recalc or layout detection they are. |
+ if (!this._currentScriptEvent) |
+ this._currentScriptEvent = event; |
+ break; |
+ |
+ case recordTypes.SetLayerTreeId: |
+ this._inspectedTargetLayerTreeId = event.args['layerTreeId'] || event.args['data']['layerTreeId']; |
+ break; |
+ |
+ case recordTypes.Paint: |
+ this._invalidationTracker.didPaint(event); |
+ event.highlightQuad = eventData['clip']; |
+ event.backendNodeId = eventData['nodeId']; |
+ // Only keep layer paint events, skip paints for subframes that get painted to the same layer as parent. |
+ if (!eventData['layerId']) |
+ break; |
+ var layerId = eventData['layerId']; |
+ this._lastPaintForLayer[layerId] = event; |
+ break; |
+ |
+ case recordTypes.DisplayItemListSnapshot: |
+ case recordTypes.PictureSnapshot: |
+ var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer); |
+ if (!layerUpdateEvent || layerUpdateEvent.args['layerTreeId'] !== this._inspectedTargetLayerTreeId) |
+ break; |
+ var paintEvent = this._lastPaintForLayer[layerUpdateEvent.args['layerId']]; |
+ if (paintEvent) |
+ paintEvent.picture = event; |
+ break; |
+ |
+ case recordTypes.ScrollLayer: |
+ event.backendNodeId = eventData['nodeId']; |
+ break; |
+ |
+ case recordTypes.PaintImage: |
+ event.backendNodeId = eventData['nodeId']; |
+ event.url = eventData['url']; |
+ break; |
+ |
+ case recordTypes.DecodeImage: |
+ case recordTypes.ResizeImage: |
+ var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage); |
+ if (!paintImageEvent) { |
+ var decodeLazyPixelRefEvent = this._findAncestorEvent(recordTypes.DecodeLazyPixelRef); |
+ paintImageEvent = decodeLazyPixelRefEvent && |
+ this._paintImageEventByPixelRefId[decodeLazyPixelRefEvent.args['LazyPixelRef']]; |
} |
- event.selfTime = duration; |
- eventStack.push(event); |
- return true; |
- }, |
+ if (!paintImageEvent) |
+ break; |
+ event.backendNodeId = paintImageEvent.backendNodeId; |
+ event.url = paintImageEvent.url; |
+ break; |
+ |
+ case recordTypes.DrawLazyPixelRef: |
+ var paintImageEvent = this._findAncestorEvent(recordTypes.PaintImage); |
+ if (!paintImageEvent) |
+ break; |
+ this._paintImageEventByPixelRefId[event.args['LazyPixelRef']] = paintImageEvent; |
+ event.backendNodeId = paintImageEvent.backendNodeId; |
+ event.url = paintImageEvent.url; |
+ break; |
+ |
+ case recordTypes.MarkDOMContent: |
+ case recordTypes.MarkLoad: |
+ var page = eventData['page']; |
+ if (page && page !== this._currentPage) |
+ return false; |
+ break; |
+ |
+ case recordTypes.CommitLoad: |
+ var page = eventData['page']; |
+ if (page && page !== this._currentPage) |
+ return false; |
+ if (!eventData['isMainFrame']) |
+ break; |
+ this._hadCommitLoad = true; |
+ this._firstCompositeLayers = null; |
+ break; |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- */ |
- _processBrowserEvent: function(event) |
- { |
- if (event.name !== WebInspector.TimelineModel.RecordType.LatencyInfoFlow) |
- return; |
- var frameId = event.args["frameTreeNodeId"]; |
- if (typeof frameId === "number" && frameId === this._mainFrameNodeId) |
- this._knownInputEvents.add(event.bind_id); |
- }, |
+ case recordTypes.CompositeLayers: |
+ if (!this._firstCompositeLayers && this._hadCommitLoad) |
+ this._firstCompositeLayers = event; |
+ break; |
- /** |
- * @param {!WebInspector.TracingModel.AsyncEvent} asyncEvent |
- * @return {?WebInspector.TimelineModel.AsyncEventGroup} |
- */ |
- _processAsyncEvent: function(asyncEvent) |
- { |
- var groups = WebInspector.TimelineModel.AsyncEventGroup; |
- if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.Console)) |
- return groups.console; |
- if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.UserTiming)) |
- return groups.userTiming; |
- if (asyncEvent.name === WebInspector.TimelineModel.RecordType.Animation) |
- return groups.animation; |
- if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo) || asyncEvent.name === WebInspector.TimelineModel.RecordType.ImplSideFling) { |
- var lastStep = asyncEvent.steps.peekLast(); |
- // FIXME: fix event termination on the back-end instead. |
- if (lastStep.phase !== WebInspector.TracingModel.Phase.AsyncEnd) |
- return null; |
- var data = lastStep.args["data"]; |
- asyncEvent.causedFrame = !!(data && data["INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT"]); |
- if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo)) { |
- if (!this._knownInputEvents.has(lastStep.id)) |
- return null; |
- if (asyncEvent.name === WebInspector.TimelineModel.RecordType.InputLatencyMouseMove && !asyncEvent.causedFrame) |
- return null; |
- var rendererMain = data["INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT"]; |
- if (rendererMain) { |
- var time = rendererMain["time"] / 1000; |
- asyncEvent.steps[0].timeWaitingForMainThread = time - asyncEvent.steps[0].startTime; |
- } |
- } |
- return groups.input; |
- } |
- return null; |
- }, |
- |
- /** |
- * @param {string} name |
- * @return {?WebInspector.TracingModel.Event} |
- */ |
- _findAncestorEvent: function(name) |
- { |
- for (var i = this._eventStack.length - 1; i >= 0; --i) { |
- var event = this._eventStack[i]; |
- if (event.name === name) |
- return event; |
+ case recordTypes.FireIdleCallback: |
+ if (event.duration > eventData['allottedMilliseconds']) { |
+ event.warning = WebInspector.TimelineModel.WarningType.IdleDeadlineExceeded; |
} |
+ break; |
+ } |
+ if (WebInspector.TracingModel.isAsyncPhase(event.phase)) |
+ return true; |
+ var duration = event.duration; |
+ if (!duration) |
+ return true; |
+ if (eventStack.length) { |
+ var parent = eventStack.peekLast(); |
+ parent.selfTime -= duration; |
+ if (parent.selfTime < 0) { |
+ var epsilon = 1e-3; |
+ if (parent.selfTime < -epsilon) |
+ console.error( |
+ 'Children are longer than parent at ' + event.startTime + ' (' + |
+ (event.startTime - this.minimumRecordTime()).toFixed(3) + ') by ' + parent.selfTime.toFixed(3)); |
+ parent.selfTime = 0; |
+ } |
+ } |
+ event.selfTime = duration; |
+ eventStack.push(event); |
+ return true; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ */ |
+ _processBrowserEvent(event) { |
+ if (event.name !== WebInspector.TimelineModel.RecordType.LatencyInfoFlow) |
+ return; |
+ var frameId = event.args['frameTreeNodeId']; |
+ if (typeof frameId === 'number' && frameId === this._mainFrameNodeId) |
+ this._knownInputEvents.add(event.bind_id); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.AsyncEvent} asyncEvent |
+ * @return {?WebInspector.TimelineModel.AsyncEventGroup} |
+ */ |
+ _processAsyncEvent(asyncEvent) { |
+ var groups = WebInspector.TimelineModel.AsyncEventGroup; |
+ if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.Console)) |
+ return groups.console; |
+ if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.UserTiming)) |
+ return groups.userTiming; |
+ if (asyncEvent.name === WebInspector.TimelineModel.RecordType.Animation) |
+ return groups.animation; |
+ if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo) || |
+ asyncEvent.name === WebInspector.TimelineModel.RecordType.ImplSideFling) { |
+ var lastStep = asyncEvent.steps.peekLast(); |
+ // FIXME: fix event termination on the back-end instead. |
+ if (lastStep.phase !== WebInspector.TracingModel.Phase.AsyncEnd) |
return null; |
- }, |
- |
- /** |
- * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} target |
- * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} source |
- */ |
- _mergeAsyncEvents: function(target, source) |
- { |
- for (var group of source.keys()) { |
- var events = target.get(group) || []; |
- events = events.mergeOrdered(source.get(group) || [], WebInspector.TracingModel.Event.compareStartAndEndTime); |
- target.set(group, events); |
+ var data = lastStep.args['data']; |
+ asyncEvent.causedFrame = !!(data && data['INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT']); |
+ if (asyncEvent.hasCategory(WebInspector.TimelineModel.Category.LatencyInfo)) { |
+ if (!this._knownInputEvents.has(lastStep.id)) |
+ return null; |
+ if (asyncEvent.name === WebInspector.TimelineModel.RecordType.InputLatencyMouseMove && !asyncEvent.causedFrame) |
+ return null; |
+ var rendererMain = data['INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT']; |
+ if (rendererMain) { |
+ var time = rendererMain['time'] / 1000; |
+ asyncEvent.steps[0].timeWaitingForMainThread = time - asyncEvent.steps[0].startTime; |
} |
- }, |
- |
- reset: function() |
- { |
- this._virtualThreads = []; |
- /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
- this._mainThreadEvents = []; |
- /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */ |
- this._mainThreadAsyncEventsByGroup = new Map(); |
- /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
- this._inspectedTargetEvents = []; |
- /** @type {!Array<!WebInspector.TimelineModel.Record>} */ |
- this._records = []; |
- /** @type {!Array<!WebInspector.TimelineModel.Record>} */ |
- this._mainThreadTasks = []; |
- /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
- this._gpuEvents = []; |
- /** @type {!Array<!WebInspector.TimelineModel.Record>} */ |
- this._eventDividerRecords = []; |
- /** @type {?string} */ |
- this._sessionId = null; |
- /** @type {?number} */ |
- this._mainFrameNodeId = null; |
- /** @type {!Array<!WebInspector.CPUProfileDataModel>} */ |
- this._cpuProfiles = []; |
- /** @type {!WeakMap<!WebInspector.TracingModel.Thread, string>} */ |
- this._workerIdByThread = new WeakMap(); |
- this._minimumRecordTime = 0; |
- this._maximumRecordTime = 0; |
- }, |
- |
- /** |
- * @return {number} |
- */ |
- minimumRecordTime: function() |
- { |
- return this._minimumRecordTime; |
- }, |
- |
- /** |
- * @return {number} |
- */ |
- maximumRecordTime: function() |
- { |
- return this._maximumRecordTime; |
- }, |
- |
- /** |
- * @return {!Array.<!WebInspector.TracingModel.Event>} |
- */ |
- inspectedTargetEvents: function() |
- { |
- return this._inspectedTargetEvents; |
- }, |
- |
- /** |
- * @return {!Array.<!WebInspector.TracingModel.Event>} |
- */ |
- mainThreadEvents: function() |
- { |
- return this._mainThreadEvents; |
- }, |
+ } |
+ return groups.input; |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * @param {string} name |
+ * @return {?WebInspector.TracingModel.Event} |
+ */ |
+ _findAncestorEvent(name) { |
+ for (var i = this._eventStack.length - 1; i >= 0; --i) { |
+ var event = this._eventStack[i]; |
+ if (event.name === name) |
+ return event; |
+ } |
+ return null; |
+ } |
+ |
+ /** |
+ * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} target |
+ * @param {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} source |
+ */ |
+ _mergeAsyncEvents(target, source) { |
+ for (var group of source.keys()) { |
+ var events = target.get(group) || []; |
+ events = events.mergeOrdered(source.get(group) || [], WebInspector.TracingModel.Event.compareStartAndEndTime); |
+ target.set(group, events); |
+ } |
+ } |
- /** |
- * @param {!Array.<!WebInspector.TracingModel.Event>} events |
- */ |
- _setMainThreadEvents: function(events) |
- { |
- this._mainThreadEvents = events; |
- }, |
+ reset() { |
+ this._virtualThreads = []; |
+ /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
+ this._mainThreadEvents = []; |
+ /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */ |
+ this._mainThreadAsyncEventsByGroup = new Map(); |
+ /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
+ this._inspectedTargetEvents = []; |
+ /** @type {!Array<!WebInspector.TimelineModel.Record>} */ |
+ this._records = []; |
+ /** @type {!Array<!WebInspector.TimelineModel.Record>} */ |
+ this._mainThreadTasks = []; |
+ /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
+ this._gpuEvents = []; |
+ /** @type {!Array<!WebInspector.TimelineModel.Record>} */ |
+ this._eventDividerRecords = []; |
+ /** @type {?string} */ |
+ this._sessionId = null; |
+ /** @type {?number} */ |
+ this._mainFrameNodeId = null; |
+ /** @type {!Array<!WebInspector.CPUProfileDataModel>} */ |
+ this._cpuProfiles = []; |
+ /** @type {!WeakMap<!WebInspector.TracingModel.Thread, string>} */ |
+ this._workerIdByThread = new WeakMap(); |
+ this._minimumRecordTime = 0; |
+ this._maximumRecordTime = 0; |
+ } |
+ |
+ /** |
+ * @return {number} |
+ */ |
+ minimumRecordTime() { |
+ return this._minimumRecordTime; |
+ } |
+ |
+ /** |
+ * @return {number} |
+ */ |
+ maximumRecordTime() { |
+ return this._maximumRecordTime; |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TracingModel.Event>} |
+ */ |
+ inspectedTargetEvents() { |
+ return this._inspectedTargetEvents; |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TracingModel.Event>} |
+ */ |
+ mainThreadEvents() { |
+ return this._mainThreadEvents; |
+ } |
+ |
+ /** |
+ * @param {!Array.<!WebInspector.TracingModel.Event>} events |
+ */ |
+ _setMainThreadEvents(events) { |
+ this._mainThreadEvents = events; |
+ } |
+ |
+ /** |
+ * @return {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array.<!WebInspector.TracingModel.AsyncEvent>>} |
+ */ |
+ mainThreadAsyncEvents() { |
+ return this._mainThreadAsyncEventsByGroup; |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TimelineModel.VirtualThread>} |
+ */ |
+ virtualThreads() { |
+ return this._virtualThreads; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ isEmpty() { |
+ return this.minimumRecordTime() === 0 && this.maximumRecordTime() === 0; |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TimelineModel.Record>} |
+ */ |
+ mainThreadTasks() { |
+ return this._mainThreadTasks; |
+ } |
+ |
+ /** |
+ * @return {!Array<!WebInspector.TracingModel.Event>} |
+ */ |
+ gpuEvents() { |
+ return this._gpuEvents; |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TimelineModel.Record>} |
+ */ |
+ eventDividerRecords() { |
+ return this._eventDividerRecords; |
+ } |
+ |
+ /** |
+ * @return {!Array<!WebInspector.TimelineModel.NetworkRequest>} |
+ */ |
+ networkRequests() { |
+ /** @type {!Map<string,!WebInspector.TimelineModel.NetworkRequest>} */ |
+ var requests = new Map(); |
+ /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */ |
+ var requestsList = []; |
+ /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */ |
+ var zeroStartRequestsList = []; |
+ var types = WebInspector.TimelineModel.RecordType; |
+ var resourceTypes = new Set( |
+ [types.ResourceSendRequest, types.ResourceReceiveResponse, types.ResourceReceivedData, types.ResourceFinish]); |
+ var events = this.mainThreadEvents(); |
+ for (var i = 0; i < events.length; ++i) { |
+ var e = events[i]; |
+ if (!resourceTypes.has(e.name)) |
+ continue; |
+ var id = e.args['data']['requestId']; |
+ var request = requests.get(id); |
+ if (request) { |
+ request.addEvent(e); |
+ } else { |
+ request = new WebInspector.TimelineModel.NetworkRequest(e); |
+ requests.set(id, request); |
+ if (request.startTime) |
+ requestsList.push(request); |
+ else |
+ zeroStartRequestsList.push(request); |
+ } |
+ } |
+ return zeroStartRequestsList.concat(requestsList); |
+ } |
+}; |
- /** |
- * @return {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array.<!WebInspector.TracingModel.AsyncEvent>>} |
- */ |
- mainThreadAsyncEvents: function() |
- { |
- return this._mainThreadAsyncEventsByGroup; |
- }, |
+/** |
+ * @enum {string} |
+ */ |
+WebInspector.TimelineModel.RecordType = { |
+ Task: 'Task', |
+ Program: 'Program', |
+ EventDispatch: 'EventDispatch', |
+ |
+ GPUTask: 'GPUTask', |
+ |
+ Animation: 'Animation', |
+ RequestMainThreadFrame: 'RequestMainThreadFrame', |
+ BeginFrame: 'BeginFrame', |
+ NeedsBeginFrameChanged: 'NeedsBeginFrameChanged', |
+ BeginMainThreadFrame: 'BeginMainThreadFrame', |
+ ActivateLayerTree: 'ActivateLayerTree', |
+ DrawFrame: 'DrawFrame', |
+ HitTest: 'HitTest', |
+ ScheduleStyleRecalculation: 'ScheduleStyleRecalculation', |
+ RecalculateStyles: 'RecalculateStyles', // For backwards compatibility only, now replaced by UpdateLayoutTree. |
+ UpdateLayoutTree: 'UpdateLayoutTree', |
+ InvalidateLayout: 'InvalidateLayout', |
+ Layout: 'Layout', |
+ UpdateLayer: 'UpdateLayer', |
+ UpdateLayerTree: 'UpdateLayerTree', |
+ PaintSetup: 'PaintSetup', |
+ Paint: 'Paint', |
+ PaintImage: 'PaintImage', |
+ Rasterize: 'Rasterize', |
+ RasterTask: 'RasterTask', |
+ ScrollLayer: 'ScrollLayer', |
+ CompositeLayers: 'CompositeLayers', |
+ |
+ ScheduleStyleInvalidationTracking: 'ScheduleStyleInvalidationTracking', |
+ StyleRecalcInvalidationTracking: 'StyleRecalcInvalidationTracking', |
+ StyleInvalidatorInvalidationTracking: 'StyleInvalidatorInvalidationTracking', |
+ LayoutInvalidationTracking: 'LayoutInvalidationTracking', |
+ LayerInvalidationTracking: 'LayerInvalidationTracking', |
+ PaintInvalidationTracking: 'PaintInvalidationTracking', |
+ ScrollInvalidationTracking: 'ScrollInvalidationTracking', |
+ |
+ ParseHTML: 'ParseHTML', |
+ ParseAuthorStyleSheet: 'ParseAuthorStyleSheet', |
+ |
+ TimerInstall: 'TimerInstall', |
+ TimerRemove: 'TimerRemove', |
+ TimerFire: 'TimerFire', |
+ |
+ XHRReadyStateChange: 'XHRReadyStateChange', |
+ XHRLoad: 'XHRLoad', |
+ CompileScript: 'v8.compile', |
+ EvaluateScript: 'EvaluateScript', |
+ |
+ CommitLoad: 'CommitLoad', |
+ MarkLoad: 'MarkLoad', |
+ MarkDOMContent: 'MarkDOMContent', |
+ MarkFirstPaint: 'MarkFirstPaint', |
+ |
+ TimeStamp: 'TimeStamp', |
+ ConsoleTime: 'ConsoleTime', |
+ UserTiming: 'UserTiming', |
+ |
+ ResourceSendRequest: 'ResourceSendRequest', |
+ ResourceReceiveResponse: 'ResourceReceiveResponse', |
+ ResourceReceivedData: 'ResourceReceivedData', |
+ ResourceFinish: 'ResourceFinish', |
+ |
+ RunMicrotasks: 'RunMicrotasks', |
+ FunctionCall: 'FunctionCall', |
+ GCEvent: 'GCEvent', // For backwards compatibility only, now replaced by MinorGC/MajorGC. |
+ MajorGC: 'MajorGC', |
+ MinorGC: 'MinorGC', |
+ JSFrame: 'JSFrame', |
+ JSSample: 'JSSample', |
+ // V8Sample events are coming from tracing and contain raw stacks with function addresses. |
+ // After being processed with help of JitCodeAdded and JitCodeMoved events they |
+ // get translated into function infos and stored as stacks in JSSample events. |
+ V8Sample: 'V8Sample', |
+ JitCodeAdded: 'JitCodeAdded', |
+ JitCodeMoved: 'JitCodeMoved', |
+ ParseScriptOnBackground: 'v8.parseOnBackground', |
+ |
+ UpdateCounters: 'UpdateCounters', |
+ |
+ RequestAnimationFrame: 'RequestAnimationFrame', |
+ CancelAnimationFrame: 'CancelAnimationFrame', |
+ FireAnimationFrame: 'FireAnimationFrame', |
+ |
+ RequestIdleCallback: 'RequestIdleCallback', |
+ CancelIdleCallback: 'CancelIdleCallback', |
+ FireIdleCallback: 'FireIdleCallback', |
+ |
+ WebSocketCreate: 'WebSocketCreate', |
+ WebSocketSendHandshakeRequest: 'WebSocketSendHandshakeRequest', |
+ WebSocketReceiveHandshakeResponse: 'WebSocketReceiveHandshakeResponse', |
+ WebSocketDestroy: 'WebSocketDestroy', |
+ |
+ EmbedderCallback: 'EmbedderCallback', |
+ |
+ SetLayerTreeId: 'SetLayerTreeId', |
+ TracingStartedInPage: 'TracingStartedInPage', |
+ TracingSessionIdForWorker: 'TracingSessionIdForWorker', |
+ |
+ DecodeImage: 'Decode Image', |
+ ResizeImage: 'Resize Image', |
+ DrawLazyPixelRef: 'Draw LazyPixelRef', |
+ DecodeLazyPixelRef: 'Decode LazyPixelRef', |
+ |
+ LazyPixelRef: 'LazyPixelRef', |
+ LayerTreeHostImplSnapshot: 'cc::LayerTreeHostImpl', |
+ PictureSnapshot: 'cc::Picture', |
+ DisplayItemListSnapshot: 'cc::DisplayItemList', |
+ LatencyInfo: 'LatencyInfo', |
+ LatencyInfoFlow: 'LatencyInfo.Flow', |
+ InputLatencyMouseMove: 'InputLatency::MouseMove', |
+ InputLatencyMouseWheel: 'InputLatency::MouseWheel', |
+ ImplSideFling: 'InputHandlerProxy::HandleGestureFling::started', |
+ GCIdleLazySweep: 'ThreadState::performIdleLazySweep', |
+ GCCompleteSweep: 'ThreadState::completeSweep', |
+ GCCollectGarbage: 'BlinkGCMarking', |
+ |
+ // CpuProfile is a virtual event created on frontend to support |
+ // serialization of CPU Profiles within tracing timeline data. |
+ CpuProfile: 'CpuProfile', |
+ Profile: 'Profile' |
+}; |
- /** |
- * @return {!Array.<!WebInspector.TimelineModel.VirtualThread>} |
- */ |
- virtualThreads: function() |
- { |
- return this._virtualThreads; |
- }, |
+WebInspector.TimelineModel.Category = { |
+ Console: 'blink.console', |
+ UserTiming: 'blink.user_timing', |
+ LatencyInfo: 'latencyInfo' |
+}; |
- /** |
- * @return {boolean} |
- */ |
- isEmpty: function() |
- { |
- return this.minimumRecordTime() === 0 && this.maximumRecordTime() === 0; |
- }, |
+/** |
+ * @enum {string} |
+ */ |
+WebInspector.TimelineModel.WarningType = { |
+ ForcedStyle: 'ForcedStyle', |
+ ForcedLayout: 'ForcedLayout', |
+ IdleDeadlineExceeded: 'IdleDeadlineExceeded', |
+ V8Deopt: 'V8Deopt' |
+}; |
- /** |
- * @return {!Array.<!WebInspector.TimelineModel.Record>} |
- */ |
- mainThreadTasks: function() |
- { |
- return this._mainThreadTasks; |
- }, |
+WebInspector.TimelineModel.MainThreadName = 'main'; |
+WebInspector.TimelineModel.WorkerThreadName = 'DedicatedWorker Thread'; |
+WebInspector.TimelineModel.RendererMainThreadName = 'CrRendererMain'; |
- /** |
- * @return {!Array<!WebInspector.TracingModel.Event>} |
- */ |
- gpuEvents: function() |
- { |
- return this._gpuEvents; |
- }, |
+/** |
+ * @enum {symbol} |
+ */ |
+WebInspector.TimelineModel.AsyncEventGroup = { |
+ animation: Symbol('animation'), |
+ console: Symbol('console'), |
+ userTiming: Symbol('userTiming'), |
+ input: Symbol('input') |
+}; |
- /** |
- * @return {!Array.<!WebInspector.TimelineModel.Record>} |
- */ |
- eventDividerRecords: function() |
- { |
- return this._eventDividerRecords; |
- }, |
- /** |
- * @return {!Array<!WebInspector.TimelineModel.NetworkRequest>} |
- */ |
- networkRequests: function() |
- { |
- /** @type {!Map<string,!WebInspector.TimelineModel.NetworkRequest>} */ |
- var requests = new Map(); |
- /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */ |
- var requestsList = []; |
- /** @type {!Array<!WebInspector.TimelineModel.NetworkRequest>} */ |
- var zeroStartRequestsList = []; |
- var types = WebInspector.TimelineModel.RecordType; |
- var resourceTypes = new Set([ |
- types.ResourceSendRequest, |
- types.ResourceReceiveResponse, |
- types.ResourceReceivedData, |
- types.ResourceFinish |
- ]); |
- var events = this.mainThreadEvents(); |
- for (var i = 0; i < events.length; ++i) { |
- var e = events[i]; |
- if (!resourceTypes.has(e.name)) |
- continue; |
- var id = e.args["data"]["requestId"]; |
- var request = requests.get(id); |
- if (request) { |
- request.addEvent(e); |
- } else { |
- request = new WebInspector.TimelineModel.NetworkRequest(e); |
- requests.set(id, request); |
- if (request.startTime) |
- requestsList.push(request); |
- else |
- zeroStartRequestsList.push(request); |
- } |
- } |
- return zeroStartRequestsList.concat(requestsList); |
- }, |
+WebInspector.TimelineModel.DevToolsMetadataEvent = { |
+ TracingStartedInBrowser: 'TracingStartedInBrowser', |
+ TracingStartedInPage: 'TracingStartedInPage', |
+ TracingSessionIdForWorker: 'TracingSessionIdForWorker', |
}; |
/** |
- * @param {!Array<!WebInspector.TimelineModel.Filter>} filters |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
+ * @unrestricted |
*/ |
-WebInspector.TimelineModel.isVisible = function(filters, event) |
-{ |
- for (var i = 0; i < filters.length; ++i) { |
- if (!filters[i].accept(event)) |
- return false; |
- } |
- return true; |
+WebInspector.TimelineModel.VirtualThread = class { |
+ /** |
+ * @param {string} name |
+ */ |
+ constructor(name) { |
+ this.name = name; |
+ /** @type {!Array<!WebInspector.TracingModel.Event>} */ |
+ this.events = []; |
+ /** @type {!Map<!WebInspector.TimelineModel.AsyncEventGroup, !Array<!WebInspector.TracingModel.AsyncEvent>>} */ |
+ this.asyncEventsByGroup = new Map(); |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ isWorker() { |
+ return this.name === WebInspector.TimelineModel.WorkerThreadName; |
+ } |
}; |
/** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
+ * @unrestricted |
*/ |
-WebInspector.TimelineModel.isMarkerEvent = function(event) |
-{ |
- var recordTypes = WebInspector.TimelineModel.RecordType; |
- switch (event.name) { |
- case recordTypes.TimeStamp: |
- case recordTypes.MarkFirstPaint: |
- return true; |
- case recordTypes.MarkDOMContent: |
- case recordTypes.MarkLoad: |
- return event.args["data"]["isMainFrame"]; |
- default: |
- return false; |
- } |
+WebInspector.TimelineModel.Record = class { |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} traceEvent |
+ */ |
+ constructor(traceEvent) { |
+ this._event = traceEvent; |
+ this._children = []; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TimelineModel.Record} a |
+ * @param {!WebInspector.TimelineModel.Record} b |
+ * @return {number} |
+ */ |
+ static _compareStartTime(a, b) { |
+ // Never return 0 as otherwise equal records would be merged. |
+ return a.startTime() <= b.startTime() ? -1 : 1; |
+ } |
+ |
+ /** |
+ * @return {?WebInspector.Target} |
+ */ |
+ target() { |
+ var threadName = this._event.thread.name(); |
+ // FIXME: correctly specify target |
+ return threadName === WebInspector.TimelineModel.RendererMainThreadName ? |
+ WebInspector.targetManager.targets()[0] || null : |
+ null; |
+ } |
+ |
+ /** |
+ * @return {!Array.<!WebInspector.TimelineModel.Record>} |
+ */ |
+ children() { |
+ return this._children; |
+ } |
+ |
+ /** |
+ * @return {number} |
+ */ |
+ startTime() { |
+ return this._event.startTime; |
+ } |
+ |
+ /** |
+ * @return {number} |
+ */ |
+ endTime() { |
+ return this._event.endTime || this._event.startTime; |
+ } |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ thread() { |
+ if (this._event.thread.name() === WebInspector.TimelineModel.RendererMainThreadName) |
+ return WebInspector.TimelineModel.MainThreadName; |
+ return this._event.thread.name(); |
+ } |
+ |
+ /** |
+ * @return {!WebInspector.TimelineModel.RecordType} |
+ */ |
+ type() { |
+ return WebInspector.TimelineModel._eventType(this._event); |
+ } |
+ |
+ /** |
+ * @param {string} key |
+ * @return {?Object} |
+ */ |
+ getUserObject(key) { |
+ if (key === 'TimelineUIUtils::preview-element') |
+ return this._event.previewElement; |
+ throw new Error('Unexpected key: ' + key); |
+ } |
+ |
+ /** |
+ * @param {string} key |
+ * @param {?Object|undefined} value |
+ */ |
+ setUserObject(key, value) { |
+ if (key !== 'TimelineUIUtils::preview-element') |
+ throw new Error('Unexpected key: ' + key); |
+ this._event.previewElement = /** @type {?Element} */ (value); |
+ } |
+ |
+ /** |
+ * @return {!WebInspector.TracingModel.Event} |
+ */ |
+ traceEvent() { |
+ return this._event; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TimelineModel.Record} child |
+ */ |
+ _addChild(child) { |
+ this._children.push(child); |
+ child.parent = this; |
+ } |
}; |
+ |
+/** @typedef {!{page: !Array<!WebInspector.TracingModel.Event>, workers: !Array<!WebInspector.TracingModel.Event>}} */ |
+WebInspector.TimelineModel.MetadataEvents; |
+ |
+ |
/** |
- * @constructor |
- * @param {!WebInspector.TracingModel.Event} event |
+ * @unrestricted |
*/ |
-WebInspector.TimelineModel.NetworkRequest = function(event) |
-{ |
+WebInspector.TimelineModel.NetworkRequest = class { |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ */ |
+ constructor(event) { |
this.startTime = event.name === WebInspector.TimelineModel.RecordType.ResourceSendRequest ? event.startTime : 0; |
this.endTime = Infinity; |
/** @type {!Array<!WebInspector.TracingModel.Event>} */ |
this.children = []; |
this.addEvent(event); |
-}; |
- |
-WebInspector.TimelineModel.NetworkRequest.prototype = { |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- */ |
- addEvent: function(event) |
- { |
- this.children.push(event); |
- var recordType = WebInspector.TimelineModel.RecordType; |
- this.startTime = Math.min(this.startTime, event.startTime); |
- var eventData = event.args["data"]; |
- if (eventData["mimeType"]) |
- this.mimeType = eventData["mimeType"]; |
- if ("priority" in eventData) |
- this.priority = eventData["priority"]; |
- if (event.name === recordType.ResourceFinish) |
- this.endTime = event.startTime; |
- if (!this.responseTime && (event.name === recordType.ResourceReceiveResponse || event.name === recordType.ResourceReceivedData)) |
- this.responseTime = event.startTime; |
- if (!this.url) |
- this.url = eventData["url"]; |
- if (!this.requestMethod) |
- this.requestMethod = eventData["requestMethod"]; |
- } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ */ |
+ addEvent(event) { |
+ this.children.push(event); |
+ var recordType = WebInspector.TimelineModel.RecordType; |
+ this.startTime = Math.min(this.startTime, event.startTime); |
+ var eventData = event.args['data']; |
+ if (eventData['mimeType']) |
+ this.mimeType = eventData['mimeType']; |
+ if ('priority' in eventData) |
+ this.priority = eventData['priority']; |
+ if (event.name === recordType.ResourceFinish) |
+ this.endTime = event.startTime; |
+ if (!this.responseTime && |
+ (event.name === recordType.ResourceReceiveResponse || event.name === recordType.ResourceReceivedData)) |
+ this.responseTime = event.startTime; |
+ if (!this.url) |
+ this.url = eventData['url']; |
+ if (!this.requestMethod) |
+ this.requestMethod = eventData['requestMethod']; |
+ } |
}; |
/** |
- * @constructor |
+ * @unrestricted |
*/ |
-WebInspector.TimelineModel.Filter = function() |
-{ |
-}; |
- |
-WebInspector.TimelineModel.Filter.prototype = { |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- accept: function(event) |
- { |
- return true; |
- } |
+WebInspector.TimelineModel.Filter = class { |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ accept(event) { |
+ return true; |
+ } |
}; |
/** |
- * @constructor |
- * @extends {WebInspector.TimelineModel.Filter} |
- * @param {!Array.<string>} visibleTypes |
+ * @unrestricted |
*/ |
-WebInspector.TimelineVisibleEventsFilter = function(visibleTypes) |
-{ |
- WebInspector.TimelineModel.Filter.call(this); |
+WebInspector.TimelineVisibleEventsFilter = class extends WebInspector.TimelineModel.Filter { |
+ /** |
+ * @param {!Array.<string>} visibleTypes |
+ */ |
+ constructor(visibleTypes) { |
+ super(); |
this._visibleTypes = new Set(visibleTypes); |
-}; |
- |
-WebInspector.TimelineVisibleEventsFilter.prototype = { |
- /** |
- * @override |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- accept: function(event) |
- { |
- return this._visibleTypes.has(WebInspector.TimelineModel._eventType(event)); |
- }, |
- |
- __proto__: WebInspector.TimelineModel.Filter.prototype |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ accept(event) { |
+ return this._visibleTypes.has(WebInspector.TimelineModel._eventType(event)); |
+ } |
}; |
/** |
- * @constructor |
- * @extends {WebInspector.TimelineModel.Filter} |
- * @param {!Array<string>} excludeNames |
+ * @unrestricted |
*/ |
-WebInspector.ExclusiveNameFilter = function(excludeNames) |
-{ |
- WebInspector.TimelineModel.Filter.call(this); |
+WebInspector.ExclusiveNameFilter = class extends WebInspector.TimelineModel.Filter { |
+ /** |
+ * @param {!Array<string>} excludeNames |
+ */ |
+ constructor(excludeNames) { |
+ super(); |
this._excludeNames = new Set(excludeNames); |
-}; |
- |
-WebInspector.ExclusiveNameFilter.prototype = { |
- /** |
- * @override |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- accept: function(event) |
- { |
- return !this._excludeNames.has(event.name); |
- }, |
- |
- __proto__: WebInspector.TimelineModel.Filter.prototype |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ accept(event) { |
+ return !this._excludeNames.has(event.name); |
+ } |
}; |
/** |
- * @constructor |
- * @extends {WebInspector.TimelineModel.Filter} |
+ * @unrestricted |
*/ |
-WebInspector.ExcludeTopLevelFilter = function() |
-{ |
- WebInspector.TimelineModel.Filter.call(this); |
-}; |
- |
-WebInspector.ExcludeTopLevelFilter.prototype = { |
- /** |
- * @override |
- * @param {!WebInspector.TracingModel.Event} event |
- * @return {boolean} |
- */ |
- accept: function(event) |
- { |
- return !WebInspector.TracingModel.isTopLevelEvent(event); |
- }, |
- |
- __proto__: WebInspector.TimelineModel.Filter.prototype |
+WebInspector.ExcludeTopLevelFilter = class extends WebInspector.TimelineModel.Filter { |
+ constructor() { |
+ super(); |
+ } |
+ |
+ /** |
+ * @override |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @return {boolean} |
+ */ |
+ accept(event) { |
+ return !WebInspector.TracingModel.isTopLevelEvent(event); |
+ } |
}; |
/** |
- * @constructor |
- * @param {!WebInspector.TracingModel.Event} event |
+ * @unrestricted |
*/ |
-WebInspector.InvalidationTrackingEvent = function(event) |
-{ |
+WebInspector.InvalidationTrackingEvent = class { |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ */ |
+ constructor(event) { |
/** @type {string} */ |
this.type = event.name; |
/** @type {number} */ |
@@ -1505,358 +1459,362 @@ WebInspector.InvalidationTrackingEvent = function(event) |
/** @type {!WebInspector.TracingModel.Event} */ |
this._tracingEvent = event; |
- var eventData = event.args["data"]; |
+ var eventData = event.args['data']; |
/** @type {number} */ |
- this.frame = eventData["frame"]; |
+ this.frame = eventData['frame']; |
/** @type {?number} */ |
- this.nodeId = eventData["nodeId"]; |
+ this.nodeId = eventData['nodeId']; |
/** @type {?string} */ |
- this.nodeName = eventData["nodeName"]; |
+ this.nodeName = eventData['nodeName']; |
/** @type {?number} */ |
- this.paintId = eventData["paintId"]; |
+ this.paintId = eventData['paintId']; |
/** @type {?number} */ |
- this.invalidationSet = eventData["invalidationSet"]; |
+ this.invalidationSet = eventData['invalidationSet']; |
/** @type {?string} */ |
- this.invalidatedSelectorId = eventData["invalidatedSelectorId"]; |
+ this.invalidatedSelectorId = eventData['invalidatedSelectorId']; |
/** @type {?string} */ |
- this.changedId = eventData["changedId"]; |
+ this.changedId = eventData['changedId']; |
/** @type {?string} */ |
- this.changedClass = eventData["changedClass"]; |
+ this.changedClass = eventData['changedClass']; |
/** @type {?string} */ |
- this.changedAttribute = eventData["changedAttribute"]; |
+ this.changedAttribute = eventData['changedAttribute']; |
/** @type {?string} */ |
- this.changedPseudo = eventData["changedPseudo"]; |
+ this.changedPseudo = eventData['changedPseudo']; |
/** @type {?string} */ |
- this.selectorPart = eventData["selectorPart"]; |
+ this.selectorPart = eventData['selectorPart']; |
/** @type {?string} */ |
- this.extraData = eventData["extraData"]; |
+ this.extraData = eventData['extraData']; |
/** @type {?Array.<!Object.<string, number>>} */ |
- this.invalidationList = eventData["invalidationList"]; |
+ this.invalidationList = eventData['invalidationList']; |
/** @type {!WebInspector.InvalidationCause} */ |
- this.cause = {reason: eventData["reason"], stackTrace: eventData["stackTrace"]}; |
+ this.cause = {reason: eventData['reason'], stackTrace: eventData['stackTrace']}; |
// FIXME: Move this to TimelineUIUtils.js. |
- if (!this.cause.reason && this.cause.stackTrace && this.type === WebInspector.TimelineModel.RecordType.LayoutInvalidationTracking) |
- this.cause.reason = "Layout forced"; |
+ if (!this.cause.reason && this.cause.stackTrace && |
+ this.type === WebInspector.TimelineModel.RecordType.LayoutInvalidationTracking) |
+ this.cause.reason = 'Layout forced'; |
+ } |
}; |
/** @typedef {{reason: string, stackTrace: ?Array<!RuntimeAgent.CallFrame>}} */ |
WebInspector.InvalidationCause; |
/** |
- * @constructor |
+ * @unrestricted |
*/ |
-WebInspector.InvalidationTracker = function() |
-{ |
+WebInspector.InvalidationTracker = class { |
+ constructor() { |
this._initializePerFrameState(); |
-}; |
- |
-WebInspector.InvalidationTracker.prototype = { |
- /** |
- * @param {!WebInspector.InvalidationTrackingEvent} invalidation |
- */ |
- addInvalidation: function(invalidation) |
- { |
- this._startNewFrameIfNeeded(); |
- |
- if (!invalidation.nodeId && !invalidation.paintId) { |
- console.error("Invalidation lacks node information."); |
- console.error(invalidation); |
- return; |
- } |
- |
- // PaintInvalidationTracking events provide a paintId and a nodeId which |
- // we can use to update the paintId for all other invalidation tracking |
- // events. |
- var recordTypes = WebInspector.TimelineModel.RecordType; |
- if (invalidation.type === recordTypes.PaintInvalidationTracking && invalidation.nodeId) { |
- var invalidations = this._invalidationsByNodeId[invalidation.nodeId] || []; |
- for (var i = 0; i < invalidations.length; ++i) |
- invalidations[i].paintId = invalidation.paintId; |
- |
- // PaintInvalidationTracking is only used for updating paintIds. |
- return; |
- } |
- |
- // Suppress StyleInvalidator StyleRecalcInvalidationTracking invalidations because they |
- // will be handled by StyleInvalidatorInvalidationTracking. |
- // FIXME: Investigate if we can remove StyleInvalidator invalidations entirely. |
- if (invalidation.type === recordTypes.StyleRecalcInvalidationTracking && invalidation.cause.reason === "StyleInvalidator") |
- return; |
- |
- // Style invalidation events can occur before and during recalc style. didRecalcStyle |
- // handles style invalidations that occur before the recalc style event but we need to |
- // handle style recalc invalidations during recalc style here. |
- var styleRecalcInvalidation = (invalidation.type === recordTypes.ScheduleStyleInvalidationTracking |
- || invalidation.type === recordTypes.StyleInvalidatorInvalidationTracking |
- || invalidation.type === recordTypes.StyleRecalcInvalidationTracking); |
- if (styleRecalcInvalidation) { |
- var duringRecalcStyle = invalidation.startTime && this._lastRecalcStyle |
- && invalidation.startTime >= this._lastRecalcStyle.startTime |
- && invalidation.startTime <= this._lastRecalcStyle.endTime; |
- if (duringRecalcStyle) |
- this._associateWithLastRecalcStyleEvent(invalidation); |
- } |
- |
- // Record the invalidation so later events can look it up. |
- if (this._invalidations[invalidation.type]) |
- this._invalidations[invalidation.type].push(invalidation); |
- else |
- this._invalidations[invalidation.type] = [ invalidation ]; |
- if (invalidation.nodeId) { |
- if (this._invalidationsByNodeId[invalidation.nodeId]) |
- this._invalidationsByNodeId[invalidation.nodeId].push(invalidation); |
- else |
- this._invalidationsByNodeId[invalidation.nodeId] = [ invalidation ]; |
- } |
- }, |
- |
- /** |
- * @param {!WebInspector.TracingModel.Event} recalcStyleEvent |
- */ |
- didRecalcStyle: function(recalcStyleEvent) |
- { |
- this._lastRecalcStyle = recalcStyleEvent; |
- var types = [WebInspector.TimelineModel.RecordType.ScheduleStyleInvalidationTracking, |
- WebInspector.TimelineModel.RecordType.StyleInvalidatorInvalidationTracking, |
- WebInspector.TimelineModel.RecordType.StyleRecalcInvalidationTracking]; |
- for (var invalidation of this._invalidationsOfTypes(types)) |
- this._associateWithLastRecalcStyleEvent(invalidation); |
- }, |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.InvalidationTrackingEvent} invalidation |
+ */ |
+ addInvalidation(invalidation) { |
+ this._startNewFrameIfNeeded(); |
+ |
+ if (!invalidation.nodeId && !invalidation.paintId) { |
+ console.error('Invalidation lacks node information.'); |
+ console.error(invalidation); |
+ return; |
+ } |
- /** |
- * @param {!WebInspector.InvalidationTrackingEvent} invalidation |
- */ |
- _associateWithLastRecalcStyleEvent: function(invalidation) |
- { |
- if (invalidation.linkedRecalcStyleEvent) |
- return; |
- |
- var recordTypes = WebInspector.TimelineModel.RecordType; |
- var recalcStyleFrameId = this._lastRecalcStyle.args["beginData"]["frame"]; |
- if (invalidation.type === recordTypes.StyleInvalidatorInvalidationTracking) { |
- // Instead of calling _addInvalidationToEvent directly, we create synthetic |
- // StyleRecalcInvalidationTracking events which will be added in _addInvalidationToEvent. |
- this._addSyntheticStyleRecalcInvalidations(this._lastRecalcStyle, recalcStyleFrameId, invalidation); |
- } else if (invalidation.type === recordTypes.ScheduleStyleInvalidationTracking) { |
- // ScheduleStyleInvalidationTracking events are only used for adding information to |
- // StyleInvalidatorInvalidationTracking events. See: _addSyntheticStyleRecalcInvalidations. |
- } else { |
- this._addInvalidationToEvent(this._lastRecalcStyle, recalcStyleFrameId, invalidation); |
- } |
+ // PaintInvalidationTracking events provide a paintId and a nodeId which |
+ // we can use to update the paintId for all other invalidation tracking |
+ // events. |
+ var recordTypes = WebInspector.TimelineModel.RecordType; |
+ if (invalidation.type === recordTypes.PaintInvalidationTracking && invalidation.nodeId) { |
+ var invalidations = this._invalidationsByNodeId[invalidation.nodeId] || []; |
+ for (var i = 0; i < invalidations.length; ++i) |
+ invalidations[i].paintId = invalidation.paintId; |
- invalidation.linkedRecalcStyleEvent = true; |
- }, |
+ // PaintInvalidationTracking is only used for updating paintIds. |
+ return; |
+ } |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @param {number} frameId |
- * @param {!WebInspector.InvalidationTrackingEvent} styleInvalidatorInvalidation |
- */ |
- _addSyntheticStyleRecalcInvalidations: function(event, frameId, styleInvalidatorInvalidation) |
- { |
- if (!styleInvalidatorInvalidation.invalidationList) { |
- this._addSyntheticStyleRecalcInvalidation(styleInvalidatorInvalidation._tracingEvent, styleInvalidatorInvalidation); |
- return; |
- } |
- if (!styleInvalidatorInvalidation.nodeId) { |
- console.error("Invalidation lacks node information."); |
- console.error(invalidation); |
- return; |
- } |
- for (var i = 0; i < styleInvalidatorInvalidation.invalidationList.length; i++) { |
- var setId = styleInvalidatorInvalidation.invalidationList[i]["id"]; |
- var lastScheduleStyleRecalculation; |
- var nodeInvalidations = this._invalidationsByNodeId[styleInvalidatorInvalidation.nodeId] || []; |
- for (var j = 0; j < nodeInvalidations.length; j++) { |
- var invalidation = nodeInvalidations[j]; |
- if (invalidation.frame !== frameId || invalidation.invalidationSet !== setId || invalidation.type !== WebInspector.TimelineModel.RecordType.ScheduleStyleInvalidationTracking) |
- continue; |
- lastScheduleStyleRecalculation = invalidation; |
- } |
- if (!lastScheduleStyleRecalculation) { |
- console.error("Failed to lookup the event that scheduled a style invalidator invalidation."); |
- continue; |
- } |
- this._addSyntheticStyleRecalcInvalidation(lastScheduleStyleRecalculation._tracingEvent, styleInvalidatorInvalidation); |
- } |
- }, |
+ // Suppress StyleInvalidator StyleRecalcInvalidationTracking invalidations because they |
+ // will be handled by StyleInvalidatorInvalidationTracking. |
+ // FIXME: Investigate if we can remove StyleInvalidator invalidations entirely. |
+ if (invalidation.type === recordTypes.StyleRecalcInvalidationTracking && |
+ invalidation.cause.reason === 'StyleInvalidator') |
+ return; |
+ |
+ // Style invalidation events can occur before and during recalc style. didRecalcStyle |
+ // handles style invalidations that occur before the recalc style event but we need to |
+ // handle style recalc invalidations during recalc style here. |
+ var styleRecalcInvalidation = |
+ (invalidation.type === recordTypes.ScheduleStyleInvalidationTracking || |
+ invalidation.type === recordTypes.StyleInvalidatorInvalidationTracking || |
+ invalidation.type === recordTypes.StyleRecalcInvalidationTracking); |
+ if (styleRecalcInvalidation) { |
+ var duringRecalcStyle = invalidation.startTime && this._lastRecalcStyle && |
+ invalidation.startTime >= this._lastRecalcStyle.startTime && |
+ invalidation.startTime <= this._lastRecalcStyle.endTime; |
+ if (duringRecalcStyle) |
+ this._associateWithLastRecalcStyleEvent(invalidation); |
+ } |
- /** |
- * @param {!WebInspector.TracingModel.Event} baseEvent |
- * @param {!WebInspector.InvalidationTrackingEvent} styleInvalidatorInvalidation |
- */ |
- _addSyntheticStyleRecalcInvalidation: function(baseEvent, styleInvalidatorInvalidation) |
- { |
- var invalidation = new WebInspector.InvalidationTrackingEvent(baseEvent); |
- invalidation.type = WebInspector.TimelineModel.RecordType.StyleRecalcInvalidationTracking; |
- invalidation.synthetic = true; |
- if (styleInvalidatorInvalidation.cause.reason) |
- invalidation.cause.reason = styleInvalidatorInvalidation.cause.reason; |
- if (styleInvalidatorInvalidation.selectorPart) |
- invalidation.selectorPart = styleInvalidatorInvalidation.selectorPart; |
- |
- this.addInvalidation(invalidation); |
- if (!invalidation.linkedRecalcStyleEvent) |
- this._associateWithLastRecalcStyleEvent(invalidation); |
- }, |
+ // Record the invalidation so later events can look it up. |
+ if (this._invalidations[invalidation.type]) |
+ this._invalidations[invalidation.type].push(invalidation); |
+ else |
+ this._invalidations[invalidation.type] = [invalidation]; |
+ if (invalidation.nodeId) { |
+ if (this._invalidationsByNodeId[invalidation.nodeId]) |
+ this._invalidationsByNodeId[invalidation.nodeId].push(invalidation); |
+ else |
+ this._invalidationsByNodeId[invalidation.nodeId] = [invalidation]; |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} recalcStyleEvent |
+ */ |
+ didRecalcStyle(recalcStyleEvent) { |
+ this._lastRecalcStyle = recalcStyleEvent; |
+ var types = [ |
+ WebInspector.TimelineModel.RecordType.ScheduleStyleInvalidationTracking, |
+ WebInspector.TimelineModel.RecordType.StyleInvalidatorInvalidationTracking, |
+ WebInspector.TimelineModel.RecordType.StyleRecalcInvalidationTracking |
+ ]; |
+ for (var invalidation of this._invalidationsOfTypes(types)) |
+ this._associateWithLastRecalcStyleEvent(invalidation); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.InvalidationTrackingEvent} invalidation |
+ */ |
+ _associateWithLastRecalcStyleEvent(invalidation) { |
+ if (invalidation.linkedRecalcStyleEvent) |
+ return; |
- /** |
- * @param {!WebInspector.TracingModel.Event} layoutEvent |
- */ |
- didLayout: function(layoutEvent) |
- { |
- var layoutFrameId = layoutEvent.args["beginData"]["frame"]; |
- for (var invalidation of this._invalidationsOfTypes([WebInspector.TimelineModel.RecordType.LayoutInvalidationTracking])) { |
- if (invalidation.linkedLayoutEvent) |
- continue; |
- this._addInvalidationToEvent(layoutEvent, layoutFrameId, invalidation); |
- invalidation.linkedLayoutEvent = true; |
- } |
- }, |
+ var recordTypes = WebInspector.TimelineModel.RecordType; |
+ var recalcStyleFrameId = this._lastRecalcStyle.args['beginData']['frame']; |
+ if (invalidation.type === recordTypes.StyleInvalidatorInvalidationTracking) { |
+ // Instead of calling _addInvalidationToEvent directly, we create synthetic |
+ // StyleRecalcInvalidationTracking events which will be added in _addInvalidationToEvent. |
+ this._addSyntheticStyleRecalcInvalidations(this._lastRecalcStyle, recalcStyleFrameId, invalidation); |
+ } else if (invalidation.type === recordTypes.ScheduleStyleInvalidationTracking) { |
+ // ScheduleStyleInvalidationTracking events are only used for adding information to |
+ // StyleInvalidatorInvalidationTracking events. See: _addSyntheticStyleRecalcInvalidations. |
+ } else { |
+ this._addInvalidationToEvent(this._lastRecalcStyle, recalcStyleFrameId, invalidation); |
+ } |
- /** |
- * @param {!WebInspector.TracingModel.Event} paintEvent |
- */ |
- didPaint: function(paintEvent) |
- { |
- this._didPaint = true; |
- |
- // If a paint doesn't have a corresponding graphics layer id, it paints |
- // into its parent so add an effectivePaintId to these events. |
- var layerId = paintEvent.args["data"]["layerId"]; |
- if (layerId) |
- this._lastPaintWithLayer = paintEvent; |
- // Quietly discard top-level paints without layerId, as these are likely |
- // to come from overlay. |
- if (!this._lastPaintWithLayer) |
- return; |
- |
- var effectivePaintId = this._lastPaintWithLayer.args["data"]["nodeId"]; |
- var paintFrameId = paintEvent.args["data"]["frame"]; |
- var types = [WebInspector.TimelineModel.RecordType.StyleRecalcInvalidationTracking, |
- WebInspector.TimelineModel.RecordType.LayoutInvalidationTracking, |
- WebInspector.TimelineModel.RecordType.PaintInvalidationTracking, |
- WebInspector.TimelineModel.RecordType.ScrollInvalidationTracking]; |
- for (var invalidation of this._invalidationsOfTypes(types)) { |
- if (invalidation.paintId === effectivePaintId) |
- this._addInvalidationToEvent(paintEvent, paintFrameId, invalidation); |
- } |
- }, |
+ invalidation.linkedRecalcStyleEvent = true; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @param {number} frameId |
+ * @param {!WebInspector.InvalidationTrackingEvent} styleInvalidatorInvalidation |
+ */ |
+ _addSyntheticStyleRecalcInvalidations(event, frameId, styleInvalidatorInvalidation) { |
+ if (!styleInvalidatorInvalidation.invalidationList) { |
+ this._addSyntheticStyleRecalcInvalidation( |
+ styleInvalidatorInvalidation._tracingEvent, styleInvalidatorInvalidation); |
+ return; |
+ } |
+ if (!styleInvalidatorInvalidation.nodeId) { |
+ console.error('Invalidation lacks node information.'); |
+ console.error(invalidation); |
+ return; |
+ } |
+ for (var i = 0; i < styleInvalidatorInvalidation.invalidationList.length; i++) { |
+ var setId = styleInvalidatorInvalidation.invalidationList[i]['id']; |
+ var lastScheduleStyleRecalculation; |
+ var nodeInvalidations = this._invalidationsByNodeId[styleInvalidatorInvalidation.nodeId] || []; |
+ for (var j = 0; j < nodeInvalidations.length; j++) { |
+ var invalidation = nodeInvalidations[j]; |
+ if (invalidation.frame !== frameId || invalidation.invalidationSet !== setId || |
+ invalidation.type !== WebInspector.TimelineModel.RecordType.ScheduleStyleInvalidationTracking) |
+ continue; |
+ lastScheduleStyleRecalculation = invalidation; |
+ } |
+ if (!lastScheduleStyleRecalculation) { |
+ console.error('Failed to lookup the event that scheduled a style invalidator invalidation.'); |
+ continue; |
+ } |
+ this._addSyntheticStyleRecalcInvalidation( |
+ lastScheduleStyleRecalculation._tracingEvent, styleInvalidatorInvalidation); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} baseEvent |
+ * @param {!WebInspector.InvalidationTrackingEvent} styleInvalidatorInvalidation |
+ */ |
+ _addSyntheticStyleRecalcInvalidation(baseEvent, styleInvalidatorInvalidation) { |
+ var invalidation = new WebInspector.InvalidationTrackingEvent(baseEvent); |
+ invalidation.type = WebInspector.TimelineModel.RecordType.StyleRecalcInvalidationTracking; |
+ invalidation.synthetic = true; |
+ if (styleInvalidatorInvalidation.cause.reason) |
+ invalidation.cause.reason = styleInvalidatorInvalidation.cause.reason; |
+ if (styleInvalidatorInvalidation.selectorPart) |
+ invalidation.selectorPart = styleInvalidatorInvalidation.selectorPart; |
+ |
+ this.addInvalidation(invalidation); |
+ if (!invalidation.linkedRecalcStyleEvent) |
+ this._associateWithLastRecalcStyleEvent(invalidation); |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} layoutEvent |
+ */ |
+ didLayout(layoutEvent) { |
+ var layoutFrameId = layoutEvent.args['beginData']['frame']; |
+ for (var invalidation of this._invalidationsOfTypes( |
+ [WebInspector.TimelineModel.RecordType.LayoutInvalidationTracking])) { |
+ if (invalidation.linkedLayoutEvent) |
+ continue; |
+ this._addInvalidationToEvent(layoutEvent, layoutFrameId, invalidation); |
+ invalidation.linkedLayoutEvent = true; |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} paintEvent |
+ */ |
+ didPaint(paintEvent) { |
+ this._didPaint = true; |
+ |
+ // If a paint doesn't have a corresponding graphics layer id, it paints |
+ // into its parent so add an effectivePaintId to these events. |
+ var layerId = paintEvent.args['data']['layerId']; |
+ if (layerId) |
+ this._lastPaintWithLayer = paintEvent; |
+ // Quietly discard top-level paints without layerId, as these are likely |
+ // to come from overlay. |
+ if (!this._lastPaintWithLayer) |
+ return; |
+ |
+ var effectivePaintId = this._lastPaintWithLayer.args['data']['nodeId']; |
+ var paintFrameId = paintEvent.args['data']['frame']; |
+ var types = [ |
+ WebInspector.TimelineModel.RecordType.StyleRecalcInvalidationTracking, |
+ WebInspector.TimelineModel.RecordType.LayoutInvalidationTracking, |
+ WebInspector.TimelineModel.RecordType.PaintInvalidationTracking, |
+ WebInspector.TimelineModel.RecordType.ScrollInvalidationTracking |
+ ]; |
+ for (var invalidation of this._invalidationsOfTypes(types)) { |
+ if (invalidation.paintId === effectivePaintId) |
+ this._addInvalidationToEvent(paintEvent, paintFrameId, invalidation); |
+ } |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ * @param {number} eventFrameId |
+ * @param {!WebInspector.InvalidationTrackingEvent} invalidation |
+ */ |
+ _addInvalidationToEvent(event, eventFrameId, invalidation) { |
+ if (eventFrameId !== invalidation.frame) |
+ return; |
+ if (!event.invalidationTrackingEvents) |
+ event.invalidationTrackingEvents = [invalidation]; |
+ else |
+ event.invalidationTrackingEvents.push(invalidation); |
+ } |
+ |
+ /** |
+ * @param {!Array.<string>=} types |
+ * @return {!Iterator.<!WebInspector.InvalidationTrackingEvent>} |
+ */ |
+ _invalidationsOfTypes(types) { |
+ var invalidations = this._invalidations; |
+ if (!types) |
+ types = Object.keys(invalidations); |
+ function* generator() { |
+ for (var i = 0; i < types.length; ++i) { |
+ var invalidationList = invalidations[types[i]] || []; |
+ for (var j = 0; j < invalidationList.length; ++j) |
+ yield invalidationList[j]; |
+ } |
+ } |
+ return generator(); |
+ } |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- * @param {number} eventFrameId |
- * @param {!WebInspector.InvalidationTrackingEvent} invalidation |
- */ |
- _addInvalidationToEvent: function(event, eventFrameId, invalidation) |
- { |
- if (eventFrameId !== invalidation.frame) |
- return; |
- if (!event.invalidationTrackingEvents) |
- event.invalidationTrackingEvents = [ invalidation ]; |
- else |
- event.invalidationTrackingEvents.push(invalidation); |
- }, |
+ _startNewFrameIfNeeded() { |
+ if (!this._didPaint) |
+ return; |
- /** |
- * @param {!Array.<string>=} types |
- * @return {!Iterator.<!WebInspector.InvalidationTrackingEvent>} |
- */ |
- _invalidationsOfTypes: function(types) |
- { |
- var invalidations = this._invalidations; |
- if (!types) |
- types = Object.keys(invalidations); |
- function* generator() |
- { |
- for (var i = 0; i < types.length; ++i) { |
- var invalidationList = invalidations[types[i]] || []; |
- for (var j = 0; j < invalidationList.length; ++j) |
- yield invalidationList[j]; |
- } |
- } |
- return generator(); |
- }, |
- |
- _startNewFrameIfNeeded: function() |
- { |
- if (!this._didPaint) |
- return; |
- |
- this._initializePerFrameState(); |
- }, |
- |
- _initializePerFrameState: function() |
- { |
- /** @type {!Object.<string, !Array.<!WebInspector.InvalidationTrackingEvent>>} */ |
- this._invalidations = {}; |
- /** @type {!Object.<number, !Array.<!WebInspector.InvalidationTrackingEvent>>} */ |
- this._invalidationsByNodeId = {}; |
- |
- this._lastRecalcStyle = undefined; |
- this._lastPaintWithLayer = undefined; |
- this._didPaint = false; |
- } |
+ this._initializePerFrameState(); |
+ } |
+ |
+ _initializePerFrameState() { |
+ /** @type {!Object.<string, !Array.<!WebInspector.InvalidationTrackingEvent>>} */ |
+ this._invalidations = {}; |
+ /** @type {!Object.<number, !Array.<!WebInspector.InvalidationTrackingEvent>>} */ |
+ this._invalidationsByNodeId = {}; |
+ |
+ this._lastRecalcStyle = undefined; |
+ this._lastPaintWithLayer = undefined; |
+ this._didPaint = false; |
+ } |
}; |
/** |
- * @constructor |
+ * @unrestricted |
*/ |
-WebInspector.TimelineAsyncEventTracker = function() |
-{ |
+WebInspector.TimelineAsyncEventTracker = class { |
+ constructor() { |
WebInspector.TimelineAsyncEventTracker._initialize(); |
/** @type {!Map<!WebInspector.TimelineModel.RecordType, !Map<string, !WebInspector.TracingModel.Event>>} */ |
this._initiatorByType = new Map(); |
for (var initiator of WebInspector.TimelineAsyncEventTracker._asyncEvents.keys()) |
- this._initiatorByType.set(initiator, new Map()); |
-}; |
+ this._initiatorByType.set(initiator, new Map()); |
+ } |
-WebInspector.TimelineAsyncEventTracker._initialize = function() |
-{ |
+ static _initialize() { |
if (WebInspector.TimelineAsyncEventTracker._asyncEvents) |
- return; |
+ return; |
var events = new Map(); |
var type = WebInspector.TimelineModel.RecordType; |
- events.set(type.TimerInstall, {causes: [type.TimerFire], joinBy: "timerId"}); |
- events.set(type.ResourceSendRequest, {causes: [type.ResourceReceiveResponse, type.ResourceReceivedData, type.ResourceFinish], joinBy: "requestId"}); |
- events.set(type.RequestAnimationFrame, {causes: [type.FireAnimationFrame], joinBy: "id"}); |
- events.set(type.RequestIdleCallback, {causes: [type.FireIdleCallback], joinBy: "id"}); |
- events.set(type.WebSocketCreate, {causes: [type.WebSocketSendHandshakeRequest, type.WebSocketReceiveHandshakeResponse, type.WebSocketDestroy], joinBy: "identifier"}); |
+ events.set(type.TimerInstall, {causes: [type.TimerFire], joinBy: 'timerId'}); |
+ events.set( |
+ type.ResourceSendRequest, |
+ {causes: [type.ResourceReceiveResponse, type.ResourceReceivedData, type.ResourceFinish], joinBy: 'requestId'}); |
+ events.set(type.RequestAnimationFrame, {causes: [type.FireAnimationFrame], joinBy: 'id'}); |
+ events.set(type.RequestIdleCallback, {causes: [type.FireIdleCallback], joinBy: 'id'}); |
+ events.set(type.WebSocketCreate, { |
+ causes: [type.WebSocketSendHandshakeRequest, type.WebSocketReceiveHandshakeResponse, type.WebSocketDestroy], |
+ joinBy: 'identifier' |
+ }); |
WebInspector.TimelineAsyncEventTracker._asyncEvents = events; |
/** @type {!Map<!WebInspector.TimelineModel.RecordType, !WebInspector.TimelineModel.RecordType>} */ |
WebInspector.TimelineAsyncEventTracker._typeToInitiator = new Map(); |
for (var entry of events) { |
- var types = entry[1].causes; |
- for (type of types) |
- WebInspector.TimelineAsyncEventTracker._typeToInitiator.set(type, entry[0]); |
+ var types = entry[1].causes; |
+ for (type of types) |
+ WebInspector.TimelineAsyncEventTracker._typeToInitiator.set(type, entry[0]); |
} |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.TracingModel.Event} event |
+ */ |
+ processEvent(event) { |
+ var initiatorType = WebInspector.TimelineAsyncEventTracker._typeToInitiator.get( |
+ /** @type {!WebInspector.TimelineModel.RecordType} */ (event.name)); |
+ var isInitiator = !initiatorType; |
+ if (!initiatorType) |
+ initiatorType = /** @type {!WebInspector.TimelineModel.RecordType} */ (event.name); |
+ var initiatorInfo = WebInspector.TimelineAsyncEventTracker._asyncEvents.get(initiatorType); |
+ if (!initiatorInfo) |
+ return; |
+ var id = event.args['data'][initiatorInfo.joinBy]; |
+ if (!id) |
+ return; |
+ /** @type {!Map<string, !WebInspector.TracingModel.Event>|undefined} */ |
+ var initiatorMap = this._initiatorByType.get(initiatorType); |
+ if (isInitiator) |
+ initiatorMap.set(id, event); |
+ else |
+ event.initiator = initiatorMap.get(id) || null; |
+ } |
}; |
-WebInspector.TimelineAsyncEventTracker.prototype = { |
- /** |
- * @param {!WebInspector.TracingModel.Event} event |
- */ |
- processEvent: function(event) |
- { |
- var initiatorType = WebInspector.TimelineAsyncEventTracker._typeToInitiator.get(/** @type {!WebInspector.TimelineModel.RecordType} */ (event.name)); |
- var isInitiator = !initiatorType; |
- if (!initiatorType) |
- initiatorType = /** @type {!WebInspector.TimelineModel.RecordType} */ (event.name); |
- var initiatorInfo = WebInspector.TimelineAsyncEventTracker._asyncEvents.get(initiatorType); |
- if (!initiatorInfo) |
- return; |
- var id = event.args["data"][initiatorInfo.joinBy]; |
- if (!id) |
- return; |
- /** @type {!Map<string, !WebInspector.TracingModel.Event>|undefined} */ |
- var initiatorMap = this._initiatorByType.get(initiatorType); |
- if (isInitiator) |
- initiatorMap.set(id, event); |
- else |
- event.initiator = initiatorMap.get(id) || null; |
- } |
-}; |
+ |