| Index: webkit/glue/devtools/js/heap_profiler_panel.js
|
| diff --git a/webkit/glue/devtools/js/heap_profiler_panel.js b/webkit/glue/devtools/js/heap_profiler_panel.js
|
| index 666f17e76a6827bbfb614d389cf87e42cb3c8a1a..ee80506717725a79ac23fcaeccb017a7d8f1f768 100644
|
| --- a/webkit/glue/devtools/js/heap_profiler_panel.js
|
| +++ b/webkit/glue/devtools/js/heap_profiler_panel.js
|
| @@ -99,6 +99,12 @@ WebInspector.HeapSnapshotView.prototype = {
|
| this.dataGrid.updateWidths();
|
| },
|
|
|
| + hide: function()
|
| + {
|
| + WebInspector.View.prototype.hide.call(this);
|
| + this._currentSearchResultIndex = -1;
|
| + },
|
| +
|
| resize: function()
|
| {
|
| if (this.dataGrid)
|
| @@ -123,6 +129,114 @@ WebInspector.HeapSnapshotView.prototype = {
|
| this.refreshVisibleData();
|
| },
|
|
|
| + _deleteSearchMatchedFlags: function(node)
|
| + {
|
| + delete node._searchMatchedConsColumn;
|
| + delete node._searchMatchedCountColumn;
|
| + delete node._searchMatchedSizeColumn;
|
| + delete node._searchMatchedCountDeltaColumn;
|
| + delete node._searchMatchedSizeDeltaColumn;
|
| + },
|
| +
|
| + searchCanceled: function()
|
| + {
|
| + if (this._searchResults) {
|
| + for (var i = 0; i < this._searchResults.length; ++i) {
|
| + var profileNode = this._searchResults[i].profileNode;
|
| + this._deleteSearchMatchedFlags(profileNode);
|
| + profileNode.refresh();
|
| + }
|
| + }
|
| +
|
| + delete this._searchFinishedCallback;
|
| + this._currentSearchResultIndex = -1;
|
| + this._searchResults = [];
|
| + },
|
| +
|
| + performSearch: function(query, finishedCallback)
|
| + {
|
| + // Call searchCanceled since it will reset everything we need before doing a new search.
|
| + this.searchCanceled();
|
| +
|
| + query = query.trimWhitespace();
|
| +
|
| + if (!query.length)
|
| + return;
|
| +
|
| + this._searchFinishedCallback = finishedCallback;
|
| +
|
| + var helper = WebInspector.HeapSnapshotView.SearchHelper;
|
| +
|
| + var operationAndNumber = helper.parseOperationAndNumber(query);
|
| + var operation = operationAndNumber[0];
|
| + var queryNumber = operationAndNumber[1];
|
| +
|
| + var percentUnits = helper.percents.test(query);
|
| + var megaBytesUnits = helper.megaBytes.test(query);
|
| + var kiloBytesUnits = helper.kiloBytes.test(query);
|
| + var bytesUnits = helper.bytes.test(query);
|
| +
|
| + var queryNumberBytes = (megaBytesUnits ? (queryNumber * 1024 * 1024) : (kiloBytesUnits ? (queryNumber * 1024) : queryNumber));
|
| +
|
| + function matchesQuery(heapSnapshotDataGridNode)
|
| + {
|
| + WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags(heapSnapshotDataGridNode);
|
| +
|
| + if (percentUnits) {
|
| + heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.countPercent, queryNumber);
|
| + heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.sizePercent, queryNumber);
|
| + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDeltaPercent, queryNumber);
|
| + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDeltaPercent, queryNumber);
|
| + } else if (megaBytesUnits || kiloBytesUnits || bytesUnits) {
|
| + heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.size, queryNumberBytes);
|
| + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDelta, queryNumberBytes);
|
| + } else {
|
| + heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.count, queryNumber);
|
| + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDelta, queryNumber);
|
| + }
|
| +
|
| + if (heapSnapshotDataGridNode.constructorName.hasSubstring(query, true))
|
| + heapSnapshotDataGridNode._searchMatchedConsColumn = true;
|
| +
|
| + if (heapSnapshotDataGridNode._searchMatchedConsColumn ||
|
| + heapSnapshotDataGridNode._searchMatchedCountColumn ||
|
| + heapSnapshotDataGridNode._searchMatchedSizeColumn ||
|
| + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn ||
|
| + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn) {
|
| + heapSnapshotDataGridNode.refresh();
|
| + return true;
|
| + }
|
| +
|
| + return false;
|
| + }
|
| +
|
| + var current = this.snapshotDataGridList.children[0];
|
| + var depth = 0;
|
| + var info = {};
|
| +
|
| + // The second and subsequent levels of heap snapshot nodes represent retainers,
|
| + // so recursive expansion will be infinite, since a graph is being traversed.
|
| + // So default to a recursion cap of 2 levels.
|
| + var maxDepth = 2;
|
| +
|
| + while (current) {
|
| + if (matchesQuery(current))
|
| + this._searchResults.push({ profileNode: current });
|
| + current = current.traverseNextNode(false, null, (depth >= maxDepth), info);
|
| + depth += info.depthChange;
|
| + }
|
| +
|
| + finishedCallback(this, this._searchResults.length);
|
| + },
|
| +
|
| + jumpToFirstSearchResult: WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult,
|
| + jumpToLastSearchResult: WebInspector.CPUProfileView.prototype.jumpToLastSearchResult,
|
| + jumpToNextSearchResult: WebInspector.CPUProfileView.prototype.jumpToNextSearchResult,
|
| + jumpToPreviousSearchResult: WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult,
|
| + showingFirstSearchResult: WebInspector.CPUProfileView.prototype.showingFirstSearchResult,
|
| + showingLastSearchResult: WebInspector.CPUProfileView.prototype.showingLastSearchResult,
|
| + _jumpToSearchResult: WebInspector.CPUProfileView.prototype._jumpToSearchResult,
|
| +
|
| refreshVisibleData: function()
|
| {
|
| var child = this.dataGrid.children[0];
|
| @@ -139,6 +253,15 @@ WebInspector.HeapSnapshotView.prototype = {
|
|
|
| this._resetDataGridList();
|
| this.refresh();
|
| +
|
| + if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
|
| + return;
|
| +
|
| + // The current search needs to be performed again. First negate out previous match
|
| + // count by calling the search finished callback with a negative number of matches.
|
| + // Then perform the search again with the same query and callback.
|
| + this._searchFinishedCallback(this, -this._searchResults.length);
|
| + this.performSearch(this.currentQuery, this._searchFinishedCallback);
|
| },
|
|
|
| _createSnapshotDataGridList: function()
|
| @@ -193,9 +316,8 @@ WebInspector.HeapSnapshotView.prototype = {
|
| {
|
| this.baseSnapshot = WebInspector.HeapSnapshotProfileType.snapshots[this.baseSelectElement.selectedIndex];
|
| var lastComparator = WebInspector.HeapSnapshotDataGridList.propertyComparator("size", false);
|
| - if (this.snapshotDataGridList) {
|
| + if (this.snapshotDataGridList)
|
| lastComparator = this.snapshotDataGridList.lastComparator;
|
| - }
|
| this.snapshotDataGridList = this._createSnapshotDataGridList();
|
| this.snapshotDataGridList.sort(lastComparator, true);
|
| },
|
| @@ -205,14 +327,14 @@ WebInspector.HeapSnapshotView.prototype = {
|
| var sortAscending = this.dataGrid.sortOrder === "ascending";
|
| var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier;
|
| var sortProperty = {
|
| - "cons": "constructorName",
|
| - "count": "count",
|
| - "size": "size",
|
| - "countDelta": this.showCountDeltaAsPercent ? "countDeltaPercent" : "countDelta",
|
| - "sizeDelta": this.showSizeDeltaAsPercent ? "sizeDeltaPercent" : "sizeDelta"
|
| + "cons": ["constructorName", null],
|
| + "count": ["count", null],
|
| + "size": ["size", "count"],
|
| + "countDelta": this.showCountDeltaAsPercent ? ["countDeltaPercent", null] : ["countDelta", null],
|
| + "sizeDelta": this.showSizeDeltaAsPercent ? ["sizeDeltaPercent", "countDeltaPercent"] : ["sizeDelta", "sizeDeltaPercent"]
|
| }[sortColumnIdentifier];
|
|
|
| - this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty, sortAscending));
|
| + this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty[0], sortProperty[1], sortAscending));
|
|
|
| this.refresh();
|
| },
|
| @@ -251,6 +373,40 @@ WebInspector.HeapSnapshotView.prototype = {
|
|
|
| WebInspector.HeapSnapshotView.prototype.__proto__ = WebInspector.View.prototype;
|
|
|
| +WebInspector.HeapSnapshotView.SearchHelper = {
|
| + // In comparators, we assume that a value from a node is passed as the first parameter.
|
| + operations: { LESS: function (a, b) { return a !== null && a < b; },
|
| + LESS_OR_EQUAL: function (a, b) { return a !== null && a <= b; },
|
| + EQUAL: function (a, b) { return a !== null && a == b; },
|
| + GREATER_OR_EQUAL: function (a, b) { return a !== null && a >= b; },
|
| + GREATER: function (a, b) { return a !== null && a > b; } },
|
| +
|
| + operationParsers: { LESS: /^<(\d+)/,
|
| + LESS_OR_EQUAL: /^<=(\d+)/,
|
| + GREATER_OR_EQUAL: /^>=(\d+)/,
|
| + GREATER: /^>(\d+)/ },
|
| +
|
| + parseOperationAndNumber: function(query)
|
| + {
|
| + var operations = WebInspector.HeapSnapshotView.SearchHelper.operations;
|
| + var parsers = WebInspector.HeapSnapshotView.SearchHelper.operationParsers;
|
| + for (var operation in parsers) {
|
| + var match = query.match(parsers[operation]);
|
| + if (match != null)
|
| + return [operations[operation], parseFloat(match[1])];
|
| + }
|
| + return [operations.EQUAL, parseFloat(query)];
|
| + },
|
| +
|
| + percents: /%$/,
|
| +
|
| + megaBytes: /MB$/i,
|
| +
|
| + kiloBytes: /KB$/i,
|
| +
|
| + bytes: /B$/i
|
| +}
|
| +
|
| WebInspector.HeapSummaryCalculator = function(total)
|
| {
|
| this.total = total;
|
| @@ -425,9 +581,8 @@ WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = {
|
| getTotalCount: function() {
|
| if (!this._count) {
|
| this._count = 0;
|
| - for (var i = 0, n = this.children.length; i < n; ++i) {
|
| + for (var i = 0, n = this.children.length; i < n; ++i)
|
| this._count += this.children[i].count;
|
| - }
|
| }
|
| return this._count;
|
| },
|
| @@ -435,9 +590,8 @@ WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = {
|
| getTotalSize: function() {
|
| if (!this._size) {
|
| this._size = 0;
|
| - for (var i = 0, n = this.children.length; i < n; ++i) {
|
| + for (var i = 0, n = this.children.length; i < n; ++i)
|
| this._size += this.children[i].size;
|
| - }
|
| }
|
| return this._size;
|
| },
|
| @@ -474,7 +628,7 @@ WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = {
|
| return Number.POSITIVE_INFINITY;
|
| },
|
|
|
| - getData: function(showSize)
|
| + get data()
|
| {
|
| var data = {};
|
|
|
| @@ -485,30 +639,42 @@ WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = {
|
| else
|
| data["count"] = this.count;
|
|
|
| - if (showSize) {
|
| + if (this.size !== null) {
|
| if (this.snapshotView.showSizeAsPercent)
|
| data["size"] = WebInspector.UIString("%.2f%%", this.sizePercent);
|
| else
|
| data["size"] = Number.bytesToString(this.size);
|
| - } else {
|
| + } else
|
| data["size"] = "";
|
| - }
|
|
|
| if (this.snapshotView.showCountDeltaAsPercent)
|
| data["countDelta"] = this.showDeltaAsPercent(this.countDeltaPercent);
|
| else
|
| data["countDelta"] = WebInspector.UIString("%s%d", this.signForDelta(this.countDelta), Math.abs(this.countDelta));
|
|
|
| - if (showSize) {
|
| + if (this.sizeDelta != null) {
|
| if (this.snapshotView.showSizeDeltaAsPercent)
|
| data["sizeDelta"] = this.showDeltaAsPercent(this.sizeDeltaPercent);
|
| else
|
| data["sizeDelta"] = WebInspector.UIString("%s%s", this.signForDelta(this.sizeDelta), Number.bytesToString(Math.abs(this.sizeDelta)));
|
| - } else {
|
| + } else
|
| data["sizeDelta"] = "";
|
| - }
|
|
|
| return data;
|
| + },
|
| +
|
| + createCell: function(columnIdentifier)
|
| + {
|
| + var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier);
|
| +
|
| + if ((columnIdentifier === "cons" && this._searchMatchedConsColumn) ||
|
| + (columnIdentifier === "count" && this._searchMatchedCountColumn) ||
|
| + (columnIdentifier === "size" && this._searchMatchedSizeColumn) ||
|
| + (columnIdentifier === "countDelta" && this._searchMatchedCountDeltaColumn) ||
|
| + (columnIdentifier === "sizeDelta" && this._searchMatchedSizeDeltaColumn))
|
| + cell.addStyleClass("highlight");
|
| +
|
| + return cell;
|
| }
|
| };
|
|
|
| @@ -536,13 +702,6 @@ WebInspector.HeapSnapshotDataGridNode = function(snapshotView, baseEntry, snapsh
|
| WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree);
|
| };
|
|
|
| -WebInspector.HeapSnapshotDataGridNode.prototype = {
|
| - get data()
|
| - {
|
| - return this.getData(true);
|
| - }
|
| -};
|
| -
|
| WebInspector.HeapSnapshotDataGridNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype;
|
|
|
| WebInspector.HeapSnapshotDataGridList = function(snapshotView, baseEntries, snapshotEntries)
|
| @@ -586,16 +745,19 @@ WebInspector.HeapSnapshotDataGridList.prototype = {
|
|
|
| WebInspector.HeapSnapshotDataGridList.propertyComparators = [{}, {}];
|
|
|
| -WebInspector.HeapSnapshotDataGridList.propertyComparator = function(property, isAscending)
|
| +WebInspector.HeapSnapshotDataGridList.propertyComparator = function(property, property2, isAscending)
|
| {
|
| - var comparator = this.propertyComparators[(isAscending ? 1 : 0)][property];
|
| + var propertyHash = property + '#' + property2;
|
| + var comparator = this.propertyComparators[(isAscending ? 1 : 0)][propertyHash];
|
| if (!comparator) {
|
| comparator = function(lhs, rhs) {
|
| var l = lhs[property], r = rhs[property];
|
| + if ((l === null || r === null) && property2 !== null)
|
| + l = lhs[property2], r = rhs[property2];
|
| var result = l < r ? -1 : (l > r ? 1 : 0);
|
| return isAscending ? result : -result;
|
| };
|
| - this.propertyComparators[(isAscending ? 1 : 0)][property] = comparator;
|
| + this.propertyComparators[(isAscending ? 1 : 0)][propertyHash] = comparator;
|
| }
|
| return comparator;
|
| };
|
| @@ -616,15 +778,21 @@ WebInspector.HeapSnapshotDataGridRetainerNode = function(snapshotView, baseEntry
|
| this.countDelta = this.count - this.baseCount;
|
| this.baseRetainers = this._calculateRetainers(this.snapshotView.baseSnapshot, baseEntry.clusters);
|
|
|
| - this.size = this.count; // This way, when sorting by sizes entries will be sorted by references count.
|
| + this.size = null;
|
| + this.sizeDelta = null;
|
|
|
| WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree);
|
| }
|
|
|
| WebInspector.HeapSnapshotDataGridRetainerNode.prototype = {
|
| - get data()
|
| + get sizePercent()
|
| + {
|
| + return null;
|
| + },
|
| +
|
| + get sizeDeltaPercent()
|
| {
|
| - return this.getData(false);
|
| + return null;
|
| },
|
|
|
| _calculateRetainers: function(snapshot, clusters) {
|
|
|