Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1344)

Unified Diff: Source/devtools/front_end/timeline/TracingTimelineModel.js

Issue 654013003: Implement invalidation tracking in devtools (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 2cd5efd8681d9011c0faab9ec83ef93ac7d996b8..fa2894db584fef2d2fc56e0792f892f09b78a228 100644
--- a/Source/devtools/front_end/timeline/TracingTimelineModel.js
+++ b/Source/devtools/front_end/timeline/TracingTimelineModel.js
@@ -47,6 +47,11 @@ WebInspector.TracingTimelineModel.RecordType = {
ScrollLayer: "ScrollLayer",
CompositeLayers: "CompositeLayers",
+ StyleRecalcInvalidationTracking: "StyleRecalcInvalidationTracking",
+ LayoutInvalidationTracking: "LayoutInvalidationTracking",
+ LayerInvalidationTracking: "LayerInvalidationTracking",
+ PaintInvalidationTracking: "PaintInvalidationTracking",
+
ParseHTML: "ParseHTML",
TimerInstall: "TimerInstall",
@@ -138,7 +143,9 @@ WebInspector.TracingTimelineModel.prototype = {
WebInspector.TracingModel.ConsoleEventCategory
];
if (captureCauses) {
- categoriesArray.push(disabledByDefault("devtools.timeline.stack"));
+ categoriesArray = categoriesArray.concat([
+ disabledByDefault("devtools.timeline.stack"),
+ disabledByDefault("devtools.timeline.invalidationTracking")]);
caseq 2014/10/15 16:24:52 make the latter conditional on Runtime.experiments
pdr. 2014/10/16 07:46:47 Great catch. This was a bad merge on my part :(
if (Runtime.experiments.isEnabled("timelineJSCPUProfile")) {
this._jsProfilerStarted = true;
this._currentTarget = WebInspector.context.flavor(WebInspector.Target);
@@ -475,6 +482,7 @@ WebInspector.TracingTimelineModel.prototype = {
this._sendRequestEvents = {};
this._timerEvents = {};
this._requestAnimationFrameEvents = {};
+ this._invalidationTracker = new WebInspector.InvalidationTracker();
this._layoutInvalidate = {};
this._lastScheduleStyleRecalculation = {};
this._webSocketCreateEvents = {};
@@ -591,6 +599,46 @@ WebInspector.TracingTimelineModel.prototype = {
this._lastRecalculateStylesEvent = event;
break;
+ case recordTypes.StyleRecalcInvalidationTracking:
+ this._invalidationTracker.addInvalidation({
+ type: recordTypes.StyleRecalcInvalidationTracking,
+ frameId: event.args.data.frame,
caseq 2014/10/15 16:24:53 here and below: we use object["field"] syntax unle
+ nodeId: event.args.data.nodeId,
+ nodeName: event.args.data.nodeName,
+ reason: event.args.data.reason,
+ callstack: event.args.data.callstack
+ });
+ break;
+
+ case recordTypes.LayoutInvalidationTracking:
+ this._invalidationTracker.addInvalidation({
+ type: recordTypes.LayoutInvalidationTracking,
+ frameId: event.args.data.frame,
+ nodeId: event.args.data.nodeId,
+ nodeName: event.args.data.nodeName,
+ callstack: event.args.data.callstack
+ });
+ break;
+
+ case recordTypes.LayerInvalidationTracking:
+ this._invalidationTracker.addInvalidation({
+ type: recordTypes.LayerInvalidationTracking,
+ frameId: event.args.data.frame,
+ paintId: event.args.data.paintId,
+ reason: event.args.data.reason
+ });
+ break;
+
+ case recordTypes.PaintInvalidationTracking:
+ this._invalidationTracker.addInvalidation({
+ type: recordTypes.PaintInvalidationTracking,
+ frameId: event.args.data.frame,
+ 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.
@@ -635,6 +683,7 @@ WebInspector.TracingTimelineModel.prototype = {
break;
case recordTypes.Paint:
+ this._invalidationTracker.didPaint(event);
event.highlightQuad = event.args["data"]["clip"];
event.backendNodeId = event.args["data"]["nodeId"];
var layerUpdateEvent = this._findAncestorEvent(recordTypes.UpdateLayer);
@@ -1103,3 +1152,88 @@ WebInspector.TracingTimelineSaver.prototype = {
*/
onError: function(reader, event) { },
}
+
+/**
caseq 2014/10/15 16:24:53 @constructor
+ * Track invalidation events across frames.
+ */
+WebInspector.InvalidationTracker = function()
caseq 2014/10/15 16:24:53 I wonder if we should make it a part of _processEv
pdr. 2014/10/16 07:46:48 Would you mind if we punt on this for now? I'm not
+{
+ this._invalidationEvents = [];
+ this._lastPaintWithLayer = undefined;
+ this._didPaint = false;
+}
+
+WebInspector.InvalidationTracker.prototype = {
+
+ addInvalidation: function(invalidation)
caseq 2014/10/15 16:24:53 please annotate!
+ {
+ this._startNewFrameIfNeeded();
+ if (!invalidation.nodeId && !invalidation.paintId) {
+ console.error('Invalidation lacks node information.');
caseq 2014/10/15 16:24:53 double quotes, please!
+ console.error(invalidation);
+ }
+
+ // Record the paintIds for style recalc or layout invalidations.
+ // FIXME: This O(n^2) loop could be optimized with a map.
+ if (invalidation.type == WebInspector.TracingTimelineModel.RecordType.PaintInvalidationTracking) {
+ this._invalidationEvents.forEach(function(invalidationToUpdate) {
+ if (invalidationToUpdate.nodeId != invalidation.nodeId)
caseq 2014/10/15 16:24:52 !==
+ return;
+ switch (invalidationToUpdate.type) {
caseq 2014/10/15 16:24:52 Can we defer making it a "switch" till we have to
pdr. 2014/10/16 07:46:48 Looks like 'switch' and 'if/else' are the same the
+ case WebInspector.TracingTimelineModel.RecordType.StyleRecalcInvalidationTracking:
+ invalidationToUpdate.paintId = invalidation.paintId;
+ break;
+ case WebInspector.TracingTimelineModel.RecordType.LayoutInvalidationTracking:
+ invalidationToUpdate.paintId = invalidation.paintId;
+ break;
+ }
+ });
+ } else {
+ this._invalidationEvents.push(invalidation);
+ }
+ },
+
+ didPaint: function(paintEvent)
caseq 2014/10/15 16:24:53 please annotate.
+ {
+ this._didPaint = true;
+
+ // If a paint doesn't have a corresponding graphics layer id, it paints into it's parent so
caseq 2014/10/15 16:24:53 s/it's/its/
pdr. 2014/10/16 07:46:47 Stupid English! Fixed.
+ // add an effectivePaintId to these events.
+ // FIXME: The parent layer is assumed to be the last paint event that had a layerId set. Is that right?
caseq 2014/10/15 16:24:53 Apparently yes, as we never have nested layer pain
+ var layerId = paintEvent.args.data.layerId;
caseq 2014/10/15 16:24:53 paintEvent.args["data"][layerId"]
+ if (layerId)
+ this._lastPaintWithLayer = paintEvent;
+
+ if (!this._lastPaintWithLayer) {
+ console.error("Failed to find the paint container for a paint event.");
+ return;
+ }
+
+ var effectivePaintId = this._lastPaintWithLayer.args.data.nodeId;
+ this._processPaint(paintEvent, effectivePaintId);
+ },
+
+ _processPaint: function(paintEvent, effectivePaintId)
caseq 2014/10/15 16:24:53 inline into didPaint?
+ {
+ var frameId = paintEvent.args.data.frame;
+
+ this._invalidationEvents.forEach(function(invalidation) {
+ if (invalidation.paintId == effectivePaintId && invalidation.frameId == frameId) {
caseq 2014/10/15 16:24:52 s/==/===/g
+ if (!paintEvent.invalidationTrackingEvents)
+ paintEvent.invalidationTrackingEvents = [];
+ paintEvent.invalidationTrackingEvents.push(invalidation);
+ }
+ });
+ },
+
+ _startNewFrameIfNeeded: function()
+ {
+ if (!this._didPaint)
+ return;
+
+ // Prepare for the next frame.
+ this._invalidationEvents = [];
caseq 2014/10/15 16:24:52 Looks like if we add new state variable, we'll be
pdr. 2014/10/16 07:46:48 Great point. Factored out into _initializePerFrame
+ this._lastPaintWithLayer = undefined;
+ this._didPaint = false;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698