From 4823dedc7181b707208a34eccdc01673d0fd5591 Mon Sep 17 00:00:00 2001 From: "loislo@chromium.org" Date: Wed, 8 Feb 2012 18:49:55 +0000 Subject: [PATCH] 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): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@107106 268f45cc-cd09-0410-ab3c-d52691b4dbfc --- Source/WebCore/ChangeLog | 44 +++++++ .../front-end/DetailedHeapshotGridNodes.js | 11 +- .../inspector/front-end/DetailedHeapshotView.js | 23 +++- Source/WebCore/inspector/front-end/HeapSnapshot.js | 131 +++++++++++++++++---- .../WebCore/inspector/front-end/heapProfiler.css | 4 + 5 files changed, 182 insertions(+), 31 deletions(-) diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index f54d169..738faba 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,47 @@ +2012-02-08 Ilya Tikhonovsky + + 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 Fix assertion in svg/dom/SVGStyledElement-pendingResource-crash.html diff --git a/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js b/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js index e127eb1..6621316 100644 --- a/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js +++ b/Source/WebCore/inspector/front-end/DetailedHeapshotGridNodes.js @@ -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; }, diff --git a/Source/WebCore/inspector/front-end/DetailedHeapshotView.js b/Source/WebCore/inspector/front-end/DetailedHeapshotView.js index 375ffd6..7db87f9 100644 --- a/Source/WebCore/inspector/front-end/DetailedHeapshotView.js +++ b/Source/WebCore/inspector/front-end/DetailedHeapshotView.js @@ -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(); diff --git a/Source/WebCore/inspector/front-end/HeapSnapshot.js b/Source/WebCore/inspector/front-end/HeapSnapshot.js index 0996adc..084ad0e 100644 --- a/Source/WebCore/inspector/front-end/HeapSnapshot.js +++ b/Source/WebCore/inspector/front-end/HeapSnapshot.js @@ -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) diff --git a/Source/WebCore/inspector/front-end/heapProfiler.css b/Source/WebCore/inspector/front-end/heapProfiler.css index 643fe7e..7f20296 100644 --- a/Source/WebCore/inspector/front-end/heapProfiler.css +++ b/Source/WebCore/inspector/front-end/heapProfiler.css @@ -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; -- 2.7.4