| 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 7284b459a7adaebb9cbfb8240d6949d8ea35a66b..8386730c6e755b2cdf6312e409833534c9f465f6 100644
|
| --- a/Source/devtools/front_end/timeline/TracingTimelineModel.js
|
| +++ b/Source/devtools/front_end/timeline/TracingTimelineModel.js
|
| @@ -31,6 +31,9 @@ WebInspector.TracingTimelineModel.RecordType = {
|
| DrawFrame: "DrawFrame",
|
| ScheduleStyleRecalculation: "ScheduleStyleRecalculation",
|
| RecalculateStyles: "RecalculateStyles",
|
| + StyleInvalidationTracking: "StyleInvalidationTracking",
|
| + LayoutInvalidationTracking: "LayoutInvalidationTracking",
|
| + PaintInvalidationTracking: "PaintInvalidationTracking",
|
| InvalidateLayout: "InvalidateLayout",
|
| Layout: "Layout",
|
| UpdateLayer: "UpdateLayer",
|
| @@ -116,8 +119,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)
|
| {
|
| @@ -144,6 +148,10 @@ WebInspector.TracingTimelineModel.prototype = {
|
| disabledByDefault("devtools.timeline.picture"),
|
| disabledByDefault("blink.graphics_context_annotations")]);
|
| }
|
| + if (captureInvalidationTracking) {
|
| + categoriesArray = categoriesArray.concat([
|
| + disabledByDefault("devtools.timeline.invalidationTracking")]);
|
| + }
|
| var categories = categoriesArray.join(",");
|
| this._startRecordingWithCategories(categories);
|
| },
|
| @@ -410,6 +418,7 @@ WebInspector.TracingTimelineModel.prototype = {
|
| this._sendRequestEvents = {};
|
| this._timerEvents = {};
|
| this._requestAnimationFrameEvents = {};
|
| + this._invalidationTracker = new WebInspector.InvalidationTracker();
|
| this._layoutInvalidate = {};
|
| this._lastScheduleStyleRecalculation = {};
|
| this._webSocketCreateEvents = {};
|
| @@ -522,6 +531,35 @@ 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,
|
| + rendererId: event.args.data.rendererId,
|
| + nodeId: event.args.data.nodeId,
|
| + nodeName: event.args.data.nodeName,
|
| + callstack: event.args.data.callstack
|
| + });
|
| + break;
|
| +
|
| + case recordTypes.PaintInvalidationTracking:
|
| + this._invalidationTracker.addPaintInvalidation({
|
| + frameId: event.args.data.frame,
|
| + rendererId: event.args.data.rendererId,
|
| + nodeId: event.args.data.nodeId,
|
| + nodeName: event.args.data.nodeName,
|
| + paintId: event.args.data.paintId
|
| + });
|
| + break;
|
| +
|
| case recordTypes.InvalidateLayout:
|
| // Consider style recalculation as a reason for layout invalidation,
|
| // but only if we had no earlier layout invalidation records.
|
| @@ -563,6 +601,7 @@ WebInspector.TracingTimelineModel.prototype = {
|
| break;
|
|
|
| case recordTypes.Paint:
|
| + this._invalidationTracker.updatePaint(event);
|
| event.highlightQuad = event.args["data"]["clip"];
|
| event.backendNodeId = event.args["data"]["nodeId"];
|
| var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer);
|
| @@ -1050,3 +1089,122 @@ WebInspector.TracingTimelineSaver.prototype = {
|
| this._writeNextChunk(stream);
|
| }
|
| }
|
| +
|
| +/**
|
| + * TODO: Properly doc this class.
|
| + *
|
| + * Track style, layout, and paint invalidation events.
|
| + */
|
| +WebInspector.InvalidationTracker = function()
|
| +{
|
| + // Invalidation events for the current frame.
|
| + this._styleTrackingEvents = {};
|
| + this._layoutTrackingEvents = {};
|
| + this._paintTrackingEvents = {};
|
| +
|
| + // FIXME: This is used to clear out the tracking event maps but it may
|
| + // not be sufficient if there are multiple frame ids.
|
| + this._lastFrameId = -1;
|
| +
|
| + this._didPaint = false;
|
| +}
|
| +
|
| +WebInspector.InvalidationTracker.prototype = {
|
| +
|
| + addStyleInvalidation: function(invalidation)
|
| + {
|
| + this._startNewFrameIfNeeded();
|
| +
|
| + var frameId = invalidation.frameId;
|
| + this._lastFrameId = frameId;
|
| +
|
| + if (!invalidation.nodeId) {
|
| + console.error('Style invalidation lacks node information.');
|
| + console.error(invalidation);
|
| + }
|
| +
|
| + if (this._styleTrackingEvents[frameId] === undefined)
|
| + this._styleTrackingEvents[frameId] = [];
|
| + this._styleTrackingEvents[frameId].push(invalidation);
|
| + },
|
| +
|
| + addLayoutInvalidation: function(invalidation)
|
| + {
|
| + this._startNewFrameIfNeeded();
|
| +
|
| + var frameId = invalidation.frameId;
|
| + this._lastFrameId = frameId;
|
| +
|
| + if (!invalidation.nodeId && !invalidation.rendererId) {
|
| + console.error('Layout invalidation lacks node or renderer information.');
|
| + console.error(invalidation);
|
| + }
|
| +
|
| + if (this._layoutTrackingEvents[frameId] === undefined)
|
| + this._layoutTrackingEvents[frameId] = [];
|
| + this._layoutTrackingEvents[frameId].push(invalidation);
|
| + },
|
| +
|
| + addPaintInvalidation: function(invalidation)
|
| + {
|
| + this._startNewFrameIfNeeded();
|
| +
|
| + var frameId = invalidation.frameId;
|
| + this._lastFrameId = frameId;
|
| +
|
| + if (!invalidation.nodeId && !invalidation.rendererId) {
|
| + console.error('Paint invalidation lacks node or renderer information.');
|
| + console.error(invalidation);
|
| + }
|
| +
|
| + if (this._paintTrackingEvents[frameId] === undefined)
|
| + this._paintTrackingEvents[frameId] = [];
|
| + this._paintTrackingEvents[frameId].push(invalidation);
|
| + },
|
| +
|
| + updatePaint: function(paintEvent)
|
| + {
|
| + this._didPaint = true;
|
| +
|
| + var frameId = paintEvent.args.data.frame;
|
| + var paintId = paintEvent.args.data.paintId;
|
| +
|
| + paintEvent.styleInvalidationTrackingEvents = [];
|
| + paintEvent.layoutInvalidationTrackingEvents = [];
|
| +
|
| + var styleTrackingEvents = this._styleTrackingEvents[frameId] || [];
|
| + var layoutTrackingEvents = this._layoutTrackingEvents[frameId] || [];
|
| + var paintTrackingEvents = this._paintTrackingEvents[frameId] || [];
|
| +
|
| + paintTrackingEvents.forEach(function(paintInvalidation) {
|
| + if (paintInvalidation.paintId != paintId)
|
| + return;
|
| +
|
| + // Collect style and layout invalidations that caused this paint.
|
| + styleTrackingEvents.forEach(function(invalidation) {
|
| + if (invalidation.nodeId == paintInvalidation.nodeId) {
|
| + if (paintEvent.styleInvalidationTrackingEvents.indexOf(invalidation) == -1)
|
| + paintEvent.styleInvalidationTrackingEvents.push(invalidation);
|
| + }
|
| + });
|
| + layoutTrackingEvents.forEach(function(invalidation) {
|
| + if (invalidation.nodeId == paintInvalidation.nodeId
|
| + || invalidation.rendererId == paintInvalidation.rendererId) {
|
| + if (paintEvent.layoutInvalidationTrackingEvents.indexOf(invalidation) == -1)
|
| + paintEvent.layoutInvalidationTrackingEvents.push(invalidation);
|
| + }
|
| + });
|
| + });
|
| + },
|
| +
|
| + // If there's a new frame, save off all current invalidations.
|
| + _startNewFrameIfNeeded: function()
|
| + {
|
| + if (!this._didPaint)
|
| + return;
|
| + this._styleTrackingEvents[this._lastFrameId] = undefined;
|
| + this._layoutTrackingEvents[this._lastFrameId] = undefined;
|
| + this._paintTrackingEvents[this._lastFrameId] = undefined;
|
| + this._didPaint = false;
|
| + }
|
| +}
|
|
|