diff options
author | mnaganov@chromium.org <mnaganov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-14 13:05:51 +0000 |
---|---|---|
committer | mnaganov@chromium.org <mnaganov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-14 13:05:51 +0000 |
commit | fbcd92d686f77817f43c262d773ca523bf16d9ae (patch) | |
tree | cb94f783b328154916ae9fcfaf0c1ccdc6b32988 /webkit | |
parent | 3244c8cb2fd6f976c7d4c7da181347dfceab9f70 (diff) | |
download | chromium_src-fbcd92d686f77817f43c262d773ca523bf16d9ae.zip chromium_src-fbcd92d686f77817f43c262d773ca523bf16d9ae.tar.gz chromium_src-fbcd92d686f77817f43c262d773ca523bf16d9ae.tar.bz2 |
DevTools: implement comparison of heap snapshots in Heap profiler.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/164557
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@23434 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/devtools/js/devtools_host_stub.js | 24 | ||||
-rw-r--r-- | webkit/glue/devtools/js/heap_profiler_panel.js | 222 | ||||
-rw-r--r-- | webkit/glue/devtools/js/profiler_processor.js | 6 | ||||
-rw-r--r-- | webkit/glue/devtools_strings.grd | 47 |
4 files changed, 250 insertions, 49 deletions
diff --git a/webkit/glue/devtools/js/devtools_host_stub.js b/webkit/glue/devtools/js/devtools_host_stub.js index 783d29c..b53c990 100644 --- a/webkit/glue/devtools/js/devtools_host_stub.js +++ b/webkit/glue/devtools/js/devtools_host_stub.js @@ -14,6 +14,7 @@ RemoteDebuggerAgentStub = function() { this.activeProfilerModules_ = devtools.DebuggerAgent.ProfilerModules.PROFILER_MODULE_NONE; this.profileLogPos_ = 0; + this.heapProfSample_ = 0; this.heapProfLog_ = ''; }; @@ -39,9 +40,16 @@ RemoteDebuggerAgentStub.prototype.StartProfiling = function(modules) { this.heapProfLog_ += 'heap-sample-begin,"Heap","allocated",' + (new Date()).getTime() + '\n' + - 'heap-sample-stats,"Heap","allocated",10000,1000\n' + - 'heap-js-cons-item,"foo",10,1000\n' + - 'heap-js-cons-item,"bar",20,2000\n' + + 'heap-sample-stats,"Heap","allocated",10000,1000\n'; + var sample = RemoteDebuggerAgentStub.HeapSamples[this.heapProfSample_]; + if (++this.heapProfSample_ == RemoteDebuggerAgentStub.HeapSamples.length) + this.heapProfSample_ = 0; + for (var obj in sample) { + this.heapProfLog_ += + 'heap-js-cons-item,"' + obj + '",' + sample[obj][0] + + ',' + sample[obj][1] + '\n'; + } + this.heapProfLog_ += 'heap-sample-end,"Heap","allocated"\n'; } } else { @@ -186,6 +194,16 @@ RemoteDebuggerAgentStub.ProfilerLogBuffer = 'profiler,pause\n'; +RemoteDebuggerAgentStub.HeapSamples = [ + {foo: [1, 100], bar: [20, 2000]}, + {foo: [2000, 200000], bar: [10, 1000]}, + {foo: [15, 1500], bar: [15, 1500]}, + {bar: [20, 2000]}, + {foo: [15, 1500], bar: [15, 1500]}, + {bar: [20, 2000], baz: [15, 1500]} +]; + + /** * @constructor */ diff --git a/webkit/glue/devtools/js/heap_profiler_panel.js b/webkit/glue/devtools/js/heap_profiler_panel.js index 6db8a06..49f34b3 100644 --- a/webkit/glue/devtools/js/heap_profiler_panel.js +++ b/webkit/glue/devtools/js/heap_profiler_panel.js @@ -83,13 +83,16 @@ WebInspector.HeapProfilerPanel.prototype = { addSnapshot: function(snapshot) { this._snapshots.push(snapshot); + snapshot.list = this._snapshots; + snapshot.listIndex = this._snapshots.length - 1; - var sidebarParent = this.sidebarTree; var snapshotsTreeElement = new WebInspector.HeapSnapshotSidebarTreeElement(snapshot); snapshotsTreeElement.small = false; snapshot._snapshotsTreeElement = snapshotsTreeElement; - sidebarParent.appendChild(snapshotsTreeElement); + this.sidebarTree.appendChild(snapshotsTreeElement); + + this.dispatchEventToListeners("snapshot added"); }, showSnapshot: function(snapshot) { @@ -118,7 +121,7 @@ WebInspector.HeapProfilerPanel.prototype = { if (!snapshot) return null; if (!snapshot._snapshotView) - snapshot._snapshotView = new WebInspector.HeapSnapshotView(snapshot); + snapshot._snapshotView = new WebInspector.HeapSnapshotView(this, snapshot); return snapshot._snapshotView; }, @@ -177,18 +180,25 @@ WebInspector.HeapProfilerPanel.prototype = { WebInspector.HeapProfilerPanel.prototype.__proto__ = WebInspector.Panel.prototype; -WebInspector.HeapSnapshotView = function(snapshot) +WebInspector.HeapSnapshotView = function(parent, snapshot) { WebInspector.View.call(this); this.element.addStyleClass("heap-snapshot-view"); + this.parent = parent; + this.parent.addEventListener("snapshot added", this._updateBaseOptions, this); + this.showCountAsPercent = true; this.showSizeAsPercent = true; + this.showCountDeltaAsPercent = true; + this.showSizeDeltaAsPercent = true; var columns = { "cons": { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true }, "count": { title: WebInspector.UIString("Count"), width: "54px", sortable: true }, - "size": { title: WebInspector.UIString("Size"), width: "72px", sort: "descending", sortable: true } }; + "size": { title: WebInspector.UIString("Size"), width: "72px", sort: "descending", sortable: true }, + "countDelta": { title: WebInspector.UIString("\xb1 Count"), width: "72px", sortable: true }, + "sizeDelta": { title: WebInspector.UIString("\xb1 Size"), width: "72px", sortable: true } }; this.dataGrid = new WebInspector.DataGrid(columns); this.dataGrid.addEventListener("sorting changed", this._sortData, this); @@ -196,11 +206,18 @@ WebInspector.HeapSnapshotView = function(snapshot) this.element.appendChild(this.dataGrid.element); this.snapshot = snapshot; - this.snapshotDataGridList = this.createSnapshotDataGridList(); - this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator("objectsSize", false)); - this.percentButton = document.createElement("button"); - this.percentButton.className = "percent-time-status-bar-item status-bar-item"; + this.baseSelectElement = document.createElement("select"); + this.baseSelectElement.className = "status-bar-item"; + this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false); + this._updateBaseOptions(); + if (this.snapshot.listIndex > 0) + this.baseSelectElement.selectedIndex = this.snapshot.listIndex - 1; + else + this.baseSelectElement.selectedIndex = this.snapshot.listIndex; + this._resetDataGridList(); + + this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item status-bar-item"); this.percentButton.addEventListener("click", this._percentClicked.bind(this), false); this.refresh(); @@ -211,7 +228,7 @@ WebInspector.HeapSnapshotView = function(snapshot) WebInspector.HeapSnapshotView.prototype = { get statusBarItems() { - return [this.percentButton]; + return [this.baseSelectElement, this.percentButton.element]; }, get snapshot() @@ -224,11 +241,16 @@ WebInspector.HeapSnapshotView.prototype = { this._snapshot = snapshot; }, - createSnapshotDataGridList: function() + show: function(parentElement) { - if (!this._snapshotDataGridList) - this._snapshotDataGridList = new WebInspector.HeapSnapshotDataGridList(this, this.snapshot.entries); - return this._snapshotDataGridList; + WebInspector.View.prototype.show.call(this, parentElement); + this.dataGrid.updateWidths(); + }, + + resize: function() + { + if (this.dataGrid) + this.dataGrid.updateWidths(); }, refresh: function() @@ -256,19 +278,40 @@ WebInspector.HeapSnapshotView.prototype = { } }, + _changeBase: function() { + if (this.baseSnapshot === this.snapshot.list[this.baseSelectElement.selectedIndex]) + return; + + this._resetDataGridList(); + this.refresh(); + }, + + _createSnapshotDataGridList: function() + { + if (this._snapshotDataGridList) + delete this._snapshotDataGridList; + + this._snapshotDataGridList = new WebInspector.HeapSnapshotDataGridList(this, this.baseSnapshot.entries, this.snapshot.entries); + return this._snapshotDataGridList; + }, + _mouseDownInDataGrid: function(event) { if (event.detail < 2) return; var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); - if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("size-column"))) + if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("size-column") && !cell.hasStyleClass("countDelta-column") && !cell.hasStyleClass("sizeDelta-column"))) return; if (cell.hasStyleClass("count-column")) this.showCountAsPercent = !this.showCountAsPercent; else if (cell.hasStyleClass("size-column")) this.showSizeAsPercent = !this.showSizeAsPercent; + else if (cell.hasStyleClass("countDelta-column")) + this.showCountDeltaAsPercent = !this.showCountDeltaAsPercent; + else if (cell.hasStyleClass("sizeDelta-column")) + this.showSizeDeltaAsPercent = !this.showSizeDeltaAsPercent; this.refreshShowAsPercents(); @@ -276,14 +319,32 @@ WebInspector.HeapSnapshotView.prototype = { event.stopPropagation(); }, + get _isShowingAsPercent() + { + return this.showCountAsPercent && this.showSizeAsPercent && this.showCountDeltaAsPercent && this.showSizeDeltaAsPercent; + }, + _percentClicked: function(event) { - var currentState = this.showCountAsPercent && this.showSizeAsPercent; + var currentState = this._isShowingAsPercent; this.showCountAsPercent = !currentState; this.showSizeAsPercent = !currentState; + this.showCountDeltaAsPercent = !currentState; + this.showSizeDeltaAsPercent = !currentState; this.refreshShowAsPercents(); }, + _resetDataGridList: function() + { + this.baseSnapshot = this.snapshot.list[this.baseSelectElement.selectedIndex]; + var lastComparator = WebInspector.HeapSnapshotDataGridList.propertyComparator("objectsSize", false); + if (this.snapshotDataGridList) { + lastComparator = this.snapshotDataGridList.lastComparator; + } + this.snapshotDataGridList = this._createSnapshotDataGridList(); + this.snapshotDataGridList.sort(lastComparator, true); + }, + _sortData: function() { var sortAscending = this.dataGrid.sortOrder === "ascending"; @@ -291,7 +352,9 @@ WebInspector.HeapSnapshotView.prototype = { var sortProperty = { "cons": "constructorName", "count": "objectsCount", - "size": "objectsSize" + "size": "objectsSize", + "countDelta": this.showCountDeltaAsPercent ? "objectsCountDeltaPercent" : "objectsCountDelta", + "sizeDelta": this.showSizeDeltaAsPercent ? "objectsSizeDeltaPercent" : "objectsSizeDelta" }[sortColumnIdentifier]; this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty, sortAscending)); @@ -299,14 +362,27 @@ WebInspector.HeapSnapshotView.prototype = { this.refresh(); }, + _updateBaseOptions: function() + { + // We're assuming that snapshots can only be added. + if (this.baseSelectElement.length == this.snapshot.list.length) + return; + + for (var i = this.baseSelectElement.length, n = this.snapshot.list.length; i < n; ++i) { + var baseOption = document.createElement("option"); + baseOption.label = WebInspector.UIString("Compared to %s", this.snapshot.list[i].title); + this.baseSelectElement.appendChild(baseOption); + } + }, + _updatePercentButton: function() { - if (this.showCountAsPercent && this.showSizeAsPercent) { - this.percentButton.title = WebInspector.UIString("Show absolute counts and sized."); - this.percentButton.addStyleClass("toggled-on"); + if (this._isShowingAsPercent) { + this.percentButton.title = WebInspector.UIString("Show absolute counts and sizes."); + this.percentButton.toggled = true; } else { this.percentButton.title = WebInspector.UIString("Show counts and sizes as percentages."); - this.percentButton.removeStyleClass("toggled-on"); + this.percentButton.toggled = false; } } }; @@ -316,7 +392,7 @@ WebInspector.HeapSnapshotView.prototype.__proto__ = WebInspector.View.prototype; WebInspector.HeapSnapshotSidebarTreeElement = function(snapshot) { this.snapshot = snapshot; - this._snapshotNumber = snapshot.number; + this.snapshot.title = WebInspector.UIString("Snapshot %d", this.snapshot.number); WebInspector.SidebarTreeElement.call(this, "heap-snapshot-sidebar-tree-item", "", "", snapshot, false); @@ -333,7 +409,7 @@ WebInspector.HeapSnapshotSidebarTreeElement.prototype = { { if (this._mainTitle) return this._mainTitle; - return WebInspector.UIString("Snapshot %d", this._snapshotNumber); + return this.snapshot.title; }, set mainTitle(x) @@ -346,7 +422,7 @@ WebInspector.HeapSnapshotSidebarTreeElement.prototype = { { if (this._subTitle) return this._subTitle; - return WebInspector.UIString("Used %s of %s (%.0f%)", Number.bytesToString(this.snapshot.used, null, false), Number.bytesToString(this.snapshot.capacity, null, false), this.snapshot.used / this.snapshot.capacity * 100.0); + return WebInspector.UIString("Used %s of %s (%.0f%%)", Number.bytesToString(this.snapshot.used, null, false), Number.bytesToString(this.snapshot.capacity, null, false), this.snapshot.used / this.snapshot.capacity * 100.0); }, set subtitle(x) @@ -358,61 +434,119 @@ WebInspector.HeapSnapshotSidebarTreeElement.prototype = { WebInspector.HeapSnapshotSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; -WebInspector.HeapSnapshotDataGridNode = function(snapshotView, snapshotEntry, owningList) +WebInspector.HeapSnapshotDataGridNode = function(snapshotView, baseEntry, snapshotEntry, owningList) { - this.snapshotView = snapshotView; - this.snapshotEntry = snapshotEntry; - WebInspector.DataGridNode.call(this, null, false); + this.snapshotView = snapshotView; this.list = owningList; - this.lastComparator = null; + if (!snapshotEntry) + snapshotEntry = { cons: baseEntry.cons, count: 0, size: 0 }; this.constructorName = snapshotEntry.cons; this.objectsCount = snapshotEntry.count; this.objectsSize = snapshotEntry.size; + + if (!baseEntry) + baseEntry = { count: 0, size: 0 }; + this.baseObjectsCount = baseEntry.count; + this.objectsCountDelta = this.objectsCount - this.baseObjectsCount; + this.baseObjectsSize = baseEntry.size; + this.objectsSizeDelta = this.objectsSize - this.baseObjectsSize; }; WebInspector.HeapSnapshotDataGridNode.prototype = { get data() { - var data = { - cons: this.constructorName - }; + var data = {}; + + data["cons"] = this.constructorName; if (this.snapshotView.showCountAsPercent) - data["count"] = WebInspector.UIString("%.2f%%", this.countPercent); + data["count"] = WebInspector.UIString("%.2f%%", this.objectsCountPercent); else data["count"] = this.objectsCount; if (this.snapshotView.showSizeAsPercent) - data["size"] = WebInspector.UIString("%.2f%%", this.sizePercent); + data["size"] = WebInspector.UIString("%.2f%%", this.objectsSizePercent); else data["size"] = Number.bytesToString(this.objectsSize); + function signForDelta(delta) { + if (delta == 0) + return ""; + if (delta > 0) + return "+"; + else + // Math minus sign, same width as plus. + return "\u2212"; + } + + function showDeltaAsPercent(value) { + if (value === Number.POSITIVE_INFINITY) + return WebInspector.UIString("new"); + else if (value === Number.NEGATIVE_INFINITY) + return WebInspector.UIString("deleted"); + if (value > 1000.0) + return WebInspector.UIString("%s >1000%%", signForDelta(value)); + return WebInspector.UIString("%s%.2f%%", signForDelta(value), Math.abs(value)); + } + + if (this.snapshotView.showCountDeltaAsPercent) + data["countDelta"] = showDeltaAsPercent(this.objectsCountDeltaPercent); + else + data["countDelta"] = WebInspector.UIString("%s%d", signForDelta(this.objectsCountDelta), Math.abs(this.objectsCountDelta)); + + if (this.snapshotView.showSizeDeltaAsPercent) + data["sizeDelta"] = showDeltaAsPercent(this.objectsSizeDeltaPercent); + else + data["sizeDelta"] = WebInspector.UIString("%s%s", signForDelta(this.objectsSizeDelta), Number.bytesToString(Math.abs(this.objectsSizeDelta))); + return data; }, - get countPercent() + get objectsCountPercent() { return this.objectsCount / this.list.objectsCount * 100.0; }, - get sizePercent() + get objectsSizePercent() { return this.objectsSize / this.list.objectsSize * 100.0; + }, + + get objectsCountDeltaPercent() + { + if (this.baseObjectsCount > 0) { + if (this.objectsCount > 0) + return this.objectsCountDelta / this.baseObjectsCount * 100.0; + else + return Number.NEGATIVE_INFINITY; + } else + return Number.POSITIVE_INFINITY; + }, + + get objectsSizeDeltaPercent() + { + if (this.baseObjectsSize > 0) { + if (this.objectsSize > 0) + return this.objectsSizeDelta / this.baseObjectsSize * 100.0; + else + return Number.NEGATIVE_INFINITY; + } else + return Number.POSITIVE_INFINITY; } }; WebInspector.HeapSnapshotDataGridNode.prototype.__proto__ = WebInspector.DataGridNode.prototype; -WebInspector.HeapSnapshotDataGridList = function(snapshotView, snapshotEntries) +WebInspector.HeapSnapshotDataGridList = function(snapshotView, baseEntries, snapshotEntries) { this.list = this; this.snapshotView = snapshotView; this.children = []; this.lastComparator = null; - this.populateChildren(snapshotEntries); + this.populateChildren(baseEntries, snapshotEntries); }; WebInspector.HeapSnapshotDataGridList.prototype = { @@ -431,11 +565,15 @@ WebInspector.HeapSnapshotDataGridList.prototype = { this.children = []; }, - populateChildren: function(snapshotEntries) + populateChildren: function(baseEntries, snapshotEntries) { - var count = snapshotEntries.length; - for (var index = 0; index < count; ++index) - this.appendChild(new WebInspector.HeapSnapshotDataGridNode(this.snapshotView, snapshotEntries[index], this)); + for (var item in snapshotEntries) + this.appendChild(new WebInspector.HeapSnapshotDataGridNode(this.snapshotView, baseEntries[item], snapshotEntries[item], this)); + + for (item in baseEntries) { + if (!(item in snapshotEntries)) + this.appendChild(new WebInspector.HeapSnapshotDataGridNode(this.snapshotView, baseEntries[item], null, this)); + } }, sort: function(comparator, force) { diff --git a/webkit/glue/devtools/js/profiler_processor.js b/webkit/glue/devtools/js/profiler_processor.js index 351d0be..556841d 100644 --- a/webkit/glue/devtools/js/profiler_processor.js +++ b/webkit/glue/devtools/js/profiler_processor.js @@ -387,7 +387,7 @@ devtools.profiler.Processor.prototype.processHeapSampleBegin_ = function( if (space != 'Heap') return; this.currentHeapSnapshot_ = { number: this.heapSnapshotId_++, - entries: [], + entries: {}, ticks: ticks }; }; @@ -404,9 +404,9 @@ devtools.profiler.Processor.prototype.processHeapSampleStats_ = function( devtools.profiler.Processor.prototype.processHeapJsConsItem_ = function( item, number, size) { if (!this.currentHeapSnapshot_) return; - this.currentHeapSnapshot_.entries.push({ + this.currentHeapSnapshot_.entries[item] = { cons: item, count: number, size: size - }); + }; }; diff --git a/webkit/glue/devtools_strings.grd b/webkit/glue/devtools_strings.grd index 650ca36..1e97a2d 100644 --- a/webkit/glue/devtools_strings.grd +++ b/webkit/glue/devtools_strings.grd @@ -46,11 +46,56 @@ Google Chrome Developer Tools. --> <message name="IDS_WINDOW_HEADER" desc="DevTools window header."> Developer Tools - <ph name="URL">%s<ex>http://www.example.com/</ex></ph> </message> + <message name="IDS_HEAP_TAB_TITLE" desc="Title of the heap profiler tab."> + Heap + </message> + <message name="IDS_TAKE_HEAP_SNAPSHOT" desc="Title of a button that takes heap snapshot."> + Take heap snapshot. + </message> <message name="IDS_HEAP_SNAPSHOT" desc="Heap snapshot title."> Snapshot <ph name="COUNT">%d<ex>1</ex></ph> </message> <message name="IDS_HEAP_USAGE" desc="Heap usage."> - Used <ph name="USED">%1$s<ex>100MB</ex></ph> of <ph name="CAPACITY">%2$s<ex>200MB</ex></ph> + Used <ph name="USED">%1$s<ex>100MB</ex></ph> of <ph name="CAPACITY">%2$s<ex>200MB</ex></ph> (<ph name="PERCENT">%3$.0f<ex>50</ex></ph>%%) + </message> + <message name="IDS_HEAP_SNAPSHOT_GRID_CONSTRUCTOR" desc="Title of a heap snapshot grid column showing object's constructor name."> + Constructor + </message> + <message name="IDS_HEAP_SNAPSHOT_GRID_COUNT" desc="Title of a heap snapshot grid column showing objects count."> + Count + </message> + <message name="IDS_HEAP_SNAPSHOT_GRID_COUNT_DELTA" desc="Title of a heap snapshot grid column showing delta of objects count."> + ± Count + </message> + <message name="IDS_HEAP_SNAPSHOT_GRID_SIZE_DELTA" desc="Title of a heap snapshot grid column showing delta of objects size."> + ± Size + </message> + <message name="IDS_HEAP_SNAPSHOT_COMPARED_TO" desc="An option to choose a snapshot to compare current snapshot with."> + Compared to <ph name="BASE">%s<ex>Snapshot 1</ex></ph> + </message> + <message name="IDS_ABSOLUTE_OBJ_COUNTS_AND_SIZES" desc="An option to show absolute objects counts and sizes."> + Show absolute counts and sizes. + </message> + <message name="IDS_PERCENTAGE_OBJ_COUNTS_AND_SIZES" desc="An option to show objects counts and sizes as percentages."> + Show counts and sizes as percentages. + </message> + <message name="IDS_NEW_OBJECTS_IN_DELTA" desc="Indicates that object instances are new compared to base state."> + new + </message> + <message name="IDS_DELETED_OBJECTS_IN_DELTA" desc="Indicates that object instances have disappeared compared to base state."> + deleted + </message> + <message name="IDS_VERY_LARGE_DELTA" desc="Shows very large delta in percents"> + <ph name="SIGN">%s<ex>+</ex></ph> >1000%% + </message> + <message name="IDS_SHARE_IN_PERCENTS_SIGNED" desc="Share in percents, with sign."> + <ph name="SIGN">%$1s<ex>+</ex></ph><ph name="SHARE">%$2.2f<ex>5</ex></ph>%% + </message> + <message name="IDS_SIGNED_DELTA" desc="Signed delta."> + %$1s%$2d + </message> + <message name="IDS_SIGNED_STRING_DELTA" desc="Signed string delta."> + %$1s%$2s </message> </messages> </release> |