| Index: Source/devtools/front_end/timeline/TracingTimelineModel.js
|
| diff --git a/Source/devtools/front_end/timeline/TracingTimelineModel.js b/Source/devtools/front_end/timeline/TracingTimelineModel.js
|
| index 4ad7f03b0e177afaeb7fac52c2ba97ce2d4936c1..5b4fed00229e28680bc6855ac7541773c2117e1e 100644
|
| --- a/Source/devtools/front_end/timeline/TracingTimelineModel.js
|
| +++ b/Source/devtools/front_end/timeline/TracingTimelineModel.js
|
| @@ -32,6 +32,9 @@ WebInspector.TracingTimelineModel.RecordType = {
|
| DrawFrame: "DrawFrame",
|
| ScheduleStyleRecalculation: "ScheduleStyleRecalculation",
|
| RecalculateStyles: "RecalculateStyles",
|
| + StyleInvalidationTracking: "StyleInvalidationTracking",
|
| + LayoutInvalidationTracking: "LayoutInvalidationTracking",
|
| + PaintInvalidationTracking: "PaintInvalidationTracking",
|
| InvalidateLayout: "InvalidateLayout",
|
| Layout: "Layout",
|
| UpdateLayer: "UpdateLayer",
|
| @@ -115,8 +118,9 @@ WebInspector.TracingTimelineModel.prototype = {
|
| * @param {boolean} captureStacks
|
| * @param {boolean} captureMemory
|
| * @param {boolean} capturePictures
|
| + * @param {boolean} captureInvalidationTracking
|
| */
|
| - startRecording: function(captureStacks, captureMemory, capturePictures)
|
| + startRecording: function(captureStacks, captureMemory, capturePictures, captureInvalidationTracking)
|
| {
|
| function disabledByDefault(category)
|
| {
|
| @@ -143,6 +147,13 @@ WebInspector.TracingTimelineModel.prototype = {
|
| disabledByDefault("devtools.timeline.picture"),
|
| disabledByDefault("blink.graphics_context_annotations")]);
|
| }
|
| + if (captureInvalidationTracking) {
|
| + categoriesArray = categoriesArray.concat([
|
| + disabledByDefault("devtools.timeline.styleInvalidationTracking"),
|
| + disabledByDefault("devtools.timeline.layoutInvalidationTracking"),
|
| + disabledByDefault("devtools.timeline.paintInvalidationTracking")
|
| + ]);
|
| + }
|
| var categories = categoriesArray.join(",");
|
| this._startRecordingWithCategories(categories);
|
| },
|
| @@ -378,6 +389,7 @@ WebInspector.TracingTimelineModel.prototype = {
|
| this._sendRequestEvents = {};
|
| this._timerEvents = {};
|
| this._requestAnimationFrameEvents = {};
|
| + this._invalidationTracker = new WebInspector.InvalidationTracker();
|
| this._layoutInvalidate = {};
|
| this._lastScheduleStyleRecalculation = {};
|
| this._webSocketCreateEvents = {};
|
| @@ -488,6 +500,30 @@ WebInspector.TracingTimelineModel.prototype = {
|
| this._lastRecalculateStylesEvent = event;
|
| break;
|
|
|
| + case recordTypes.StyleInvalidationTracking:
|
| + this._invalidationTracker.addStyleInvalidation({
|
| + frameId: event.args.data.frame,
|
| + nodeId: event.args.data.nodeId,
|
| + nodeName: event.args.data.nodeName,
|
| + callstack: event.args.data.callstack
|
| + });
|
| + break;
|
| +
|
| + case recordTypes.LayoutInvalidationTracking:
|
| + this._invalidationTracker.addLayoutInvalidation({
|
| + frameId: event.args.data.frame,
|
| + nodeId: event.args.data.nodeId,
|
| + callstack: event.args.data.callstack
|
| + });
|
| + break;
|
| +
|
| + case recordTypes.PaintInvalidationTracking:
|
| + this._invalidationTracker.addPaintInvalidation({
|
| + frameId: event.args.data.frame,
|
| + nodeId: event.args.data.nodeId
|
| + });
|
| + break;
|
| +
|
| case recordTypes.InvalidateLayout:
|
| // Consider style recalculation as a reason for layout invalidation,
|
| // but only if we had no earlier layout invalidation records.
|
| @@ -529,6 +565,7 @@ WebInspector.TracingTimelineModel.prototype = {
|
| break;
|
|
|
| case recordTypes.Paint:
|
| + this._invalidationTracker.setCurrentPaint(event);
|
| event.highlightQuad = event.args["data"]["clip"];
|
| event.backendNodeId = event.args["data"]["nodeId"];
|
| var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer);
|
| @@ -1016,3 +1053,125 @@ WebInspector.TracingTimelineSaver.prototype = {
|
| this._writeNextChunk(stream);
|
| }
|
| }
|
| +
|
| +/**
|
| + * TODO: Properly doc this class.
|
| + *
|
| + * Track style, layout, and paint invalidation events.
|
| + *
|
| + * As style or layout tracking invalidation events come in, they should be
|
| + * registered here with add{Style,Layout}Invalidation.
|
| + * When a paint event occurs (not invalidation tracking event), setCurrentPaint
|
| + * should be called.
|
| + * As paint tracking invalidation events come in, they should be registered
|
| + * here with addPaintInvalidation. This function will annote the correct
|
| + * paint event with style and layout invalidations.
|
| + *
|
| + * This class assumes events will come in the following order (expressed in pdr-bnf):
|
| + * 1) (one or more) layout or style invalidation tracking events.
|
| + * 2) (one or more) paint event followed by one or more paint invalidation tracking events.
|
| + */
|
| +WebInspector.InvalidationTracker = function()
|
| +{
|
| + // Invalidation events for the current frame.
|
| + this._styleTrackingEvents = {};
|
| + this._layoutTrackingEvents = {};
|
| +
|
| + // Invalidation events for the currently painting frame.
|
| + // FIXME: these maps grow over time and need to be cleared after the frame ends.
|
| + this._paintingStyleInvalidationMap = {};
|
| + this._paintingLayoutInvalidationMap = {};
|
| +
|
| + this._currentPaintEvent = undefined;
|
| +}
|
| +
|
| +WebInspector.InvalidationTracker.prototype = {
|
| +
|
| + addStyleInvalidation: function(invalidation)
|
| + {
|
| + this._currentPaintEvent = undefined;
|
| +
|
| + var frameId = invalidation.frameId;
|
| + if (this._styleTrackingEvents[frameId] === undefined)
|
| + this._styleTrackingEvents[frameId] = [];
|
| + this._styleTrackingEvents[frameId].push(invalidation);
|
| + },
|
| +
|
| + addLayoutInvalidation: function(invalidation)
|
| + {
|
| + this._currentPaintEvent = undefined;
|
| +
|
| + var frameId = invalidation.frameId;
|
| + if (this._layoutTrackingEvents[frameId] === undefined)
|
| + this._layoutTrackingEvents[frameId] = [];
|
| + this._layoutTrackingEvents[frameId].push(invalidation);
|
| + },
|
| +
|
| + addPaintInvalidation: function(invalidation)
|
| + {
|
| + var frameId = invalidation.frameId;
|
| + var paintEvent = this._currentPaintEvent;
|
| +
|
| + if (paintEvent === undefined) {
|
| + console.warn("Received paint event with no style or layout invalidations.");
|
| + return;
|
| + }
|
| +
|
| + var styleNodeIdMap = this._paintingStyleInvalidationMap[frameId];
|
| + if (styleNodeIdMap && styleNodeIdMap[invalidation.nodeId]) {
|
| + styleNodeIdMap[invalidation.nodeId].forEach(function(styleEvent) {
|
| + if (paintEvent.styleInvalidationTrackingEvents.indexOf(styleEvent) == -1)
|
| + paintEvent.styleInvalidationTrackingEvents.push(styleEvent);
|
| + });
|
| + }
|
| + var layoutNodeIdMap = this._paintingLayoutInvalidationMap[frameId];
|
| + if (layoutNodeIdMap && layoutNodeIdMap[invalidation.nodeId]) {
|
| + layoutNodeIdMap[invalidation.nodeId].forEach(function(layoutEvent) {
|
| + if (paintEvent.layoutInvalidationTrackingEvents.indexOf(layoutEvent) == -1)
|
| + paintEvent.layoutInvalidationTrackingEvents.push(layoutEvent);
|
| + });
|
| + }
|
| + },
|
| +
|
| + setCurrentPaint: function(event)
|
| + {
|
| + this._startNewFrameIfNeeded(event.args.data.frame);
|
| +
|
| + event.styleInvalidationTrackingEvents = [];
|
| + event.layoutInvalidationTrackingEvents = [];
|
| + this._currentPaintEvent = event;
|
| + },
|
| +
|
| + // If there's a new frame, save off all current invalidations.
|
| + _startNewFrameIfNeeded: function(frameId)
|
| + {
|
| + // FIXME: Need to track compositor events as well, as they can cause
|
| + // paints without style or layout invalidating. For now, we
|
| + // assume that the existance of style or layout invalidations
|
| + // after paint begins indicates a new frame has started.
|
| + if (this._styleTrackingEvents[frameId] === undefined &&
|
| + this._layoutTrackingEvents[frameId] === undefined)
|
| + return;
|
| +
|
| + var styleTrackingEvents = this._styleTrackingEvents[frameId] || [];
|
| + var layoutTrackingEvents = this._layoutTrackingEvents[frameId] || [];
|
| + this._styleTrackingEvents[frameId] = undefined;
|
| + this._layoutTrackingEvents[frameId] = undefined;
|
| +
|
| + var styleInvalidationMap = {};
|
| + styleTrackingEvents.forEach(function(styleEvent) {
|
| + if (styleInvalidationMap[styleEvent.nodeId] === undefined)
|
| + styleInvalidationMap[styleEvent.nodeId] = [];
|
| + styleInvalidationMap[styleEvent.nodeId].push(styleEvent);
|
| + });
|
| + this._paintingStyleInvalidationMap[frameId] = styleInvalidationMap;
|
| +
|
| + var layoutInvalidationMap = {};
|
| + layoutTrackingEvents.forEach(function(layoutEvent) {
|
| + if (layoutInvalidationMap[layoutEvent.nodeId] === undefined)
|
| + layoutInvalidationMap[layoutEvent.nodeId] = [];
|
| + layoutInvalidationMap[layoutEvent.nodeId].push(layoutEvent);
|
| + });
|
| + this._paintingLayoutInvalidationMap[frameId] = layoutInvalidationMap;
|
| + }
|
| +}
|
|
|