| 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;
|
| - }
|
| -};
|
| +
|
|
|