Web Inspector: heap snapshot: implement Distance column in Object's retaining tree.
authorloislo@chromium.org <loislo@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Feb 2012 18:49:55 +0000 (18:49 +0000)
committerloislo@chromium.org <loislo@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Feb 2012 18:49:55 +0000 (18:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=78113

Retaining path list was replaced with Retaining tree some time ago.
But it was not so useful when we want to track the retaining path from an object to a DOM Window node.

Drive by fix: sort doesn't work in retaining tree panel.
Drive by fix: save/load child nodes doesn't work for the retaining tree panel.

Reviewed by Yury Semikhatsky.

* inspector/front-end/DetailedHeapshotGridNodes.js:
(WebInspector.HeapSnapshotObjectNode):
(WebInspector.HeapSnapshotObjectNode.prototype._childHashForEntity): save/load children fix
(WebInspector.HeapSnapshotObjectNode.prototype._childHashForNode): save/load children fix
(WebInspector.HeapSnapshotObjectNode.prototype.comparator):
(WebInspector.HeapSnapshotObjectNode.prototype._enhanceData):
* inspector/front-end/DetailedHeapshotView.js:
(WebInspector.HeapSnapshotContainmentDataGrid):
(WebInspector.HeapSnapshotRetainmentDataGrid):
(WebInspector.HeapSnapshotRetainmentDataGrid.prototype._sortFields):
* inspector/front-end/HeapSnapshot.js:
(WebInspector.HeapSnapshotRetainerEdge.prototype.set retainerIndex):
(WebInspector.HeapSnapshotRetainerEdge.prototype.set edgeIndex):
(WebInspector.HeapSnapshotRetainerEdge.prototype.get _node):
(WebInspector.HeapSnapshotRetainerEdge.prototype.get _edge):
(WebInspector.HeapSnapshotNode.prototype.get distanceToWindow):
(WebInspector.HeapSnapshot.prototype._init):
(WebInspector.HeapSnapshot.prototype._buildRetainers):
(WebInspector.HeapSnapshot.prototype._calculateObjectToWindowDistance):
(WebInspector.HeapSnapshot.prototype._bfs):
(WebInspector.HeapSnapshotEdgesProvider.prototype._serialize):
(WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareEdgeFieldName):
(WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareNodeField):
(WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareEdgeAndNode):
(WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareNodeAndEdge):
(WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareNodeAndNode):
(WebInspector.HeapSnapshotEdgesProvider.prototype.sort):
(WebInspector.HeapSnapshotNodesProvider.prototype._serialize):
* inspector/front-end/heapProfiler.css:
(.detailed-heapshot-view .data-grid td.distanceToWindow-column):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@107106 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js
Source/WebCore/inspector/front-end/DetailedHeapshotView.js
Source/WebCore/inspector/front-end/HeapSnapshot.js
Source/WebCore/inspector/front-end/heapProfiler.css

index f54d1694b1c7664c9cee3af3a08f738c05d1337e..738fabadb3afe1d6320cbb9d0708bb0d94fcc9f7 100644 (file)
@@ -1,3 +1,47 @@
+2012-02-08  Ilya Tikhonovsky  <loislo@chromium.org>
+
+        Web Inspector: heap snapshot: implement Distance column in Object's retaining tree.
+        https://bugs.webkit.org/show_bug.cgi?id=78113
+
+        Retaining path list was replaced with Retaining tree some time ago.
+        But it was not so useful when we want to track the retaining path from an object to a DOM Window node.
+
+        Drive by fix: sort doesn't work in retaining tree panel.
+        Drive by fix: save/load child nodes doesn't work for the retaining tree panel.
+
+        Reviewed by Yury Semikhatsky.
+
+        * inspector/front-end/DetailedHeapshotGridNodes.js:
+        (WebInspector.HeapSnapshotObjectNode):
+        (WebInspector.HeapSnapshotObjectNode.prototype._childHashForEntity): save/load children fix
+        (WebInspector.HeapSnapshotObjectNode.prototype._childHashForNode): save/load children fix
+        (WebInspector.HeapSnapshotObjectNode.prototype.comparator):
+        (WebInspector.HeapSnapshotObjectNode.prototype._enhanceData):
+        * inspector/front-end/DetailedHeapshotView.js:
+        (WebInspector.HeapSnapshotContainmentDataGrid):
+        (WebInspector.HeapSnapshotRetainmentDataGrid):
+        (WebInspector.HeapSnapshotRetainmentDataGrid.prototype._sortFields):
+        * inspector/front-end/HeapSnapshot.js:
+        (WebInspector.HeapSnapshotRetainerEdge.prototype.set retainerIndex):
+        (WebInspector.HeapSnapshotRetainerEdge.prototype.set edgeIndex):
+        (WebInspector.HeapSnapshotRetainerEdge.prototype.get _node):
+        (WebInspector.HeapSnapshotRetainerEdge.prototype.get _edge):
+        (WebInspector.HeapSnapshotNode.prototype.get distanceToWindow):
+        (WebInspector.HeapSnapshot.prototype._init):
+        (WebInspector.HeapSnapshot.prototype._buildRetainers):
+        (WebInspector.HeapSnapshot.prototype._calculateObjectToWindowDistance):
+        (WebInspector.HeapSnapshot.prototype._bfs):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype._serialize):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareEdgeFieldName):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareNodeField):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareEdgeAndNode):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareNodeAndEdge):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype.sort.compareNodeAndNode):
+        (WebInspector.HeapSnapshotEdgesProvider.prototype.sort):
+        (WebInspector.HeapSnapshotNodesProvider.prototype._serialize):
+        * inspector/front-end/heapProfiler.css:
+        (.detailed-heapshot-view .data-grid td.distanceToWindow-column):
+
 2012-02-08  Anders Carlsson  <andersca@apple.com>
 
         Fix assertion in svg/dom/SVGStyledElement-pendingResource-crash.html
index e127eb1f956dbffb391d10d8d937f2e66e143dec..66213163d46e5a830a12c5a8074744582ceb1f0c 100644 (file)
@@ -371,6 +371,7 @@ WebInspector.HeapSnapshotObjectNode = function(tree, isFromBaseSnapshot, edge, p
     this._referenceName = edge.name;
     this._referenceType = edge.type;
     this._propertyAccessor = edge.propertyAccessor;
+    this._distanceToWindow = edge.distanceToWindow;
     this.showRetainingEdges = tree.showRetainingEdges;
     this._isFromBaseSnapshot = isFromBaseSnapshot;
     this._provider = this._createProvider(!isFromBaseSnapshot ? tree.snapshot : tree.baseSnapshot, edge.nodeIndex, tree);
@@ -415,12 +416,14 @@ WebInspector.HeapSnapshotObjectNode.prototype = {
 
     _childHashForEntity: function(edge)
     {
-        return edge.type + "#" + edge.name;
+        var prefix = this.showRetainingEdges ? edge.node.id + "#" : "";
+        return prefix + edge.type + "#" + edge.name;
     },
 
     _childHashForNode: function(childNode)
     {
-        return childNode._referenceType + "#" + childNode._referenceName;
+        var prefix = this.showRetainingEdges ? childNode.snapshotNodeId + "#" : "";
+        return prefix + childNode._referenceType + "#" + childNode._referenceName;
     },
 
     comparator: function()
@@ -431,7 +434,8 @@ WebInspector.HeapSnapshotObjectNode.prototype = {
             object: ["!edgeName", sortAscending, "retainedSize", false],
             count: ["!edgeName", true, "retainedSize", false],
             shallowSize: ["selfSize", sortAscending, "!edgeName", true],
-            retainedSize: ["retainedSize", sortAscending, "!edgeName", true]
+            retainedSize: ["retainedSize", sortAscending, "!edgeName", true],
+            distanceToWindow: ["distanceToWindow", sortAscending, "_name", true]
         }[sortColumnIdentifier] || ["!edgeName", true, "retainedSize", false];
         return WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator(sortFields);
     },
@@ -460,6 +464,7 @@ WebInspector.HeapSnapshotObjectNode.prototype = {
         }
         data["object"].nameClass = nameClass;
         data["object"].name = name;
+        data["distanceToWindow"] = this._distanceToWindow;
         return data;
     },
 
index 375ffd6747f67e46ac27b280e0d5c8c4f6efd6b3..7db87f96260961f147fd27166ac4f34faf505072 100644 (file)
@@ -112,9 +112,9 @@ WebInspector.HeapSnapshotSortableDataGrid.prototype = {
 
 WebInspector.HeapSnapshotSortableDataGrid.prototype.__proto__ = WebInspector.DataGrid.prototype;
 
-WebInspector.HeapSnapshotContainmentDataGrid = function()
+WebInspector.HeapSnapshotContainmentDataGrid = function(columns)
 {
-    var columns = {
+    columns = columns || {
         object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
         shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
         retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true, sort: "descending" }
@@ -183,10 +183,27 @@ WebInspector.HeapSnapshotContainmentDataGrid.prototype.__proto__ = WebInspector.
 WebInspector.HeapSnapshotRetainmentDataGrid = function()
 {
     this.showRetainingEdges = true;
-    WebInspector.HeapSnapshotContainmentDataGrid.call(this);
+    var columns = {
+        object: { title: WebInspector.UIString("Object"), disclosure: true, sortable: true },
+        shallowSize: { title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true },
+        retainedSize: { title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true },
+        distanceToWindow: { title: WebInspector.UIString("Distance"), width: "80px", sortable: true, sort: "ascending" }
+    };
+    WebInspector.HeapSnapshotContainmentDataGrid.call(this, columns);
 }
 
 WebInspector.HeapSnapshotRetainmentDataGrid.prototype = {
+    _sortFields: function(sortColumn, sortAscending)
+    {
+        return {
+            object: ["_name", sortAscending, "_count", false],
+            count: ["_count", sortAscending, "_name", true],
+            shallowSize: ["_shallowSize", sortAscending, "_name", true],
+            retainedSize: ["_retainedSize", sortAscending, "_name", true],
+            distanceToWindow: ["_distanceToWindow", sortAscending, "_name", true]
+        }[sortColumn];
+    },
+
     reset: function()
     {
         this.removeChildren();
index 0996adc4d9f1d00aeed3dfa060bf3de2304fcd55..084ad0e28f13f432138980329a68c0f8662578e8 100644 (file)
@@ -436,17 +436,32 @@ WebInspector.HeapSnapshotRetainerEdge.prototype = {
     {
         if (newIndex !== this._retainerIndex) {
             this._retainerIndex = newIndex;
-            this._setupEdge();
+            this.edgeIndex = newIndex;
         }
     },
 
-    _setupEdge: function()
+    set edgeIndex(edgeIndex)
     {
-        var globalEdgeIndex = this._retainers.item(this._retainerIndex);
-        this._nodeIndex = this._snapshot._findNearestNodeIndex(globalEdgeIndex);
-        this._node = new WebInspector.HeapSnapshotNode(this._snapshot, this._nodeIndex);
-        var edgeIndex = globalEdgeIndex - this._nodeIndex - this._snapshot._firstEdgeOffset;
-        this._edge = new WebInspector.HeapSnapshotEdge(this._snapshot, this._node.rawEdges, edgeIndex);
+        this._globalEdgeIndex = this._retainers.item(edgeIndex);
+        this._nodeIndex = this._snapshot._findNearestNodeIndex(this._globalEdgeIndex);
+        delete this._edgeInstance;
+        delete this._nodeInstance;
+    },
+
+    get _node()
+    {
+        if (!this._nodeInstance)
+            this._nodeInstance = new WebInspector.HeapSnapshotNode(this._snapshot, this._nodeIndex);
+        return this._nodeInstance;
+    },
+
+    get _edge()
+    {
+        if (!this._edgeInstance) {
+            var edgeIndex = this._globalEdgeIndex - this._nodeIndex - this._snapshot._firstEdgeOffset;
+            this._edgeInstance = new WebInspector.HeapSnapshotEdge(this._snapshot, this._node.rawEdges, edgeIndex);
+        }
+        return this._edgeInstance;
     },
 
     toString: function()
@@ -511,6 +526,11 @@ WebInspector.HeapSnapshotNode.prototype = {
         return !!(flags & this._snapshot._nodeFlags.canBeQueried);
     },
 
+    get distanceToWindow()
+    {
+        return this._snapshot._distancesToWindow[this.nodeIndex];
+    },
+
     get className()
     {
         switch (this.type) {
@@ -731,6 +751,7 @@ WebInspector.HeapSnapshot.prototype = {
             detachedDOMTreeNode: 2,
         };
 
+        this._distancesToWindow = [];
         this._markInvisibleEdges();
     },
 
@@ -917,6 +938,49 @@ WebInspector.HeapSnapshot.prototype = {
                      dataCallback(indexCallback(retIndex), node.nodeIndex + this._firstEdgeOffset + edge.edgeIndex);
                  }
              }).bind(this));
+        this._calculateObjectToWindowDistance();
+    },
+
+    _calculateObjectToWindowDistance: function()
+    {
+        this._distancesToWindow = new Array(this.nodeCount);
+
+        // bfs for DOMWindow roots
+        var list = [];
+        for (var iter = this.rootNode.edges; iter.hasNext(); iter.next()) {
+            if (iter.edge.node.isDOMWindow) {
+                list.push(iter.edge.node);
+                this._distancesToWindow[iter.edge.node.nodeIndex] = 0;
+            }
+        }
+        this._bfs(list);
+
+        // bfs for root
+        list = [];
+        list.push(this.rootNode);
+        this._distancesToWindow[this.rootNode.nodeIndex] = 0;
+        this._bfs(list);
+    },
+
+    _bfs: function(list)
+    {
+        var index = 0;
+        while (index < list.length) {
+            var node = list[index++]; // shift generates too much garbage.
+            if (index > 100000) {
+                list = list.slice(index);
+                index = 0;
+            }
+            var distance = this._distancesToWindow[node.nodeIndex] + 1;
+            for (var iter = node.edges; iter.hasNext(); iter.next()) {
+                var edge = iter.edge;
+                var childNode = edge.node;
+                if (typeof this._distancesToWindow[childNode.nodeIndex] !== "undefined")
+                    continue;
+                this._distancesToWindow[childNode.nodeIndex] = distance;
+                list.push(childNode);
+            }
+        }
     },
 
     _buildAggregates: function(filter)
@@ -1352,7 +1416,14 @@ WebInspector.HeapSnapshotEdgesProvider = function(snapshot, nodeIndex, filter, i
 WebInspector.HeapSnapshotEdgesProvider.prototype = {
     _serialize: function(edge)
     {
-        return {name: edge.name, propertyAccessor: edge.toString(), node: WebInspector.HeapSnapshotNodesProvider.prototype._serialize(edge.node), nodeIndex: edge.nodeIndex, type: edge.type};
+        return {
+            name: edge.name,
+            propertyAccessor: edge.toString(),
+            node: WebInspector.HeapSnapshotNodesProvider.prototype._serialize(edge.node),
+            nodeIndex: edge.nodeIndex,
+            type: edge.type,
+            distanceToWindow: edge.node.distanceToWindow
+        };
     },
 
     sort: function(comparator, leftBound, rightBound, count)
@@ -1367,7 +1438,7 @@ WebInspector.HeapSnapshotEdgesProvider.prototype = {
         var nodeA = new WebInspector.HeapSnapshotNode(this.snapshot);
         var nodeB = new WebInspector.HeapSnapshotNode(this.snapshot);
 
-        function sortByEdgeFieldName(ascending, indexA, indexB)
+        function compareEdgeFieldName(ascending, indexA, indexB)
         {
             edgeA.edgeIndex = indexA;
             edgeB.edgeIndex = indexB;
@@ -1380,45 +1451,47 @@ WebInspector.HeapSnapshotEdgesProvider.prototype = {
             return ascending ? result : -result;
         }
 
-        function sortByNodeField(fieldName, ascending, indexA, indexB)
+        function compareNodeField(fieldName, ascending, indexA, indexB)
         {
             edgeA.edgeIndex = indexA;
-            edgeB.edgeIndex = indexB;
             nodeA.nodeIndex = edgeA.nodeIndex;
-            nodeB.nodeIndex = edgeB.nodeIndex;
             var valueA = nodeA[fieldName];
+
+            edgeB.edgeIndex = indexB;
+            nodeB.nodeIndex = edgeB.nodeIndex;
             var valueB = nodeB[fieldName];
+
             var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0);
             return ascending ? result : -result;
         }
 
-        function sortByEdgeAndNode(indexA, indexB) {
-            var result = sortByEdgeFieldName(ascending1, indexA, indexB);
+        function compareEdgeAndNode(indexA, indexB) {
+            var result = compareEdgeFieldName(ascending1, indexA, indexB);
             if (result === 0)
-                result = sortByNodeField(fieldName2, ascending2, indexA, indexB);
+                result = compareNodeField(fieldName2, ascending2, indexA, indexB);
             return result;
         }
 
-        function sortByNodeAndEdge(indexA, indexB) {
-            var result = sortByNodeField(fieldName1, ascending1, indexA, indexB);
+        function compareNodeAndEdge(indexA, indexB) {
+            var result = compareNodeField(fieldName1, ascending1, indexA, indexB);
             if (result === 0)
-                result = sortByEdgeFieldName(ascending2, indexA, indexB);
+                result = compareEdgeFieldName(ascending2, indexA, indexB);
             return result;
         }
 
-        function sortByNodeAndNode(indexA, indexB) {
-            var result = sortByNodeField(fieldName1, ascending1, indexA, indexB);
+        function compareNodeAndNode(indexA, indexB) {
+            var result = compareNodeField(fieldName1, ascending1, indexA, indexB);
             if (result === 0)
-                result = sortByNodeField(fieldName2, ascending2, indexA, indexB);
+                result = compareNodeField(fieldName2, ascending2, indexA, indexB);
             return result;
         }
 
         if (fieldName1 === "!edgeName")
-            this._iterationOrder.sortRange(sortByEdgeAndNode, leftBound, rightBound, count);
+            this._iterationOrder.sortRange(compareEdgeAndNode, leftBound, rightBound, count);
         else if (fieldName2 === "!edgeName")
-            this._iterationOrder.sortRange(sortByNodeAndEdge, leftBound, rightBound, count);
+            this._iterationOrder.sortRange(compareNodeAndEdge, leftBound, rightBound, count);
         else
-            this._iterationOrder.sortRange(sortByNodeAndNode, leftBound, rightBound, count);
+            this._iterationOrder.sortRange(compareNodeAndNode, leftBound, rightBound, count);
     }
 };
 
@@ -1433,7 +1506,15 @@ WebInspector.HeapSnapshotNodesProvider = function(snapshot, filter, nodeIndexes)
 WebInspector.HeapSnapshotNodesProvider.prototype = {
     _serialize: function(node)
     {
-        return {id: node.id, name: node.name, nodeIndex: node.nodeIndex, retainedSize: node.retainedSize, selfSize: node.selfSize, type: node.type, flags: node.flags};
+        return {
+            id: node.id,
+            name: node.name,
+            nodeIndex: node.nodeIndex,
+            retainedSize: node.retainedSize,
+            selfSize: node.selfSize,
+            type: node.type,
+            flags: node.flags
+        };
     },
 
     sort: function(comparator, leftBound, rightBound, count)
index 643fe7ecbb5da4a304851bb58d5dabe77e101abc..7f20296c1acb9010ed97e18a9f9590f552bbaaf0 100644 (file)
@@ -115,6 +115,10 @@ body.inactive .heap-snapshot-sidebar-tree-item.wait.selected .icon {
     text-align: right;
 }
 
+.detailed-heapshot-view .data-grid td.distanceToWindow-column {
+    text-align: right;
+}
+
 .detailed-heapshot-view .data-grid span.percent-column {
     color: grey;
     width: 42px;