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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month 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 unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer 11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 12 * in the documentation and/or other materials provided with the
13 * distribution. 13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its 14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from 15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission. 16 * this software without specific prior written permission.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30
31 /** 30 /**
32 * @constructor
33 * @implements {WebInspector.ProfileType.DataDisplayDelegate} 31 * @implements {WebInspector.ProfileType.DataDisplayDelegate}
34 * @implements {WebInspector.Searchable} 32 * @implements {WebInspector.Searchable}
35 * @extends {WebInspector.SimpleView} 33 * @unrestricted
36 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
37 * @param {!WebInspector.HeapProfileHeader} profile
38 */ 34 */
39 WebInspector.HeapSnapshotView = function(dataDisplayDelegate, profile) 35 WebInspector.HeapSnapshotView = class extends WebInspector.SimpleView {
40 { 36 /**
41 WebInspector.SimpleView.call(this, WebInspector.UIString("Heap Snapshot")); 37 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
38 * @param {!WebInspector.HeapProfileHeader} profile
39 */
40 constructor(dataDisplayDelegate, profile) {
41 super(WebInspector.UIString('Heap Snapshot'));
42 42
43 this.element.classList.add("heap-snapshot-view"); 43 this.element.classList.add('heap-snapshot-view');
44 44
45 profile.profileType().addEventListener(WebInspector.HeapSnapshotProfileType. SnapshotReceived, this._onReceiveSnapshot, this); 45 profile.profileType().addEventListener(
46 profile.profileType().addEventListener(WebInspector.ProfileType.Events.Remov eProfileHeader, this._onProfileHeaderRemoved, this); 46 WebInspector.HeapSnapshotProfileType.SnapshotReceived, this._onReceiveSn apshot, this);
47 profile.profileType().addEventListener(
48 WebInspector.ProfileType.Events.RemoveProfileHeader, this._onProfileHead erRemoved, this);
47 49
48 var isHeapTimeline = profile.profileType().id === WebInspector.TrackingHeapS napshotProfileType.TypeId; 50 var isHeapTimeline = profile.profileType().id === WebInspector.TrackingHeapS napshotProfileType.TypeId;
49 if (isHeapTimeline) { 51 if (isHeapTimeline) {
50 this._trackingOverviewGrid = new WebInspector.HeapTrackingOverviewGrid(p rofile); 52 this._trackingOverviewGrid = new WebInspector.HeapTrackingOverviewGrid(pro file);
51 this._trackingOverviewGrid.addEventListener(WebInspector.HeapTrackingOve rviewGrid.IdsRangeChanged, this._onIdsRangeChanged.bind(this)); 53 this._trackingOverviewGrid.addEventListener(
54 WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged, this._onIdsRang eChanged.bind(this));
52 } 55 }
53 56
54 this._parentDataDisplayDelegate = dataDisplayDelegate; 57 this._parentDataDisplayDelegate = dataDisplayDelegate;
55 58
56 this._searchableView = new WebInspector.SearchableView(this); 59 this._searchableView = new WebInspector.SearchableView(this);
57 this._searchableView.show(this.element); 60 this._searchableView.show(this.element);
58 61
59 this._splitWidget = new WebInspector.SplitWidget(false, true, "heapSnapshotS plitViewState", 200, 200); 62 this._splitWidget = new WebInspector.SplitWidget(false, true, 'heapSnapshotS plitViewState', 200, 200);
60 this._splitWidget.show(this._searchableView.element); 63 this._splitWidget.show(this._searchableView.element);
61 64
62 this._containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid (this); 65 this._containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid (this);
63 this._containmentDataGrid.addEventListener(WebInspector.DataGrid.Events.Sele ctedNode, this._selectionChanged, this); 66 this._containmentDataGrid.addEventListener(WebInspector.DataGrid.Events.Sele ctedNode, this._selectionChanged, this);
64 this._containmentWidget = this._containmentDataGrid.asWidget(); 67 this._containmentWidget = this._containmentDataGrid.asWidget();
65 this._containmentWidget.setMinimumSize(50, 25); 68 this._containmentWidget.setMinimumSize(50, 25);
66 69
67 this._statisticsView = new WebInspector.HeapSnapshotStatisticsView(); 70 this._statisticsView = new WebInspector.HeapSnapshotStatisticsView();
68 71
69 this._constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGr id(this); 72 this._constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGr id(this);
70 this._constructorsDataGrid.addEventListener(WebInspector.DataGrid.Events.Sel ectedNode, this._selectionChanged, this); 73 this._constructorsDataGrid.addEventListener(
74 WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this) ;
71 this._constructorsWidget = this._constructorsDataGrid.asWidget(); 75 this._constructorsWidget = this._constructorsDataGrid.asWidget();
72 this._constructorsWidget.setMinimumSize(50, 25); 76 this._constructorsWidget.setMinimumSize(50, 25);
73 77
74 this._diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid(this); 78 this._diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid(this);
75 this._diffDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNod e, this._selectionChanged, this); 79 this._diffDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNod e, this._selectionChanged, this);
76 this._diffWidget = this._diffDataGrid.asWidget(); 80 this._diffWidget = this._diffDataGrid.asWidget();
77 this._diffWidget.setMinimumSize(50, 25); 81 this._diffWidget.setMinimumSize(50, 25);
78 82
79 if (isHeapTimeline && WebInspector.moduleSetting("recordAllocationStacks").g et()) { 83 if (isHeapTimeline && WebInspector.moduleSetting('recordAllocationStacks').g et()) {
80 this._allocationDataGrid = new WebInspector.AllocationDataGrid(profile.t arget() , this); 84 this._allocationDataGrid = new WebInspector.AllocationDataGrid(profile.tar get(), this);
81 this._allocationDataGrid.addEventListener(WebInspector.DataGrid.Events.S electedNode, this._onSelectAllocationNode, this); 85 this._allocationDataGrid.addEventListener(
82 this._allocationWidget = this._allocationDataGrid.asWidget(); 86 WebInspector.DataGrid.Events.SelectedNode, this._onSelectAllocationNod e, this);
83 this._allocationWidget.setMinimumSize(50, 25); 87 this._allocationWidget = this._allocationDataGrid.asWidget();
88 this._allocationWidget.setMinimumSize(50, 25);
84 89
85 this._allocationStackView = new WebInspector.HeapAllocationStackView(pro file.target()); 90 this._allocationStackView = new WebInspector.HeapAllocationStackView(profi le.target());
86 this._allocationStackView.setMinimumSize(50, 25); 91 this._allocationStackView.setMinimumSize(50, 25);
87 92
88 this._tabbedPane = new WebInspector.TabbedPane(); 93 this._tabbedPane = new WebInspector.TabbedPane();
89 } 94 }
90 95
91 this._retainmentDataGrid = new WebInspector.HeapSnapshotRetainmentDataGrid(t his); 96 this._retainmentDataGrid = new WebInspector.HeapSnapshotRetainmentDataGrid(t his);
92 this._retainmentWidget = this._retainmentDataGrid.asWidget(); 97 this._retainmentWidget = this._retainmentDataGrid.asWidget();
93 this._retainmentWidget.setMinimumSize(50, 21); 98 this._retainmentWidget.setMinimumSize(50, 21);
94 this._retainmentWidget.element.classList.add("retaining-paths-view"); 99 this._retainmentWidget.element.classList.add('retaining-paths-view');
95 100
96 var splitWidgetResizer; 101 var splitWidgetResizer;
97 if (this._allocationStackView) { 102 if (this._allocationStackView) {
98 this._tabbedPane = new WebInspector.TabbedPane(); 103 this._tabbedPane = new WebInspector.TabbedPane();
99 104
100 this._tabbedPane.appendTab("retainers", WebInspector.UIString("Retainers "), this._retainmentWidget); 105 this._tabbedPane.appendTab('retainers', WebInspector.UIString('Retainers') , this._retainmentWidget);
101 this._tabbedPane.appendTab("allocation-stack", WebInspector.UIString("Al location stack"), this._allocationStackView); 106 this._tabbedPane.appendTab(
107 'allocation-stack', WebInspector.UIString('Allocation stack'), this._a llocationStackView);
102 108
103 splitWidgetResizer = this._tabbedPane.headerElement(); 109 splitWidgetResizer = this._tabbedPane.headerElement();
104 this._objectDetailsView = this._tabbedPane; 110 this._objectDetailsView = this._tabbedPane;
105 } else { 111 } else {
106 var retainmentViewHeader = createElementWithClass("div", "heap-snapshot- view-resizer"); 112 var retainmentViewHeader = createElementWithClass('div', 'heap-snapshot-vi ew-resizer');
107 var retainingPathsTitleDiv = retainmentViewHeader.createChild("div", "ti tle"); 113 var retainingPathsTitleDiv = retainmentViewHeader.createChild('div', 'titl e');
108 var retainingPathsTitle = retainingPathsTitleDiv.createChild("span"); 114 var retainingPathsTitle = retainingPathsTitleDiv.createChild('span');
109 retainingPathsTitle.textContent = WebInspector.UIString("Retainers"); 115 retainingPathsTitle.textContent = WebInspector.UIString('Retainers');
110 116
111 splitWidgetResizer = retainmentViewHeader; 117 splitWidgetResizer = retainmentViewHeader;
112 this._objectDetailsView = new WebInspector.VBox(); 118 this._objectDetailsView = new WebInspector.VBox();
113 this._objectDetailsView.element.appendChild(retainmentViewHeader); 119 this._objectDetailsView.element.appendChild(retainmentViewHeader);
114 this._retainmentWidget.show(this._objectDetailsView.element); 120 this._retainmentWidget.show(this._objectDetailsView.element);
115 } 121 }
116 this._splitWidget.hideDefaultResizer(); 122 this._splitWidget.hideDefaultResizer();
117 this._splitWidget.installResizer(splitWidgetResizer); 123 this._splitWidget.installResizer(splitWidgetResizer);
118 124
119 this._retainmentDataGrid.addEventListener(WebInspector.DataGrid.Events.Selec tedNode, this._inspectedObjectChanged, this); 125 this._retainmentDataGrid.addEventListener(
126 WebInspector.DataGrid.Events.SelectedNode, this._inspectedObjectChanged, this);
120 this._retainmentDataGrid.reset(); 127 this._retainmentDataGrid.reset();
121 128
122 this._perspectives = []; 129 this._perspectives = [];
123 this._perspectives.push(new WebInspector.HeapSnapshotView.SummaryPerspective ()); 130 this._perspectives.push(new WebInspector.HeapSnapshotView.SummaryPerspective ());
124 if (profile.profileType() !== WebInspector.ProfileTypeRegistry.instance.trac kingHeapSnapshotProfileType) 131 if (profile.profileType() !== WebInspector.ProfileTypeRegistry.instance.trac kingHeapSnapshotProfileType)
125 this._perspectives.push(new WebInspector.HeapSnapshotView.ComparisonPers pective()); 132 this._perspectives.push(new WebInspector.HeapSnapshotView.ComparisonPerspe ctive());
126 this._perspectives.push(new WebInspector.HeapSnapshotView.ContainmentPerspec tive()); 133 this._perspectives.push(new WebInspector.HeapSnapshotView.ContainmentPerspec tive());
127 if (this._allocationWidget) 134 if (this._allocationWidget)
128 this._perspectives.push(new WebInspector.HeapSnapshotView.AllocationPers pective()); 135 this._perspectives.push(new WebInspector.HeapSnapshotView.AllocationPerspe ctive());
129 this._perspectives.push(new WebInspector.HeapSnapshotView.StatisticsPerspect ive()); 136 this._perspectives.push(new WebInspector.HeapSnapshotView.StatisticsPerspect ive());
130 137
131 this._perspectiveSelect = new WebInspector.ToolbarComboBox(this._onSelectedP erspectiveChanged.bind(this)); 138 this._perspectiveSelect = new WebInspector.ToolbarComboBox(this._onSelectedP erspectiveChanged.bind(this));
132 for (var i = 0; i < this._perspectives.length; ++i) 139 for (var i = 0; i < this._perspectives.length; ++i)
133 this._perspectiveSelect.createOption(this._perspectives[i].title()); 140 this._perspectiveSelect.createOption(this._perspectives[i].title());
134 141
135 this._profile = profile; 142 this._profile = profile;
136 143
137 this._baseSelect = new WebInspector.ToolbarComboBox(this._changeBase.bind(th is)); 144 this._baseSelect = new WebInspector.ToolbarComboBox(this._changeBase.bind(th is));
138 this._baseSelect.setVisible(false); 145 this._baseSelect.setVisible(false);
139 this._updateBaseOptions(); 146 this._updateBaseOptions();
140 147
141 this._filterSelect = new WebInspector.ToolbarComboBox(this._changeFilter.bin d(this)); 148 this._filterSelect = new WebInspector.ToolbarComboBox(this._changeFilter.bin d(this));
142 this._filterSelect.setVisible(false); 149 this._filterSelect.setVisible(false);
143 this._updateFilterOptions(); 150 this._updateFilterOptions();
144 151
145 this._classNameFilter = new WebInspector.ToolbarInput("Class filter"); 152 this._classNameFilter = new WebInspector.ToolbarInput('Class filter');
146 this._classNameFilter.setVisible(false); 153 this._classNameFilter.setVisible(false);
147 this._constructorsDataGrid.setNameFilter(this._classNameFilter); 154 this._constructorsDataGrid.setNameFilter(this._classNameFilter);
148 this._diffDataGrid.setNameFilter(this._classNameFilter); 155 this._diffDataGrid.setNameFilter(this._classNameFilter);
149 156
150 this._selectedSizeText = new WebInspector.ToolbarText(); 157 this._selectedSizeText = new WebInspector.ToolbarText();
151 158
152 this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, thi s._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefine d, true); 159 this._popoverHelper = new WebInspector.ObjectPopoverHelper(
160 this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPop over.bind(this), undefined, true);
153 161
154 this._currentPerspectiveIndex = 0; 162 this._currentPerspectiveIndex = 0;
155 this._currentPerspective = this._perspectives[0]; 163 this._currentPerspective = this._perspectives[0];
156 this._currentPerspective.activate(this); 164 this._currentPerspective.activate(this);
157 this._dataGrid = this._currentPerspective.masterGrid(this); 165 this._dataGrid = this._currentPerspective.masterGrid(this);
158 166
159 this._populate(); 167 this._populate();
160 this._searchThrottler = new WebInspector.Throttler(0); 168 this._searchThrottler = new WebInspector.Throttler(0);
161 }; 169 }
162 170
163 /** 171 /**
164 * @constructor 172 * @return {!WebInspector.SearchableView}
165 * @param {string} title 173 */
166 */ 174 searchableView() {
167 WebInspector.HeapSnapshotView.Perspective = function(title) 175 return this._searchableView;
168 { 176 }
169 this._title = title; 177
170 }; 178 /**
171 179 * @override
172 WebInspector.HeapSnapshotView.Perspective.prototype = { 180 * @param {?WebInspector.ProfileHeader} profile
181 * @return {?WebInspector.Widget}
182 */
183 showProfile(profile) {
184 return this._parentDataDisplayDelegate.showProfile(profile);
185 }
186
187 /**
188 * @override
189 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
190 * @param {string} perspectiveName
191 */
192 showObject(snapshotObjectId, perspectiveName) {
193 if (snapshotObjectId <= this._profile.maxJSObjectId)
194 this.selectLiveObject(perspectiveName, snapshotObjectId);
195 else
196 this._parentDataDisplayDelegate.showObject(snapshotObjectId, perspectiveNa me);
197 }
198
199 _populate() {
200 this._profile._loadPromise
201 .then(heapSnapshotProxy => {
202 heapSnapshotProxy.getStatistics().then(this._gotStatistics.bind(this)) ;
203 this._dataGrid.setDataSource(heapSnapshotProxy);
204 if (this._profile.profileType().id === WebInspector.TrackingHeapSnapsh otProfileType.TypeId &&
205 this._profile.fromFile())
206 return heapSnapshotProxy.getSamples().then(samples => this._tracking OverviewGrid._setSamples(samples));
207 })
208 .then(_ => {
209 var list = this._profiles();
210 var profileIndex = list.indexOf(this._profile);
211 this._baseSelect.setSelectedIndex(Math.max(0, profileIndex - 1));
212 if (this._trackingOverviewGrid)
213 this._trackingOverviewGrid._updateGrid();
214 });
215 }
216
217 /**
218 * @param {!WebInspector.HeapSnapshotCommon.Statistics} statistics
219 */
220 _gotStatistics(statistics) {
221 this._statisticsView.setTotal(statistics.total);
222 this._statisticsView.addRecord(statistics.code, WebInspector.UIString('Code' ), '#f77');
223 this._statisticsView.addRecord(statistics.strings, WebInspector.UIString('St rings'), '#5e5');
224 this._statisticsView.addRecord(statistics.jsArrays, WebInspector.UIString('J S Arrays'), '#7af');
225 this._statisticsView.addRecord(statistics.native, WebInspector.UIString('Typ ed Arrays'), '#fc5');
226 this._statisticsView.addRecord(statistics.system, WebInspector.UIString('Sys tem Objects'), '#98f');
227 this._statisticsView.addRecord(statistics.total, WebInspector.UIString('Tota l'));
228 }
229
230 /**
231 * @param {!WebInspector.Event} event
232 */
233 _onIdsRangeChanged(event) {
234 var minId = event.data.minId;
235 var maxId = event.data.maxId;
236 this._selectedSizeText.setText(WebInspector.UIString('Selected size: %s', Nu mber.bytesToString(event.data.size)));
237 if (this._constructorsDataGrid.snapshot)
238 this._constructorsDataGrid.setSelectionRange(minId, maxId);
239 }
240
241 /**
242 * @override
243 * @return {!Array.<!WebInspector.ToolbarItem>}
244 */
245 syncToolbarItems() {
246 var result = [this._perspectiveSelect, this._classNameFilter];
247 if (this._profile.profileType() !== WebInspector.ProfileTypeRegistry.instanc e.trackingHeapSnapshotProfileType)
248 result.push(this._baseSelect, this._filterSelect);
249 result.push(this._selectedSizeText);
250 return result;
251 }
252
253 /**
254 * @override
255 */
256 wasShown() {
257 this._profile._loadPromise.then(this._profile._wasShown.bind(this._profile)) ;
258 }
259
260 /**
261 * @override
262 */
263 willHide() {
264 this._currentSearchResultIndex = -1;
265 this._popoverHelper.hidePopover();
266 if (this.helpPopover && this.helpPopover.isShowing())
267 this.helpPopover.hide();
268 }
269
270 /**
271 * @override
272 * @return {boolean}
273 */
274 supportsCaseSensitiveSearch() {
275 return true;
276 }
277
278 /**
279 * @override
280 * @return {boolean}
281 */
282 supportsRegexSearch() {
283 return false;
284 }
285
286 /**
287 * @override
288 */
289 searchCanceled() {
290 this._currentSearchResultIndex = -1;
291 this._searchResults = [];
292 }
293
294 /**
295 * @param {?WebInspector.HeapSnapshotGridNode} node
296 */
297 _selectRevealedNode(node) {
298 if (node)
299 node.select();
300 }
301
302 /**
303 * @override
304 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig
305 * @param {boolean} shouldJump
306 * @param {boolean=} jumpBackwards
307 */
308 performSearch(searchConfig, shouldJump, jumpBackwards) {
309 var nextQuery = new WebInspector.HeapSnapshotCommon.SearchConfig(
310 searchConfig.query.trim(), searchConfig.caseSensitive, searchConfig.isRe gex, shouldJump,
311 jumpBackwards || false);
312
313 this._searchThrottler.schedule(this._performSearch.bind(this, nextQuery));
314 }
315
316 /**
317 * @param {!WebInspector.HeapSnapshotCommon.SearchConfig} nextQuery
318 * @return {!Promise<?>}
319 */
320 _performSearch(nextQuery) {
321 // Call searchCanceled since it will reset everything we need before doing a new search.
322 this.searchCanceled();
323
324 if (!this._currentPerspective.supportsSearch())
325 return Promise.resolve();
326
327 this.currentQuery = nextQuery;
328 var query = nextQuery.query.trim();
329
330 if (!query)
331 return Promise.resolve();
332
333 if (query.charAt(0) === '@') {
334 var snapshotNodeId = parseInt(query.substring(1), 10);
335 if (isNaN(snapshotNodeId))
336 return Promise.resolve();
337 return this._dataGrid.revealObjectByHeapSnapshotId(String(snapshotNodeId))
338 .then(this._selectRevealedNode.bind(this));
339 }
340
173 /** 341 /**
174 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView 342 * @param {!Array<number>} entryIds
343 * @return {!Promise<?>}
344 * @this {WebInspector.HeapSnapshotView}
175 */ 345 */
176 activate: function(heapSnapshotView) { }, 346 function didSearch(entryIds) {
347 this._searchResults = entryIds;
348 this._searchableView.updateSearchMatchesCount(this._searchResults.length);
349 if (this._searchResults.length)
350 this._currentSearchResultIndex = nextQuery.jumpBackwards ? this._searchR esults.length - 1 : 0;
351 return this._jumpToSearchResult(this._currentSearchResultIndex);
352 }
353
354 return this._profile._snapshotProxy.search(this.currentQuery, this._dataGrid .nodeFilter())
355 .then(didSearch.bind(this));
356 }
357
358 /**
359 * @override
360 */
361 jumpToNextSearchResult() {
362 if (!this._searchResults.length)
363 return;
364 this._currentSearchResultIndex = (this._currentSearchResultIndex + 1) % this ._searchResults.length;
365 this._searchThrottler.schedule(this._jumpToSearchResult.bind(this, this._cur rentSearchResultIndex));
366 }
367
368 /**
369 * @override
370 */
371 jumpToPreviousSearchResult() {
372 if (!this._searchResults.length)
373 return;
374 this._currentSearchResultIndex =
375 (this._currentSearchResultIndex + this._searchResults.length - 1) % this ._searchResults.length;
376 this._searchThrottler.schedule(this._jumpToSearchResult.bind(this, this._cur rentSearchResultIndex));
377 }
378
379 /**
380 * @param {number} searchResultIndex
381 * @return {!Promise<undefined>}
382 */
383 _jumpToSearchResult(searchResultIndex) {
384 this._searchableView.updateCurrentMatchIndex(searchResultIndex);
385 return this._dataGrid.revealObjectByHeapSnapshotId(String(this._searchResult s[searchResultIndex]))
386 .then(this._selectRevealedNode.bind(this));
387 }
388
389 refreshVisibleData() {
390 if (!this._dataGrid)
391 return;
392 var child = this._dataGrid.rootNode().children[0];
393 while (child) {
394 child.refresh();
395 child = child.traverseNextNode(false, null, true);
396 }
397 }
398
399 _changeBase() {
400 if (this._baseProfile === this._profiles()[this._baseSelect.selectedIndex()] )
401 return;
402
403 this._baseProfile = this._profiles()[this._baseSelect.selectedIndex()];
404 var dataGrid = /** @type {!WebInspector.HeapSnapshotDiffDataGrid} */ (this._ dataGrid);
405 // Change set base data source only if main data source is already set.
406 if (dataGrid.snapshot)
407 this._baseProfile._loadPromise.then(dataGrid.setBaseDataSource.bind(dataGr id));
408
409 if (!this.currentQuery || !this._searchResults)
410 return;
411
412 // The current search needs to be performed again. First negate out previous match
413 // count by calling the search finished callback with a negative number of m atches.
414 // Then perform the search again with the same query and callback.
415 this.performSearch(this.currentQuery, false);
416 }
417
418 _changeFilter() {
419 var profileIndex = this._filterSelect.selectedIndex() - 1;
420 this._dataGrid.filterSelectIndexChanged(this._profiles(), profileIndex);
421
422 if (!this.currentQuery || !this._searchResults)
423 return;
424
425 // The current search needs to be performed again. First negate out previous match
426 // count by calling the search finished callback with a negative number of m atches.
427 // Then perform the search again with the same query and callback.
428 this.performSearch(this.currentQuery, false);
429 }
430
431 /**
432 * @return {!Array.<!WebInspector.ProfileHeader>}
433 */
434 _profiles() {
435 return this._profile.profileType().getProfiles();
436 }
437
438 /**
439 * @param {!WebInspector.ContextMenu} contextMenu
440 * @param {!Event} event
441 */
442 populateContextMenu(contextMenu, event) {
443 if (this._dataGrid)
444 this._dataGrid.populateContextMenu(contextMenu, event);
445 }
446
447 _selectionChanged(event) {
448 var selectedNode = event.target.selectedNode;
449 this._setSelectedNodeForDetailsView(selectedNode);
450 this._inspectedObjectChanged(event);
451 }
452
453 _onSelectAllocationNode(event) {
454 var selectedNode = event.target.selectedNode;
455 this._constructorsDataGrid.setAllocationNodeId(selectedNode.allocationNodeId ());
456 this._setSelectedNodeForDetailsView(null);
457 }
458
459 _inspectedObjectChanged(event) {
460 var selectedNode = event.target.selectedNode;
461 var target = this._profile.target();
462 if (target && selectedNode instanceof WebInspector.HeapSnapshotGenericObject Node)
463 target.heapProfilerAgent().addInspectedHeapObject(String(selectedNode.snap shotNodeId));
464 }
465
466 /**
467 * @param {?WebInspector.HeapSnapshotGridNode} nodeItem
468 */
469 _setSelectedNodeForDetailsView(nodeItem) {
470 var dataSource = nodeItem && nodeItem.retainersDataSource();
471 if (dataSource) {
472 this._retainmentDataGrid.setDataSource(dataSource.snapshot, dataSource.sna pshotNodeIndex);
473 if (this._allocationStackView)
474 this._allocationStackView.setAllocatedObject(dataSource.snapshot, dataSo urce.snapshotNodeIndex);
475 } else {
476 if (this._allocationStackView)
477 this._allocationStackView.clear();
478 this._retainmentDataGrid.reset();
479 }
480 }
481
482 /**
483 * @param {string} perspectiveTitle
484 * @param {function()} callback
485 */
486 _changePerspectiveAndWait(perspectiveTitle, callback) {
487 var perspectiveIndex = null;
488 for (var i = 0; i < this._perspectives.length; ++i) {
489 if (this._perspectives[i].title() === perspectiveTitle) {
490 perspectiveIndex = i;
491 break;
492 }
493 }
494 if (this._currentPerspectiveIndex === perspectiveIndex || perspectiveIndex = == null) {
495 setTimeout(callback, 0);
496 return;
497 }
177 498
178 /** 499 /**
179 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView 500 * @this {WebInspector.HeapSnapshotView}
180 */ 501 */
181 deactivate: function(heapSnapshotView) 502 function dataGridContentShown(event) {
182 { 503 var dataGrid = event.data;
183 heapSnapshotView._baseSelect.setVisible(false); 504 dataGrid.removeEventListener(
184 heapSnapshotView._filterSelect.setVisible(false); 505 WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGri dContentShown, this);
185 heapSnapshotView._classNameFilter.setVisible(false); 506 if (dataGrid === this._dataGrid)
186 if (heapSnapshotView._trackingOverviewGrid) 507 callback();
187 heapSnapshotView._trackingOverviewGrid.detach(); 508 }
188 if (heapSnapshotView._allocationWidget) 509 this._perspectives[perspectiveIndex].masterGrid(this).addEventListener(
189 heapSnapshotView._allocationWidget.detach(); 510 WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridC ontentShown, this);
190 if (heapSnapshotView._statisticsView) 511
191 heapSnapshotView._statisticsView.detach(); 512 this._perspectiveSelect.setSelectedIndex(perspectiveIndex);
192 513 this._changePerspective(perspectiveIndex);
193 heapSnapshotView._splitWidget.detach(); 514 }
194 heapSnapshotView._splitWidget.detachChildWidgets(); 515
195 }, 516 _updateDataSourceAndView() {
517 var dataGrid = this._dataGrid;
518 if (!dataGrid || dataGrid.snapshot)
519 return;
520
521 this._profile._loadPromise.then(didLoadSnapshot.bind(this));
196 522
197 /** 523 /**
198 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView 524 * @this {WebInspector.HeapSnapshotView}
199 * @return {?WebInspector.DataGrid}
200 */ 525 */
201 masterGrid: function(heapSnapshotView) 526 function didLoadSnapshot(snapshotProxy) {
202 { 527 if (this._dataGrid !== dataGrid)
203 return null; 528 return;
204 }, 529 if (dataGrid.snapshot !== snapshotProxy)
530 dataGrid.setDataSource(snapshotProxy);
531 if (dataGrid === this._diffDataGrid) {
532 if (!this._baseProfile)
533 this._baseProfile = this._profiles()[this._baseSelect.selectedIndex()] ;
534 this._baseProfile._loadPromise.then(didLoadBaseSnapshot.bind(this));
535 }
536 }
205 537
206 /** 538 /**
207 * @return {string} 539 * @this {WebInspector.HeapSnapshotView}
208 */ 540 */
209 title: function() 541 function didLoadBaseSnapshot(baseSnapshotProxy) {
210 { 542 if (this._diffDataGrid.baseSnapshot !== baseSnapshotProxy)
211 return this._title; 543 this._diffDataGrid.setBaseDataSource(baseSnapshotProxy);
212 }, 544 }
545 }
546
547 _onSelectedPerspectiveChanged(event) {
548 this._changePerspective(event.target.selectedIndex);
549 }
550
551 /**
552 * @param {number} selectedIndex
553 */
554 _changePerspective(selectedIndex) {
555 if (selectedIndex === this._currentPerspectiveIndex)
556 return;
557
558 this._currentPerspectiveIndex = selectedIndex;
559
560 this._currentPerspective.deactivate(this);
561 var perspective = this._perspectives[selectedIndex];
562 this._currentPerspective = perspective;
563 this._dataGrid = perspective.masterGrid(this);
564 perspective.activate(this);
565
566 this.refreshVisibleData();
567 if (this._dataGrid)
568 this._dataGrid.updateWidths();
569
570 this._updateDataSourceAndView();
571
572 if (!this.currentQuery || !this._searchResults)
573 return;
574
575 // The current search needs to be performed again. First negate out previous match
576 // count by calling the search finished callback with a negative number of m atches.
577 // Then perform the search again the with same query and callback.
578 this.performSearch(this.currentQuery, false);
579 }
580
581 /**
582 * @param {string} perspectiveName
583 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
584 */
585 selectLiveObject(perspectiveName, snapshotObjectId) {
586 this._changePerspectiveAndWait(perspectiveName, didChangePerspective.bind(th is));
213 587
214 /** 588 /**
215 * @return {boolean} 589 * @this {WebInspector.HeapSnapshotView}
216 */ 590 */
217 supportsSearch: function() 591 function didChangePerspective() {
218 { 592 this._dataGrid.revealObjectByHeapSnapshotId(snapshotObjectId, didRevealObj ect);
219 return false; 593 }
220 }
221 };
222
223 /**
224 * @constructor
225 * @extends {WebInspector.HeapSnapshotView.Perspective}
226 */
227 WebInspector.HeapSnapshotView.SummaryPerspective = function()
228 {
229 WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString( "Summary"));
230 };
231
232 WebInspector.HeapSnapshotView.SummaryPerspective.prototype = {
233 /**
234 * @override
235 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
236 */
237 activate: function(heapSnapshotView)
238 {
239 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._constructo rsWidget);
240 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectD etailsView);
241 heapSnapshotView._splitWidget.show(heapSnapshotView._searchableView.elem ent);
242 heapSnapshotView._filterSelect.setVisible(true);
243 heapSnapshotView._classNameFilter.setVisible(true);
244 if (heapSnapshotView._trackingOverviewGrid) {
245 heapSnapshotView._trackingOverviewGrid.show(heapSnapshotView._search ableView.element, heapSnapshotView._splitWidget.element);
246 heapSnapshotView._trackingOverviewGrid.update();
247 heapSnapshotView._trackingOverviewGrid._updateGrid();
248 }
249 },
250
251 /**
252 * @override
253 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
254 * @return {?WebInspector.DataGrid}
255 */
256 masterGrid: function(heapSnapshotView)
257 {
258 return heapSnapshotView._constructorsDataGrid;
259 },
260
261 /**
262 * @override
263 * @return {boolean}
264 */
265 supportsSearch: function()
266 {
267 return true;
268 },
269
270 __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
271 };
272
273 /**
274 * @constructor
275 * @extends {WebInspector.HeapSnapshotView.Perspective}
276 */
277 WebInspector.HeapSnapshotView.ComparisonPerspective = function()
278 {
279 WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString( "Comparison"));
280 };
281
282 WebInspector.HeapSnapshotView.ComparisonPerspective.prototype = {
283 /**
284 * @override
285 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
286 */
287 activate: function(heapSnapshotView)
288 {
289 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._diffWidget );
290 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectD etailsView);
291 heapSnapshotView._splitWidget.show(heapSnapshotView._searchableView.elem ent);
292 heapSnapshotView._baseSelect.setVisible(true);
293 heapSnapshotView._classNameFilter.setVisible(true);
294 },
295
296 /**
297 * @override
298 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
299 * @return {?WebInspector.DataGrid}
300 */
301 masterGrid: function(heapSnapshotView)
302 {
303 return heapSnapshotView._diffDataGrid;
304 },
305
306 /**
307 * @override
308 * @return {boolean}
309 */
310 supportsSearch: function()
311 {
312 return true;
313 },
314
315 __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
316 };
317
318 /**
319 * @constructor
320 * @extends {WebInspector.HeapSnapshotView.Perspective}
321 */
322 WebInspector.HeapSnapshotView.ContainmentPerspective = function()
323 {
324 WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString( "Containment"));
325 };
326
327 WebInspector.HeapSnapshotView.ContainmentPerspective.prototype = {
328 /**
329 * @override
330 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
331 */
332 activate: function(heapSnapshotView)
333 {
334 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._containmen tWidget);
335 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectD etailsView);
336 heapSnapshotView._splitWidget.show(heapSnapshotView._searchableView.elem ent);
337 },
338
339 /**
340 * @override
341 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
342 * @return {?WebInspector.DataGrid}
343 */
344 masterGrid: function(heapSnapshotView)
345 {
346 return heapSnapshotView._containmentDataGrid;
347 },
348
349 __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
350 };
351
352 /**
353 * @constructor
354 * @extends {WebInspector.HeapSnapshotView.Perspective}
355 */
356 WebInspector.HeapSnapshotView.AllocationPerspective = function()
357 {
358 WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString( "Allocation"));
359 this._allocationSplitWidget = new WebInspector.SplitWidget(false, true, "hea pSnapshotAllocationSplitViewState", 200, 200);
360 this._allocationSplitWidget.setSidebarWidget(new WebInspector.VBox());
361
362 };
363
364 WebInspector.HeapSnapshotView.AllocationPerspective.prototype = {
365 /**
366 * @override
367 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
368 */
369 activate: function(heapSnapshotView)
370 {
371 this._allocationSplitWidget.setMainWidget(heapSnapshotView._allocationWi dget);
372 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._constructo rsWidget);
373 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectD etailsView);
374
375 var allocatedObjectsView = new WebInspector.VBox();
376 var resizer = createElementWithClass("div", "heap-snapshot-view-resizer" );
377 var title = resizer.createChild("div", "title").createChild("span");
378 title.textContent = WebInspector.UIString("Live objects");
379 this._allocationSplitWidget.hideDefaultResizer();
380 this._allocationSplitWidget.installResizer(resizer);
381 allocatedObjectsView.element.appendChild(resizer);
382 heapSnapshotView._splitWidget.show(allocatedObjectsView.element);
383 this._allocationSplitWidget.setSidebarWidget(allocatedObjectsView);
384
385 this._allocationSplitWidget.show(heapSnapshotView._searchableView.elemen t);
386
387 heapSnapshotView._constructorsDataGrid.clear();
388 var selectedNode = heapSnapshotView._allocationDataGrid.selectedNode;
389 if (selectedNode)
390 heapSnapshotView._constructorsDataGrid.setAllocationNodeId(selectedN ode.allocationNodeId());
391 },
392
393 /**
394 * @override
395 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
396 */
397 deactivate: function(heapSnapshotView)
398 {
399 this._allocationSplitWidget.detach();
400 WebInspector.HeapSnapshotView.Perspective.prototype.deactivate.call(this , heapSnapshotView);
401 },
402
403 /**
404 * @override
405 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
406 * @return {?WebInspector.DataGrid}
407 */
408 masterGrid: function(heapSnapshotView)
409 {
410 return heapSnapshotView._allocationDataGrid;
411 },
412
413 __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
414 };
415
416 /**
417 * @constructor
418 * @extends {WebInspector.HeapSnapshotView.Perspective}
419 */
420 WebInspector.HeapSnapshotView.StatisticsPerspective = function()
421 {
422 WebInspector.HeapSnapshotView.Perspective.call(this, WebInspector.UIString( "Statistics"));
423 };
424
425 WebInspector.HeapSnapshotView.StatisticsPerspective.prototype = {
426 /**
427 * @override
428 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
429 */
430 activate: function(heapSnapshotView)
431 {
432 heapSnapshotView._statisticsView.show(heapSnapshotView._searchableView.e lement);
433 },
434
435 /**
436 * @override
437 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
438 * @return {?WebInspector.DataGrid}
439 */
440 masterGrid: function(heapSnapshotView)
441 {
442 return null;
443 },
444
445 __proto__: WebInspector.HeapSnapshotView.Perspective.prototype
446 };
447
448
449 WebInspector.HeapSnapshotView.prototype = {
450 /**
451 * @return {!WebInspector.SearchableView}
452 */
453 searchableView: function()
454 {
455 return this._searchableView;
456 },
457
458 /**
459 * @override
460 * @param {?WebInspector.ProfileHeader} profile
461 * @return {?WebInspector.Widget}
462 */
463 showProfile: function(profile)
464 {
465 return this._parentDataDisplayDelegate.showProfile(profile);
466 },
467
468 /**
469 * @override
470 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
471 * @param {string} perspectiveName
472 */
473 showObject: function(snapshotObjectId, perspectiveName)
474 {
475 if (snapshotObjectId <= this._profile.maxJSObjectId)
476 this.selectLiveObject(perspectiveName, snapshotObjectId);
477 else
478 this._parentDataDisplayDelegate.showObject(snapshotObjectId, perspec tiveName);
479 },
480
481 _populate: function()
482 {
483 this._profile._loadPromise.then(heapSnapshotProxy => {
484 heapSnapshotProxy.getStatistics().then(this._gotStatistics.bind(this ));
485 this._dataGrid.setDataSource(heapSnapshotProxy);
486 if (this._profile.profileType().id === WebInspector.TrackingHeapSnap shotProfileType.TypeId && this._profile.fromFile())
487 return heapSnapshotProxy.getSamples().then(samples => this._trac kingOverviewGrid._setSamples(samples));
488 }).then(_ => {
489 var list = this._profiles();
490 var profileIndex = list.indexOf(this._profile);
491 this._baseSelect.setSelectedIndex(Math.max(0, profileIndex - 1));
492 if (this._trackingOverviewGrid)
493 this._trackingOverviewGrid._updateGrid();
494 });
495 },
496
497 /**
498 * @param {!WebInspector.HeapSnapshotCommon.Statistics} statistics
499 */
500 _gotStatistics: function(statistics)
501 {
502 this._statisticsView.setTotal(statistics.total);
503 this._statisticsView.addRecord(statistics.code, WebInspector.UIString("C ode"), "#f77");
504 this._statisticsView.addRecord(statistics.strings, WebInspector.UIString ("Strings"), "#5e5");
505 this._statisticsView.addRecord(statistics.jsArrays, WebInspector.UIStrin g("JS Arrays"), "#7af");
506 this._statisticsView.addRecord(statistics.native, WebInspector.UIString( "Typed Arrays"), "#fc5");
507 this._statisticsView.addRecord(statistics.system, WebInspector.UIString( "System Objects"), "#98f");
508 this._statisticsView.addRecord(statistics.total, WebInspector.UIString(" Total"));
509 },
510
511 /**
512 * @param {!WebInspector.Event} event
513 */
514 _onIdsRangeChanged: function(event)
515 {
516 var minId = event.data.minId;
517 var maxId = event.data.maxId;
518 this._selectedSizeText.setText(WebInspector.UIString("Selected size: %s" , Number.bytesToString(event.data.size)));
519 if (this._constructorsDataGrid.snapshot)
520 this._constructorsDataGrid.setSelectionRange(minId, maxId);
521 },
522
523 /**
524 * @override
525 * @return {!Array.<!WebInspector.ToolbarItem>}
526 */
527 syncToolbarItems: function()
528 {
529 var result = [this._perspectiveSelect, this._classNameFilter];
530 if (this._profile.profileType() !== WebInspector.ProfileTypeRegistry.ins tance.trackingHeapSnapshotProfileType)
531 result.push(this._baseSelect, this._filterSelect);
532 result.push(this._selectedSizeText);
533 return result;
534 },
535
536 /**
537 * @override
538 */
539 wasShown: function()
540 {
541 this._profile._loadPromise.then(this._profile._wasShown.bind(this._profi le));
542 },
543
544 /**
545 * @override
546 */
547 willHide: function()
548 {
549 this._currentSearchResultIndex = -1;
550 this._popoverHelper.hidePopover();
551 if (this.helpPopover && this.helpPopover.isShowing())
552 this.helpPopover.hide();
553 },
554
555 /**
556 * @override
557 * @return {boolean}
558 */
559 supportsCaseSensitiveSearch: function()
560 {
561 return true;
562 },
563
564 /**
565 * @override
566 * @return {boolean}
567 */
568 supportsRegexSearch: function()
569 {
570 return false;
571 },
572
573 /**
574 * @override
575 */
576 searchCanceled: function()
577 {
578 this._currentSearchResultIndex = -1;
579 this._searchResults = [];
580 },
581 594
582 /** 595 /**
583 * @param {?WebInspector.HeapSnapshotGridNode} node 596 * @param {?WebInspector.HeapSnapshotGridNode} node
584 */ 597 */
585 _selectRevealedNode: function(node) 598 function didRevealObject(node) {
586 { 599 if (node)
587 if (node) 600 node.select();
588 node.select(); 601 else
589 }, 602 WebInspector.console.error('Cannot find corresponding heap snapshot node ');
603 }
604 }
605
606 _getHoverAnchor(target) {
607 var span = target.enclosingNodeOrSelfWithNodeName('span');
608 if (!span)
609 return;
610 var row = target.enclosingNodeOrSelfWithNodeName('tr');
611 if (!row)
612 return;
613 span.node = row._dataGridNode;
614 return span;
615 }
616
617 _resolveObjectForPopover(element, showCallback, objectGroupName) {
618 if (!this._profile.target())
619 return;
620 if (!element.node)
621 return;
622 element.node.queryObjectContent(this._profile.target(), showCallback, object GroupName);
623 }
624
625 _updateBaseOptions() {
626 var list = this._profiles();
627 // We're assuming that snapshots can only be added.
628 if (this._baseSelect.size() === list.length)
629 return;
630
631 for (var i = this._baseSelect.size(), n = list.length; i < n; ++i) {
632 var title = list[i].title;
633 this._baseSelect.createOption(title);
634 }
635 }
636
637 _updateFilterOptions() {
638 var list = this._profiles();
639 // We're assuming that snapshots can only be added.
640 if (this._filterSelect.size() - 1 === list.length)
641 return;
642
643 if (!this._filterSelect.size())
644 this._filterSelect.createOption(WebInspector.UIString('All objects'));
645
646 for (var i = this._filterSelect.size() - 1, n = list.length; i < n; ++i) {
647 var title = list[i].title;
648 if (!i)
649 title = WebInspector.UIString('Objects allocated before %s', title);
650 else
651 title = WebInspector.UIString('Objects allocated between %s and %s', lis t[i - 1].title, title);
652 this._filterSelect.createOption(title);
653 }
654 }
655
656 _updateControls() {
657 this._updateBaseOptions();
658 this._updateFilterOptions();
659 }
660
661 /**
662 * @param {!WebInspector.Event} event
663 */
664 _onReceiveSnapshot(event) {
665 this._updateControls();
666 }
667
668 /**
669 * @param {!WebInspector.Event} event
670 */
671 _onProfileHeaderRemoved(event) {
672 var profile = event.data;
673 if (this._profile === profile) {
674 this.detach();
675 this._profile.profileType().removeEventListener(
676 WebInspector.HeapSnapshotProfileType.SnapshotReceived, this._onReceive Snapshot, this);
677 this._profile.profileType().removeEventListener(
678 WebInspector.ProfileType.Events.RemoveProfileHeader, this._onProfileHe aderRemoved, this);
679 this.dispose();
680 } else {
681 this._updateControls();
682 }
683 }
684
685 dispose() {
686 if (this._allocationStackView) {
687 this._allocationStackView.clear();
688 this._allocationDataGrid.dispose();
689 }
690 if (this._trackingOverviewGrid)
691 this._trackingOverviewGrid.dispose();
692 }
693 };
694
695 /**
696 * @unrestricted
697 */
698 WebInspector.HeapSnapshotView.Perspective = class {
699 /**
700 * @param {string} title
701 */
702 constructor(title) {
703 this._title = title;
704 }
705
706 /**
707 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
708 */
709 activate(heapSnapshotView) {
710 }
711
712 /**
713 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
714 */
715 deactivate(heapSnapshotView) {
716 heapSnapshotView._baseSelect.setVisible(false);
717 heapSnapshotView._filterSelect.setVisible(false);
718 heapSnapshotView._classNameFilter.setVisible(false);
719 if (heapSnapshotView._trackingOverviewGrid)
720 heapSnapshotView._trackingOverviewGrid.detach();
721 if (heapSnapshotView._allocationWidget)
722 heapSnapshotView._allocationWidget.detach();
723 if (heapSnapshotView._statisticsView)
724 heapSnapshotView._statisticsView.detach();
725
726 heapSnapshotView._splitWidget.detach();
727 heapSnapshotView._splitWidget.detachChildWidgets();
728 }
729
730 /**
731 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
732 * @return {?WebInspector.DataGrid}
733 */
734 masterGrid(heapSnapshotView) {
735 return null;
736 }
737
738 /**
739 * @return {string}
740 */
741 title() {
742 return this._title;
743 }
744
745 /**
746 * @return {boolean}
747 */
748 supportsSearch() {
749 return false;
750 }
751 };
752
753 /**
754 * @unrestricted
755 */
756 WebInspector.HeapSnapshotView.SummaryPerspective = class extends WebInspector.He apSnapshotView.Perspective {
757 constructor() {
758 super(WebInspector.UIString('Summary'));
759 }
760
761 /**
762 * @override
763 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
764 */
765 activate(heapSnapshotView) {
766 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._constructorsWi dget);
767 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectDetai lsView);
768 heapSnapshotView._splitWidget.show(heapSnapshotView._searchableView.element) ;
769 heapSnapshotView._filterSelect.setVisible(true);
770 heapSnapshotView._classNameFilter.setVisible(true);
771 if (heapSnapshotView._trackingOverviewGrid) {
772 heapSnapshotView._trackingOverviewGrid.show(
773 heapSnapshotView._searchableView.element, heapSnapshotView._splitWidge t.element);
774 heapSnapshotView._trackingOverviewGrid.update();
775 heapSnapshotView._trackingOverviewGrid._updateGrid();
776 }
777 }
778
779 /**
780 * @override
781 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
782 * @return {?WebInspector.DataGrid}
783 */
784 masterGrid(heapSnapshotView) {
785 return heapSnapshotView._constructorsDataGrid;
786 }
787
788 /**
789 * @override
790 * @return {boolean}
791 */
792 supportsSearch() {
793 return true;
794 }
795 };
796
797 /**
798 * @unrestricted
799 */
800 WebInspector.HeapSnapshotView.ComparisonPerspective = class extends WebInspector .HeapSnapshotView.Perspective {
801 constructor() {
802 super(WebInspector.UIString('Comparison'));
803 }
804
805 /**
806 * @override
807 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
808 */
809 activate(heapSnapshotView) {
810 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._diffWidget);
811 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectDetai lsView);
812 heapSnapshotView._splitWidget.show(heapSnapshotView._searchableView.element) ;
813 heapSnapshotView._baseSelect.setVisible(true);
814 heapSnapshotView._classNameFilter.setVisible(true);
815 }
816
817 /**
818 * @override
819 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
820 * @return {?WebInspector.DataGrid}
821 */
822 masterGrid(heapSnapshotView) {
823 return heapSnapshotView._diffDataGrid;
824 }
825
826 /**
827 * @override
828 * @return {boolean}
829 */
830 supportsSearch() {
831 return true;
832 }
833 };
834
835 /**
836 * @unrestricted
837 */
838 WebInspector.HeapSnapshotView.ContainmentPerspective = class extends WebInspecto r.HeapSnapshotView.Perspective {
839 constructor() {
840 super(WebInspector.UIString('Containment'));
841 }
842
843 /**
844 * @override
845 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
846 */
847 activate(heapSnapshotView) {
848 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._containmentWid get);
849 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectDetai lsView);
850 heapSnapshotView._splitWidget.show(heapSnapshotView._searchableView.element) ;
851 }
852
853 /**
854 * @override
855 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
856 * @return {?WebInspector.DataGrid}
857 */
858 masterGrid(heapSnapshotView) {
859 return heapSnapshotView._containmentDataGrid;
860 }
861 };
862
863 /**
864 * @unrestricted
865 */
866 WebInspector.HeapSnapshotView.AllocationPerspective = class extends WebInspector .HeapSnapshotView.Perspective {
867 constructor() {
868 super(WebInspector.UIString('Allocation'));
869 this._allocationSplitWidget =
870 new WebInspector.SplitWidget(false, true, 'heapSnapshotAllocationSplitVi ewState', 200, 200);
871 this._allocationSplitWidget.setSidebarWidget(new WebInspector.VBox());
872 }
873
874 /**
875 * @override
876 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
877 */
878 activate(heapSnapshotView) {
879 this._allocationSplitWidget.setMainWidget(heapSnapshotView._allocationWidget );
880 heapSnapshotView._splitWidget.setMainWidget(heapSnapshotView._constructorsWi dget);
881 heapSnapshotView._splitWidget.setSidebarWidget(heapSnapshotView._objectDetai lsView);
882
883 var allocatedObjectsView = new WebInspector.VBox();
884 var resizer = createElementWithClass('div', 'heap-snapshot-view-resizer');
885 var title = resizer.createChild('div', 'title').createChild('span');
886 title.textContent = WebInspector.UIString('Live objects');
887 this._allocationSplitWidget.hideDefaultResizer();
888 this._allocationSplitWidget.installResizer(resizer);
889 allocatedObjectsView.element.appendChild(resizer);
890 heapSnapshotView._splitWidget.show(allocatedObjectsView.element);
891 this._allocationSplitWidget.setSidebarWidget(allocatedObjectsView);
892
893 this._allocationSplitWidget.show(heapSnapshotView._searchableView.element);
894
895 heapSnapshotView._constructorsDataGrid.clear();
896 var selectedNode = heapSnapshotView._allocationDataGrid.selectedNode;
897 if (selectedNode)
898 heapSnapshotView._constructorsDataGrid.setAllocationNodeId(selectedNode.al locationNodeId());
899 }
900
901 /**
902 * @override
903 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
904 */
905 deactivate(heapSnapshotView) {
906 this._allocationSplitWidget.detach();
907 super.deactivate(heapSnapshotView);
908 }
909
910 /**
911 * @override
912 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
913 * @return {?WebInspector.DataGrid}
914 */
915 masterGrid(heapSnapshotView) {
916 return heapSnapshotView._allocationDataGrid;
917 }
918 };
919
920 /**
921 * @unrestricted
922 */
923 WebInspector.HeapSnapshotView.StatisticsPerspective = class extends WebInspector .HeapSnapshotView.Perspective {
924 constructor() {
925 super(WebInspector.UIString('Statistics'));
926 }
927
928 /**
929 * @override
930 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
931 */
932 activate(heapSnapshotView) {
933 heapSnapshotView._statisticsView.show(heapSnapshotView._searchableView.eleme nt);
934 }
935
936 /**
937 * @override
938 * @param {!WebInspector.HeapSnapshotView} heapSnapshotView
939 * @return {?WebInspector.DataGrid}
940 */
941 masterGrid(heapSnapshotView) {
942 return null;
943 }
944 };
945
946 /**
947 * @implements {WebInspector.TargetManager.Observer}
948 * @unrestricted
949 */
950 WebInspector.HeapSnapshotProfileType = class extends WebInspector.ProfileType {
951 /**
952 * @param {string=} id
953 * @param {string=} title
954 */
955 constructor(id, title) {
956 super(id || WebInspector.HeapSnapshotProfileType.TypeId, title || WebInspect or.UIString('Take Heap Snapshot'));
957 WebInspector.targetManager.observeTargets(this);
958 WebInspector.targetManager.addModelListener(
959 WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.Re setProfiles, this._resetProfiles, this);
960 WebInspector.targetManager.addModelListener(
961 WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.Ad dHeapSnapshotChunk,
962 this._addHeapSnapshotChunk, this);
963 WebInspector.targetManager.addModelListener(
964 WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.Re portHeapSnapshotProgress,
965 this._reportHeapSnapshotProgress, this);
966 }
967
968 /**
969 * @override
970 * @param {!WebInspector.Target} target
971 */
972 targetAdded(target) {
973 target.heapProfilerModel.enable();
974 }
975
976 /**
977 * @override
978 * @param {!WebInspector.Target} target
979 */
980 targetRemoved(target) {
981 }
982
983 /**
984 * @override
985 * @return {string}
986 */
987 fileExtension() {
988 return '.heapsnapshot';
989 }
990
991 get buttonTooltip() {
992 return WebInspector.UIString('Take heap snapshot');
993 }
994
995 /**
996 * @override
997 * @return {boolean}
998 */
999 isInstantProfile() {
1000 return true;
1001 }
1002
1003 /**
1004 * @override
1005 * @return {boolean}
1006 */
1007 buttonClicked() {
1008 this._takeHeapSnapshot(function() {});
1009 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.Profile sHeapProfileTaken);
1010 return false;
1011 }
1012
1013 get treeItemTitle() {
1014 return WebInspector.UIString('HEAP SNAPSHOTS');
1015 }
1016
1017 get description() {
1018 return WebInspector.UIString(
1019 'Heap snapshot profiles show memory distribution among your page\'s Java Script objects and related DOM nodes.');
1020 }
1021
1022 /**
1023 * @override
1024 * @param {string} title
1025 * @return {!WebInspector.ProfileHeader}
1026 */
1027 createProfileLoadedFromFile(title) {
1028 return new WebInspector.HeapProfileHeader(null, this, title);
1029 }
1030
1031 _takeHeapSnapshot(callback) {
1032 if (this.profileBeingRecorded())
1033 return;
1034 var target = /** @type {!WebInspector.Target} */ (WebInspector.context.flavo r(WebInspector.Target));
1035 var profile = new WebInspector.HeapProfileHeader(target, this);
1036 this.setProfileBeingRecorded(profile);
1037 this.addProfile(profile);
1038 profile.updateStatus(WebInspector.UIString('Snapshotting\u2026'));
590 1039
591 /** 1040 /**
592 * @override 1041 * @param {?string} error
593 * @param {!WebInspector.SearchableView.SearchConfig} searchConfig 1042 * @this {WebInspector.HeapSnapshotProfileType}
594 * @param {boolean} shouldJump
595 * @param {boolean=} jumpBackwards
596 */ 1043 */
597 performSearch: function(searchConfig, shouldJump, jumpBackwards) 1044 function didTakeHeapSnapshot(error) {
598 { 1045 var profile = this._profileBeingRecorded;
599 var nextQuery = new WebInspector.HeapSnapshotCommon.SearchConfig( 1046 profile.title = WebInspector.UIString('Snapshot %d', profile.uid);
600 searchConfig.query.trim(), 1047 profile._finishLoad();
601 searchConfig.caseSensitive, 1048 this.setProfileBeingRecorded(null);
602 searchConfig.isRegex, 1049 this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProfileCompl ete, profile);
603 shouldJump, 1050 callback();
604 jumpBackwards || false 1051 }
605 ); 1052 target.heapProfilerAgent().takeHeapSnapshot(true, didTakeHeapSnapshot.bind(t his));
606 1053 }
607 this._searchThrottler.schedule(this._performSearch.bind(this, nextQuery) ); 1054
608 }, 1055 /**
609 1056 * @param {!WebInspector.Event} event
1057 */
1058 _addHeapSnapshotChunk(event) {
1059 if (!this.profileBeingRecorded())
1060 return;
1061 var chunk = /** @type {string} */ (event.data);
1062 this.profileBeingRecorded().transferChunk(chunk);
1063 }
1064
1065 /**
1066 * @param {!WebInspector.Event} event
1067 */
1068 _reportHeapSnapshotProgress(event) {
1069 var profile = this.profileBeingRecorded();
1070 if (!profile)
1071 return;
1072 var data = /** @type {{done: number, total: number, finished: boolean}} */ ( event.data);
1073 profile.updateStatus(WebInspector.UIString('%.0f%%', (data.done / data.total ) * 100), true);
1074 if (data.finished)
1075 profile._prepareToLoad();
1076 }
1077
1078 _resetProfiles() {
1079 this._reset();
1080 }
1081
1082 _snapshotReceived(profile) {
1083 if (this._profileBeingRecorded === profile)
1084 this.setProfileBeingRecorded(null);
1085 this.dispatchEventToListeners(WebInspector.HeapSnapshotProfileType.SnapshotR eceived, profile);
1086 }
1087 };
1088
1089 WebInspector.HeapSnapshotProfileType.TypeId = 'HEAP';
1090 WebInspector.HeapSnapshotProfileType.SnapshotReceived = 'SnapshotReceived';
1091
1092 /**
1093 * @unrestricted
1094 */
1095 WebInspector.TrackingHeapSnapshotProfileType = class extends WebInspector.HeapSn apshotProfileType {
1096 constructor() {
1097 super(WebInspector.TrackingHeapSnapshotProfileType.TypeId, WebInspector.UISt ring('Record Allocation Timeline'));
1098 }
1099
1100 /**
1101 * @override
1102 * @param {!WebInspector.Target} target
1103 */
1104 targetAdded(target) {
1105 super.targetAdded(target);
1106 target.heapProfilerModel.addEventListener(
1107 WebInspector.HeapProfilerModel.Events.HeapStatsUpdate, this._heapStatsUp date, this);
1108 target.heapProfilerModel.addEventListener(
1109 WebInspector.HeapProfilerModel.Events.LastSeenObjectId, this._lastSeenOb jectId, this);
1110 }
1111
1112 /**
1113 * @override
1114 * @param {!WebInspector.Target} target
1115 */
1116 targetRemoved(target) {
1117 super.targetRemoved(target);
1118 target.heapProfilerModel.removeEventListener(
1119 WebInspector.HeapProfilerModel.Events.HeapStatsUpdate, this._heapStatsUp date, this);
1120 target.heapProfilerModel.removeEventListener(
1121 WebInspector.HeapProfilerModel.Events.LastSeenObjectId, this._lastSeenOb jectId, this);
1122 }
1123
1124 /**
1125 * @param {!WebInspector.Event} event
1126 */
1127 _heapStatsUpdate(event) {
1128 if (!this._profileSamples)
1129 return;
1130 var samples = /** @type {!Array.<number>} */ (event.data);
1131 var index;
1132 for (var i = 0; i < samples.length; i += 3) {
1133 index = samples[i];
1134 var size = samples[i + 2];
1135 this._profileSamples.sizes[index] = size;
1136 if (!this._profileSamples.max[index])
1137 this._profileSamples.max[index] = size;
1138 }
1139 }
1140
1141 /**
1142 * @param {!WebInspector.Event} event
1143 */
1144 _lastSeenObjectId(event) {
1145 var profileSamples = this._profileSamples;
1146 if (!profileSamples)
1147 return;
1148 var data = /** @type {{lastSeenObjectId: number, timestamp: number}} */ (eve nt.data);
1149 var currentIndex = Math.max(profileSamples.ids.length, profileSamples.max.le ngth - 1);
1150 profileSamples.ids[currentIndex] = data.lastSeenObjectId;
1151 if (!profileSamples.max[currentIndex]) {
1152 profileSamples.max[currentIndex] = 0;
1153 profileSamples.sizes[currentIndex] = 0;
1154 }
1155 profileSamples.timestamps[currentIndex] = data.timestamp;
1156 if (profileSamples.totalTime < data.timestamp - profileSamples.timestamps[0] )
1157 profileSamples.totalTime *= 2;
1158 this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.H eapStatsUpdate, this._profileSamples);
1159 this._profileBeingRecorded.updateStatus(null, true);
1160 }
1161
1162 /**
1163 * @override
1164 * @return {boolean}
1165 */
1166 hasTemporaryView() {
1167 return true;
1168 }
1169
1170 get buttonTooltip() {
1171 return this._recording ? WebInspector.UIString('Stop recording heap profile' ) :
1172 WebInspector.UIString('Start recording heap profile ');
1173 }
1174
1175 /**
1176 * @override
1177 * @return {boolean}
1178 */
1179 isInstantProfile() {
1180 return false;
1181 }
1182
1183 /**
1184 * @override
1185 * @return {boolean}
1186 */
1187 buttonClicked() {
1188 return this._toggleRecording();
1189 }
1190
1191 _startRecordingProfile() {
1192 if (this.profileBeingRecorded())
1193 return;
1194 this._addNewProfile();
1195 var recordAllocationStacks = WebInspector.moduleSetting('recordAllocationSta cks').get();
1196 this.profileBeingRecorded().target().heapProfilerAgent().startTrackingHeapOb jects(recordAllocationStacks);
1197 }
1198
1199 _addNewProfile() {
1200 var target = WebInspector.context.flavor(WebInspector.Target);
1201 this.setProfileBeingRecorded(new WebInspector.HeapProfileHeader(target, this , undefined));
1202 this._profileSamples = new WebInspector.TrackingHeapSnapshotProfileType.Samp les();
1203 this._profileBeingRecorded._profileSamples = this._profileSamples;
1204 this._recording = true;
1205 this.addProfile(this._profileBeingRecorded);
1206 this._profileBeingRecorded.updateStatus(WebInspector.UIString('Recording\u20 26'));
1207 this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.T rackingStarted);
1208 }
1209
1210 _stopRecordingProfile() {
1211 this._profileBeingRecorded.updateStatus(WebInspector.UIString('Snapshotting\ u2026'));
610 /** 1212 /**
611 * @param {!WebInspector.HeapSnapshotCommon.SearchConfig} nextQuery 1213 * @param {?string} error
612 * @return {!Promise<?>} 1214 * @this {WebInspector.HeapSnapshotProfileType}
613 */ 1215 */
614 _performSearch: function(nextQuery) 1216 function didTakeHeapSnapshot(error) {
615 { 1217 var profile = this.profileBeingRecorded();
616 // Call searchCanceled since it will reset everything we need before doi ng a new search. 1218 if (!profile)
617 this.searchCanceled(); 1219 return;
618 1220 profile._finishLoad();
619 if (!this._currentPerspective.supportsSearch()) 1221 this._profileSamples = null;
620 return Promise.resolve(); 1222 this.setProfileBeingRecorded(null);
621 1223 this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProfileCompl ete, profile);
622 this.currentQuery = nextQuery; 1224 }
623 var query = nextQuery.query.trim(); 1225
624 1226 this._profileBeingRecorded.target().heapProfilerAgent().stopTrackingHeapObje cts(
625 if (!query) 1227 true, didTakeHeapSnapshot.bind(this));
626 return Promise.resolve(); 1228 this._recording = false;
627 1229 this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.T rackingStopped);
628 if (query.charAt(0) === "@") { 1230 }
629 var snapshotNodeId = parseInt(query.substring(1), 10); 1231
630 if (isNaN(snapshotNodeId)) 1232 _toggleRecording() {
631 return Promise.resolve(); 1233 if (this._recording)
632 return this._dataGrid.revealObjectByHeapSnapshotId(String(snapshotNo deId)).then(this._selectRevealedNode.bind(this)); 1234 this._stopRecordingProfile();
633 } 1235 else
634 1236 this._startRecordingProfile();
635 /** 1237 return this._recording;
636 * @param {!Array<number>} entryIds 1238 }
637 * @return {!Promise<?>} 1239
638 * @this {WebInspector.HeapSnapshotView} 1240 /**
639 */ 1241 * @override
640 function didSearch(entryIds) 1242 * @return {string}
641 { 1243 */
642 this._searchResults = entryIds; 1244 fileExtension() {
643 this._searchableView.updateSearchMatchesCount(this._searchResults.le ngth); 1245 return '.heaptimeline';
644 if (this._searchResults.length) 1246 }
645 this._currentSearchResultIndex = nextQuery.jumpBackwards ? this. _searchResults.length - 1 : 0; 1247
646 return this._jumpToSearchResult(this._currentSearchResultIndex); 1248 get treeItemTitle() {
647 } 1249 return WebInspector.UIString('ALLOCATION TIMELINES');
648 1250 }
649 return this._profile._snapshotProxy.search(this.currentQuery, this._data Grid.nodeFilter()).then(didSearch.bind(this)); 1251
650 }, 1252 get description() {
651 1253 return WebInspector.UIString(
652 /** 1254 'Allocation timelines show memory allocations from your heap over time. Use this profile type to isolate memory leaks.');
653 * @override 1255 }
654 */ 1256
655 jumpToNextSearchResult: function() 1257 /**
656 { 1258 * @override
657 if (!this._searchResults.length) 1259 */
658 return; 1260 _resetProfiles() {
659 this._currentSearchResultIndex = (this._currentSearchResultIndex + 1) % this._searchResults.length; 1261 var wasRecording = this._recording;
660 this._searchThrottler.schedule(this._jumpToSearchResult.bind(this, this. _currentSearchResultIndex)); 1262 // Clear current profile to avoid stopping backend.
661 }, 1263 this.setProfileBeingRecorded(null);
662 1264 super._resetProfiles();
663 /** 1265 this._profileSamples = null;
664 * @override 1266 if (wasRecording)
665 */ 1267 this._addNewProfile();
666 jumpToPreviousSearchResult: function() 1268 }
667 { 1269
668 if (!this._searchResults.length) 1270 /**
669 return; 1271 * @override
670 this._currentSearchResultIndex = (this._currentSearchResultIndex + this. _searchResults.length - 1) % this._searchResults.length; 1272 */
671 this._searchThrottler.schedule(this._jumpToSearchResult.bind(this, this. _currentSearchResultIndex)); 1273 profileBeingRecordedRemoved() {
672 }, 1274 this._stopRecordingProfile();
673 1275 this._profileSamples = null;
674 /** 1276 }
675 * @param {number} searchResultIndex
676 * @return {!Promise<undefined>}
677 */
678 _jumpToSearchResult: function(searchResultIndex)
679 {
680 this._searchableView.updateCurrentMatchIndex(searchResultIndex);
681 return this._dataGrid.revealObjectByHeapSnapshotId(String(this._searchRe sults[searchResultIndex])).then(this._selectRevealedNode.bind(this));
682 },
683
684 refreshVisibleData: function()
685 {
686 if (!this._dataGrid)
687 return;
688 var child = this._dataGrid.rootNode().children[0];
689 while (child) {
690 child.refresh();
691 child = child.traverseNextNode(false, null, true);
692 }
693 },
694
695 _changeBase: function()
696 {
697 if (this._baseProfile === this._profiles()[this._baseSelect.selectedInde x()])
698 return;
699
700 this._baseProfile = this._profiles()[this._baseSelect.selectedIndex()];
701 var dataGrid = /** @type {!WebInspector.HeapSnapshotDiffDataGrid} */ (th is._dataGrid);
702 // Change set base data source only if main data source is already set.
703 if (dataGrid.snapshot)
704 this._baseProfile._loadPromise.then(dataGrid.setBaseDataSource.bind( dataGrid));
705
706 if (!this.currentQuery || !this._searchResults)
707 return;
708
709 // The current search needs to be performed again. First negate out prev ious match
710 // count by calling the search finished callback with a negative number of matches.
711 // Then perform the search again with the same query and callback.
712 this.performSearch(this.currentQuery, false);
713 },
714
715 _changeFilter: function()
716 {
717 var profileIndex = this._filterSelect.selectedIndex() - 1;
718 this._dataGrid.filterSelectIndexChanged(this._profiles(), profileIndex);
719
720 if (!this.currentQuery || !this._searchResults)
721 return;
722
723 // The current search needs to be performed again. First negate out prev ious match
724 // count by calling the search finished callback with a negative number of matches.
725 // Then perform the search again with the same query and callback.
726 this.performSearch(this.currentQuery, false);
727 },
728
729 /**
730 * @return {!Array.<!WebInspector.ProfileHeader>}
731 */
732 _profiles: function()
733 {
734 return this._profile.profileType().getProfiles();
735 },
736
737 /**
738 * @param {!WebInspector.ContextMenu} contextMenu
739 * @param {!Event} event
740 */
741 populateContextMenu: function(contextMenu, event)
742 {
743 if (this._dataGrid)
744 this._dataGrid.populateContextMenu(contextMenu, event);
745 },
746
747 _selectionChanged: function(event)
748 {
749 var selectedNode = event.target.selectedNode;
750 this._setSelectedNodeForDetailsView(selectedNode);
751 this._inspectedObjectChanged(event);
752 },
753
754 _onSelectAllocationNode: function(event)
755 {
756 var selectedNode = event.target.selectedNode;
757 this._constructorsDataGrid.setAllocationNodeId(selectedNode.allocationNo deId());
758 this._setSelectedNodeForDetailsView(null);
759 },
760
761 _inspectedObjectChanged: function(event)
762 {
763 var selectedNode = event.target.selectedNode;
764 var target = this._profile.target();
765 if (target && selectedNode instanceof WebInspector.HeapSnapshotGenericOb jectNode)
766 target.heapProfilerAgent().addInspectedHeapObject(String(selectedNod e.snapshotNodeId));
767 },
768
769 /**
770 * @param {?WebInspector.HeapSnapshotGridNode} nodeItem
771 */
772 _setSelectedNodeForDetailsView: function(nodeItem)
773 {
774 var dataSource = nodeItem && nodeItem.retainersDataSource();
775 if (dataSource) {
776 this._retainmentDataGrid.setDataSource(dataSource.snapshot, dataSour ce.snapshotNodeIndex);
777 if (this._allocationStackView)
778 this._allocationStackView.setAllocatedObject(dataSource.snapshot , dataSource.snapshotNodeIndex);
779 } else {
780 if (this._allocationStackView)
781 this._allocationStackView.clear();
782 this._retainmentDataGrid.reset();
783 }
784 },
785
786 /**
787 * @param {string} perspectiveTitle
788 * @param {function()} callback
789 */
790 _changePerspectiveAndWait: function(perspectiveTitle, callback)
791 {
792 var perspectiveIndex = null;
793 for (var i = 0; i < this._perspectives.length; ++i) {
794 if (this._perspectives[i].title() === perspectiveTitle) {
795 perspectiveIndex = i;
796 break;
797 }
798 }
799 if (this._currentPerspectiveIndex === perspectiveIndex || perspectiveInd ex === null) {
800 setTimeout(callback, 0);
801 return;
802 }
803
804 /**
805 * @this {WebInspector.HeapSnapshotView}
806 */
807 function dataGridContentShown(event)
808 {
809 var dataGrid = event.data;
810 dataGrid.removeEventListener(WebInspector.HeapSnapshotSortableDataGr id.Events.ContentShown, dataGridContentShown, this);
811 if (dataGrid === this._dataGrid)
812 callback();
813 }
814 this._perspectives[perspectiveIndex].masterGrid(this).addEventListener(W ebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentSho wn, this);
815
816 this._perspectiveSelect.setSelectedIndex(perspectiveIndex);
817 this._changePerspective(perspectiveIndex);
818 },
819
820 _updateDataSourceAndView: function()
821 {
822 var dataGrid = this._dataGrid;
823 if (!dataGrid || dataGrid.snapshot)
824 return;
825
826 this._profile._loadPromise.then(didLoadSnapshot.bind(this));
827
828 /**
829 * @this {WebInspector.HeapSnapshotView}
830 */
831 function didLoadSnapshot(snapshotProxy)
832 {
833 if (this._dataGrid !== dataGrid)
834 return;
835 if (dataGrid.snapshot !== snapshotProxy)
836 dataGrid.setDataSource(snapshotProxy);
837 if (dataGrid === this._diffDataGrid) {
838 if (!this._baseProfile)
839 this._baseProfile = this._profiles()[this._baseSelect.select edIndex()];
840 this._baseProfile._loadPromise.then(didLoadBaseSnapshot.bind(thi s));
841 }
842 }
843
844 /**
845 * @this {WebInspector.HeapSnapshotView}
846 */
847 function didLoadBaseSnapshot(baseSnapshotProxy)
848 {
849 if (this._diffDataGrid.baseSnapshot !== baseSnapshotProxy)
850 this._diffDataGrid.setBaseDataSource(baseSnapshotProxy);
851 }
852 },
853
854 _onSelectedPerspectiveChanged: function(event)
855 {
856 this._changePerspective(event.target.selectedIndex);
857 },
858
859 /**
860 * @param {number} selectedIndex
861 */
862 _changePerspective: function(selectedIndex)
863 {
864 if (selectedIndex === this._currentPerspectiveIndex)
865 return;
866
867 this._currentPerspectiveIndex = selectedIndex;
868
869 this._currentPerspective.deactivate(this);
870 var perspective = this._perspectives[selectedIndex];
871 this._currentPerspective = perspective;
872 this._dataGrid = perspective.masterGrid(this);
873 perspective.activate(this);
874
875 this.refreshVisibleData();
876 if (this._dataGrid)
877 this._dataGrid.updateWidths();
878
879 this._updateDataSourceAndView();
880
881 if (!this.currentQuery || !this._searchResults)
882 return;
883
884 // The current search needs to be performed again. First negate out prev ious match
885 // count by calling the search finished callback with a negative number of matches.
886 // Then perform the search again the with same query and callback.
887 this.performSearch(this.currentQuery, false);
888 },
889
890 /**
891 * @param {string} perspectiveName
892 * @param {!HeapProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
893 */
894 selectLiveObject: function(perspectiveName, snapshotObjectId)
895 {
896 this._changePerspectiveAndWait(perspectiveName, didChangePerspective.bin d(this));
897
898 /**
899 * @this {WebInspector.HeapSnapshotView}
900 */
901 function didChangePerspective()
902 {
903 this._dataGrid.revealObjectByHeapSnapshotId(snapshotObjectId, didRev ealObject);
904 }
905
906 /**
907 * @param {?WebInspector.HeapSnapshotGridNode} node
908 */
909 function didRevealObject(node)
910 {
911 if (node)
912 node.select();
913 else
914 WebInspector.console.error("Cannot find corresponding heap snaps hot node");
915 }
916 },
917
918 _getHoverAnchor: function(target)
919 {
920 var span = target.enclosingNodeOrSelfWithNodeName("span");
921 if (!span)
922 return;
923 var row = target.enclosingNodeOrSelfWithNodeName("tr");
924 if (!row)
925 return;
926 span.node = row._dataGridNode;
927 return span;
928 },
929
930 _resolveObjectForPopover: function(element, showCallback, objectGroupName)
931 {
932 if (!this._profile.target())
933 return;
934 if (!element.node)
935 return;
936 element.node.queryObjectContent(this._profile.target(), showCallback, ob jectGroupName);
937 },
938
939 _updateBaseOptions: function()
940 {
941 var list = this._profiles();
942 // We're assuming that snapshots can only be added.
943 if (this._baseSelect.size() === list.length)
944 return;
945
946 for (var i = this._baseSelect.size(), n = list.length; i < n; ++i) {
947 var title = list[i].title;
948 this._baseSelect.createOption(title);
949 }
950 },
951
952 _updateFilterOptions: function()
953 {
954 var list = this._profiles();
955 // We're assuming that snapshots can only be added.
956 if (this._filterSelect.size() - 1 === list.length)
957 return;
958
959 if (!this._filterSelect.size())
960 this._filterSelect.createOption(WebInspector.UIString("All objects") );
961
962 for (var i = this._filterSelect.size() - 1, n = list.length; i < n; ++i) {
963 var title = list[i].title;
964 if (!i)
965 title = WebInspector.UIString("Objects allocated before %s", tit le);
966 else
967 title = WebInspector.UIString("Objects allocated between %s and %s", list[i - 1].title, title);
968 this._filterSelect.createOption(title);
969 }
970 },
971
972 _updateControls: function()
973 {
974 this._updateBaseOptions();
975 this._updateFilterOptions();
976 },
977
978 /**
979 * @param {!WebInspector.Event} event
980 */
981 _onReceiveSnapshot: function(event)
982 {
983 this._updateControls();
984 },
985
986 /**
987 * @param {!WebInspector.Event} event
988 */
989 _onProfileHeaderRemoved: function(event)
990 {
991 var profile = event.data;
992 if (this._profile === profile) {
993 this.detach();
994 this._profile.profileType().removeEventListener(WebInspector.HeapSna pshotProfileType.SnapshotReceived, this._onReceiveSnapshot, this);
995 this._profile.profileType().removeEventListener(WebInspector.Profile Type.Events.RemoveProfileHeader, this._onProfileHeaderRemoved, this);
996 this.dispose();
997 } else {
998 this._updateControls();
999 }
1000 },
1001
1002 dispose: function()
1003 {
1004 if (this._allocationStackView) {
1005 this._allocationStackView.clear();
1006 this._allocationDataGrid.dispose();
1007 }
1008 if (this._trackingOverviewGrid)
1009 this._trackingOverviewGrid.dispose();
1010 },
1011
1012 __proto__: WebInspector.SimpleView.prototype
1013 }; 1277 };
1014 1278
1279 WebInspector.TrackingHeapSnapshotProfileType.TypeId = 'HEAP-RECORD';
1280
1281 WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate = 'HeapStatsUpdate' ;
1282 WebInspector.TrackingHeapSnapshotProfileType.TrackingStarted = 'TrackingStarted' ;
1283 WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped = 'TrackingStopped' ;
1284
1015 /** 1285 /**
1016 * @constructor 1286 * @unrestricted
1017 * @extends {WebInspector.ProfileType}
1018 * @implements {WebInspector.TargetManager.Observer}
1019 * @param {string=} id
1020 * @param {string=} title
1021 */ 1287 */
1022 WebInspector.HeapSnapshotProfileType = function(id, title) 1288 WebInspector.TrackingHeapSnapshotProfileType.Samples = class {
1023 { 1289 constructor() {
1024 WebInspector.ProfileType.call(this, id || WebInspector.HeapSnapshotProfileTy pe.TypeId, title || WebInspector.UIString("Take Heap Snapshot"));
1025 WebInspector.targetManager.observeTargets(this);
1026 WebInspector.targetManager.addModelListener(WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.ResetProfiles, this._resetProfiles, this);
1027 WebInspector.targetManager.addModelListener(WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.AddHeapSnapshotChunk, this._addHeapSnapsho tChunk, this);
1028 WebInspector.targetManager.addModelListener(WebInspector.HeapProfilerModel, WebInspector.HeapProfilerModel.Events.ReportHeapSnapshotProgress, this._reportHe apSnapshotProgress, this);
1029 };
1030
1031 WebInspector.HeapSnapshotProfileType.TypeId = "HEAP";
1032 WebInspector.HeapSnapshotProfileType.SnapshotReceived = "SnapshotReceived";
1033
1034 WebInspector.HeapSnapshotProfileType.prototype = {
1035 /**
1036 * @override
1037 * @param {!WebInspector.Target} target
1038 */
1039 targetAdded: function(target)
1040 {
1041 target.heapProfilerModel.enable();
1042 },
1043
1044 /**
1045 * @override
1046 * @param {!WebInspector.Target} target
1047 */
1048 targetRemoved: function(target)
1049 {
1050 },
1051
1052 /**
1053 * @override
1054 * @return {string}
1055 */
1056 fileExtension: function()
1057 {
1058 return ".heapsnapshot";
1059 },
1060
1061 get buttonTooltip()
1062 {
1063 return WebInspector.UIString("Take heap snapshot");
1064 },
1065
1066 /**
1067 * @override
1068 * @return {boolean}
1069 */
1070 isInstantProfile: function()
1071 {
1072 return true;
1073 },
1074
1075 /**
1076 * @override
1077 * @return {boolean}
1078 */
1079 buttonClicked: function()
1080 {
1081 this._takeHeapSnapshot(function() {});
1082 WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.Pro filesHeapProfileTaken);
1083 return false;
1084 },
1085
1086 get treeItemTitle()
1087 {
1088 return WebInspector.UIString("HEAP SNAPSHOTS");
1089 },
1090
1091 get description()
1092 {
1093 return WebInspector.UIString("Heap snapshot profiles show memory distrib ution among your page's JavaScript objects and related DOM nodes.");
1094 },
1095
1096 /**
1097 * @override
1098 * @param {string} title
1099 * @return {!WebInspector.ProfileHeader}
1100 */
1101 createProfileLoadedFromFile: function(title)
1102 {
1103 return new WebInspector.HeapProfileHeader(null, this, title);
1104 },
1105
1106 _takeHeapSnapshot: function(callback)
1107 {
1108 if (this.profileBeingRecorded())
1109 return;
1110 var target = /** @type {!WebInspector.Target} */ (WebInspector.context.f lavor(WebInspector.Target));
1111 var profile = new WebInspector.HeapProfileHeader(target, this);
1112 this.setProfileBeingRecorded(profile);
1113 this.addProfile(profile);
1114 profile.updateStatus(WebInspector.UIString("Snapshotting\u2026"));
1115
1116 /**
1117 * @param {?string} error
1118 * @this {WebInspector.HeapSnapshotProfileType}
1119 */
1120 function didTakeHeapSnapshot(error)
1121 {
1122 var profile = this._profileBeingRecorded;
1123 profile.title = WebInspector.UIString("Snapshot %d", profile.uid);
1124 profile._finishLoad();
1125 this.setProfileBeingRecorded(null);
1126 this.dispatchEventToListeners(WebInspector.ProfileType.Events.Profil eComplete, profile);
1127 callback();
1128 }
1129 target.heapProfilerAgent().takeHeapSnapshot(true, didTakeHeapSnapshot.bi nd(this));
1130 },
1131
1132 /**
1133 * @param {!WebInspector.Event} event
1134 */
1135 _addHeapSnapshotChunk: function(event)
1136 {
1137 if (!this.profileBeingRecorded())
1138 return;
1139 var chunk = /** @type {string} */(event.data);
1140 this.profileBeingRecorded().transferChunk(chunk);
1141 },
1142
1143 /**
1144 * @param {!WebInspector.Event} event
1145 */
1146 _reportHeapSnapshotProgress: function(event)
1147 {
1148 var profile = this.profileBeingRecorded();
1149 if (!profile)
1150 return;
1151 var data = /** @type {{done: number, total: number, finished: boolean}} */ (event.data);
1152 profile.updateStatus(WebInspector.UIString("%.0f%%", (data.done / data.t otal) * 100), true);
1153 if (data.finished)
1154 profile._prepareToLoad();
1155 },
1156
1157 _resetProfiles: function()
1158 {
1159 this._reset();
1160 },
1161
1162 _snapshotReceived: function(profile)
1163 {
1164 if (this._profileBeingRecorded === profile)
1165 this.setProfileBeingRecorded(null);
1166 this.dispatchEventToListeners(WebInspector.HeapSnapshotProfileType.Snaps hotReceived, profile);
1167 },
1168
1169 __proto__: WebInspector.ProfileType.prototype
1170 };
1171
1172
1173 /**
1174 * @constructor
1175 * @extends {WebInspector.HeapSnapshotProfileType}
1176 */
1177 WebInspector.TrackingHeapSnapshotProfileType = function()
1178 {
1179 WebInspector.HeapSnapshotProfileType.call(this, WebInspector.TrackingHeapSna pshotProfileType.TypeId, WebInspector.UIString("Record Allocation Timeline"));
1180 };
1181
1182 WebInspector.TrackingHeapSnapshotProfileType.TypeId = "HEAP-RECORD";
1183
1184 WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate = "HeapStatsUpdate" ;
1185 WebInspector.TrackingHeapSnapshotProfileType.TrackingStarted = "TrackingStarted" ;
1186 WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped = "TrackingStopped" ;
1187
1188
1189 /**
1190 * @constructor
1191 */
1192 WebInspector.TrackingHeapSnapshotProfileType.Samples = function()
1193 {
1194 /** @type {!Array.<number>} */ 1290 /** @type {!Array.<number>} */
1195 this.sizes = []; 1291 this.sizes = [];
1196 /** @type {!Array.<number>} */ 1292 /** @type {!Array.<number>} */
1197 this.ids = []; 1293 this.ids = [];
1198 /** @type {!Array.<number>} */ 1294 /** @type {!Array.<number>} */
1199 this.timestamps = []; 1295 this.timestamps = [];
1200 /** @type {!Array.<number>} */ 1296 /** @type {!Array.<number>} */
1201 this.max = []; 1297 this.max = [];
1202 /** @type {number} */ 1298 /** @type {number} */
1203 this.totalTime = 30000; 1299 this.totalTime = 30000;
1204 }; 1300 }
1205
1206 WebInspector.TrackingHeapSnapshotProfileType.prototype = {
1207
1208 /**
1209 * @override
1210 * @param {!WebInspector.Target} target
1211 */
1212 targetAdded: function(target)
1213 {
1214 WebInspector.HeapSnapshotProfileType.prototype.targetAdded.call(this, ta rget);
1215 target.heapProfilerModel.addEventListener(WebInspector.HeapProfilerModel .Events.HeapStatsUpdate, this._heapStatsUpdate, this);
1216 target.heapProfilerModel.addEventListener(WebInspector.HeapProfilerModel .Events.LastSeenObjectId, this._lastSeenObjectId, this);
1217 },
1218
1219 /**
1220 * @override
1221 * @param {!WebInspector.Target} target
1222 */
1223 targetRemoved: function(target)
1224 {
1225 WebInspector.HeapSnapshotProfileType.prototype.targetRemoved.call(this, target);
1226 target.heapProfilerModel.removeEventListener(WebInspector.HeapProfilerMo del.Events.HeapStatsUpdate, this._heapStatsUpdate, this);
1227 target.heapProfilerModel.removeEventListener(WebInspector.HeapProfilerMo del.Events.LastSeenObjectId, this._lastSeenObjectId, this);
1228 },
1229
1230 /**
1231 * @param {!WebInspector.Event} event
1232 */
1233 _heapStatsUpdate: function(event)
1234 {
1235 if (!this._profileSamples)
1236 return;
1237 var samples = /** @type {!Array.<number>} */ (event.data);
1238 var index;
1239 for (var i = 0; i < samples.length; i += 3) {
1240 index = samples[i];
1241 var size = samples[i + 2];
1242 this._profileSamples.sizes[index] = size;
1243 if (!this._profileSamples.max[index])
1244 this._profileSamples.max[index] = size;
1245 }
1246 },
1247
1248 /**
1249 * @param {!WebInspector.Event} event
1250 */
1251 _lastSeenObjectId: function(event)
1252 {
1253 var profileSamples = this._profileSamples;
1254 if (!profileSamples)
1255 return;
1256 var data = /** @type {{lastSeenObjectId: number, timestamp: number}} */ (event.data);
1257 var currentIndex = Math.max(profileSamples.ids.length, profileSamples.ma x.length - 1);
1258 profileSamples.ids[currentIndex] = data.lastSeenObjectId;
1259 if (!profileSamples.max[currentIndex]) {
1260 profileSamples.max[currentIndex] = 0;
1261 profileSamples.sizes[currentIndex] = 0;
1262 }
1263 profileSamples.timestamps[currentIndex] = data.timestamp;
1264 if (profileSamples.totalTime < data.timestamp - profileSamples.timestamp s[0])
1265 profileSamples.totalTime *= 2;
1266 this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileTy pe.HeapStatsUpdate, this._profileSamples);
1267 this._profileBeingRecorded.updateStatus(null, true);
1268 },
1269
1270 /**
1271 * @override
1272 * @return {boolean}
1273 */
1274 hasTemporaryView: function()
1275 {
1276 return true;
1277 },
1278
1279 get buttonTooltip()
1280 {
1281 return this._recording ? WebInspector.UIString("Stop recording heap prof ile") : WebInspector.UIString("Start recording heap profile");
1282 },
1283
1284 /**
1285 * @override
1286 * @return {boolean}
1287 */
1288 isInstantProfile: function()
1289 {
1290 return false;
1291 },
1292
1293 /**
1294 * @override
1295 * @return {boolean}
1296 */
1297 buttonClicked: function()
1298 {
1299 return this._toggleRecording();
1300 },
1301
1302 _startRecordingProfile: function()
1303 {
1304 if (this.profileBeingRecorded())
1305 return;
1306 this._addNewProfile();
1307 var recordAllocationStacks = WebInspector.moduleSetting("recordAllocatio nStacks").get();
1308 this.profileBeingRecorded().target().heapProfilerAgent().startTrackingHe apObjects(recordAllocationStacks);
1309 },
1310
1311 _addNewProfile: function()
1312 {
1313 var target = WebInspector.context.flavor(WebInspector.Target);
1314 this.setProfileBeingRecorded(new WebInspector.HeapProfileHeader(target, this, undefined));
1315 this._profileSamples = new WebInspector.TrackingHeapSnapshotProfileType. Samples();
1316 this._profileBeingRecorded._profileSamples = this._profileSamples;
1317 this._recording = true;
1318 this.addProfile(this._profileBeingRecorded);
1319 this._profileBeingRecorded.updateStatus(WebInspector.UIString("Recording \u2026"));
1320 this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileTy pe.TrackingStarted);
1321 },
1322
1323 _stopRecordingProfile: function()
1324 {
1325 this._profileBeingRecorded.updateStatus(WebInspector.UIString("Snapshott ing\u2026"));
1326 /**
1327 * @param {?string} error
1328 * @this {WebInspector.HeapSnapshotProfileType}
1329 */
1330 function didTakeHeapSnapshot(error)
1331 {
1332 var profile = this.profileBeingRecorded();
1333 if (!profile)
1334 return;
1335 profile._finishLoad();
1336 this._profileSamples = null;
1337 this.setProfileBeingRecorded(null);
1338 this.dispatchEventToListeners(WebInspector.ProfileType.Events.Profil eComplete, profile);
1339 }
1340
1341 this._profileBeingRecorded.target().heapProfilerAgent().stopTrackingHeap Objects(true, didTakeHeapSnapshot.bind(this));
1342 this._recording = false;
1343 this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileTy pe.TrackingStopped);
1344 },
1345
1346 _toggleRecording: function()
1347 {
1348 if (this._recording)
1349 this._stopRecordingProfile();
1350 else
1351 this._startRecordingProfile();
1352 return this._recording;
1353 },
1354
1355 /**
1356 * @override
1357 * @return {string}
1358 */
1359 fileExtension: function()
1360 {
1361 return ".heaptimeline";
1362 },
1363
1364 get treeItemTitle()
1365 {
1366 return WebInspector.UIString("ALLOCATION TIMELINES");
1367 },
1368
1369 get description()
1370 {
1371 return WebInspector.UIString("Allocation timelines show memory allocatio ns from your heap over time. Use this profile type to isolate memory leaks.");
1372 },
1373
1374 /**
1375 * @override
1376 */
1377 _resetProfiles: function()
1378 {
1379 var wasRecording = this._recording;
1380 // Clear current profile to avoid stopping backend.
1381 this.setProfileBeingRecorded(null);
1382 WebInspector.HeapSnapshotProfileType.prototype._resetProfiles.call(this) ;
1383 this._profileSamples = null;
1384 if (wasRecording)
1385 this._addNewProfile();
1386 },
1387
1388 /**
1389 * @override
1390 */
1391 profileBeingRecordedRemoved: function()
1392 {
1393 this._stopRecordingProfile();
1394 this._profileSamples = null;
1395 },
1396
1397 __proto__: WebInspector.HeapSnapshotProfileType.prototype
1398 }; 1301 };
1399 1302
1400 /** 1303 /**
1401 * @constructor 1304 * @unrestricted
1402 * @extends {WebInspector.ProfileHeader}
1403 * @param {?WebInspector.Target} target
1404 * @param {!WebInspector.HeapSnapshotProfileType} type
1405 * @param {string=} title
1406 */ 1305 */
1407 WebInspector.HeapProfileHeader = function(target, type, title) 1306 WebInspector.HeapProfileHeader = class extends WebInspector.ProfileHeader {
1408 { 1307 /**
1409 WebInspector.ProfileHeader.call(this, target, type, title || WebInspector.UI String("Snapshot %d", type.nextProfileUid())); 1308 * @param {?WebInspector.Target} target
1309 * @param {!WebInspector.HeapSnapshotProfileType} type
1310 * @param {string=} title
1311 */
1312 constructor(target, type, title) {
1313 super(target, type, title || WebInspector.UIString('Snapshot %d', type.nextP rofileUid()));
1410 this.maxJSObjectId = -1; 1314 this.maxJSObjectId = -1;
1411 /** 1315 /**
1412 * @type {?WebInspector.HeapSnapshotWorkerProxy} 1316 * @type {?WebInspector.HeapSnapshotWorkerProxy}
1413 */ 1317 */
1414 this._workerProxy = null; 1318 this._workerProxy = null;
1415 /** 1319 /**
1416 * @type {?WebInspector.OutputStream} 1320 * @type {?WebInspector.OutputStream}
1417 */ 1321 */
1418 this._receiver = null; 1322 this._receiver = null;
1419 /** 1323 /**
1420 * @type {?WebInspector.HeapSnapshotProxy} 1324 * @type {?WebInspector.HeapSnapshotProxy}
1421 */ 1325 */
1422 this._snapshotProxy = null; 1326 this._snapshotProxy = null;
1423 /** 1327 /**
1424 * @type {!Promise.<!WebInspector.HeapSnapshotProxy>} 1328 * @type {!Promise.<!WebInspector.HeapSnapshotProxy>}
1425 */ 1329 */
1426 this._loadPromise = new Promise(loadResolver.bind(this)); 1330 this._loadPromise = new Promise(loadResolver.bind(this));
1427 this._totalNumberOfChunks = 0; 1331 this._totalNumberOfChunks = 0;
1428 this._bufferedWriter = null; 1332 this._bufferedWriter = null;
1429 1333
1430 /** 1334 /**
1431 * @param {function(!WebInspector.HeapSnapshotProxy)} fulfill 1335 * @param {function(!WebInspector.HeapSnapshotProxy)} fulfill
1432 * @this {WebInspector.HeapProfileHeader} 1336 * @this {WebInspector.HeapProfileHeader}
1433 */ 1337 */
1434 function loadResolver(fulfill) 1338 function loadResolver(fulfill) {
1435 { 1339 this._fulfillLoad = fulfill;
1436 this._fulfillLoad = fulfill; 1340 }
1437 } 1341 }
1342
1343 /**
1344 * @override
1345 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
1346 * @return {!WebInspector.ProfileSidebarTreeElement}
1347 */
1348 createSidebarTreeElement(dataDisplayDelegate) {
1349 return new WebInspector.ProfileSidebarTreeElement(dataDisplayDelegate, this, 'heap-snapshot-sidebar-tree-item');
1350 }
1351
1352 /**
1353 * @override
1354 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
1355 * @return {!WebInspector.HeapSnapshotView}
1356 */
1357 createView(dataDisplayDelegate) {
1358 return new WebInspector.HeapSnapshotView(dataDisplayDelegate, this);
1359 }
1360
1361 _prepareToLoad() {
1362 console.assert(!this._receiver, 'Already loading');
1363 this._setupWorker();
1364 this.updateStatus(WebInspector.UIString('Loading\u2026'), true);
1365 }
1366
1367 _finishLoad() {
1368 if (!this._wasDisposed)
1369 this._receiver.close();
1370 if (this._bufferedWriter) {
1371 this._bufferedWriter.finishWriting(this._didWriteToTempFile.bind(this));
1372 this._bufferedWriter = null;
1373 }
1374 }
1375
1376 _didWriteToTempFile(tempFile) {
1377 if (this._wasDisposed) {
1378 if (tempFile)
1379 tempFile.remove();
1380 return;
1381 }
1382 this._tempFile = tempFile;
1383 if (!tempFile)
1384 this._failedToCreateTempFile = true;
1385 if (this._onTempFileReady) {
1386 this._onTempFileReady();
1387 this._onTempFileReady = null;
1388 }
1389 }
1390
1391 _setupWorker() {
1392 /**
1393 * @this {WebInspector.HeapProfileHeader}
1394 */
1395 function setProfileWait(event) {
1396 this.updateStatus(null, event.data);
1397 }
1398 console.assert(!this._workerProxy, 'HeapSnapshotWorkerProxy already exists') ;
1399 this._workerProxy = new WebInspector.HeapSnapshotWorkerProxy(this._handleWor kerEvent.bind(this));
1400 this._workerProxy.addEventListener('wait', setProfileWait, this);
1401 this._receiver = this._workerProxy.createLoader(this.uid, this._snapshotRece ived.bind(this));
1402 }
1403
1404 /**
1405 * @param {string} eventName
1406 * @param {*} data
1407 */
1408 _handleWorkerEvent(eventName, data) {
1409 if (WebInspector.HeapSnapshotProgressEvent.BrokenSnapshot === eventName) {
1410 var error = /** @type {string} */ (data);
1411 WebInspector.console.error(error);
1412 return;
1413 }
1414
1415 if (WebInspector.HeapSnapshotProgressEvent.Update !== eventName)
1416 return;
1417 var subtitle = /** @type {string} */ (data);
1418 this.updateStatus(subtitle);
1419 }
1420
1421 /**
1422 * @override
1423 */
1424 dispose() {
1425 if (this._workerProxy)
1426 this._workerProxy.dispose();
1427 this.removeTempFile();
1428 this._wasDisposed = true;
1429 }
1430
1431 _didCompleteSnapshotTransfer() {
1432 if (!this._snapshotProxy)
1433 return;
1434 this.updateStatus(Number.bytesToString(this._snapshotProxy.totalSize), false );
1435 }
1436
1437 /**
1438 * @param {string} chunk
1439 */
1440 transferChunk(chunk) {
1441 if (!this._bufferedWriter)
1442 this._bufferedWriter = new WebInspector.DeferredTempFile('heap-profiler', String(this.uid));
1443 this._bufferedWriter.write([chunk]);
1444
1445 ++this._totalNumberOfChunks;
1446 this._receiver.write(chunk);
1447 }
1448
1449 _snapshotReceived(snapshotProxy) {
1450 if (this._wasDisposed)
1451 return;
1452 this._receiver = null;
1453 this._snapshotProxy = snapshotProxy;
1454 this.maxJSObjectId = snapshotProxy.maxJSObjectId();
1455 this._didCompleteSnapshotTransfer();
1456 this._workerProxy.startCheckingForLongRunningCalls();
1457 this.notifySnapshotReceived();
1458 }
1459
1460 notifySnapshotReceived() {
1461 this._fulfillLoad(this._snapshotProxy);
1462 this._profileType._snapshotReceived(this);
1463 if (this.canSaveToFile())
1464 this.dispatchEventToListeners(WebInspector.ProfileHeader.Events.ProfileRec eived);
1465 }
1466
1467 // Hook point for tests.
1468 _wasShown() {
1469 }
1470
1471 /**
1472 * @override
1473 * @return {boolean}
1474 */
1475 canSaveToFile() {
1476 return !this.fromFile() && !!this._snapshotProxy;
1477 }
1478
1479 /**
1480 * @override
1481 */
1482 saveToFile() {
1483 var fileOutputStream = new WebInspector.FileOutputStream();
1484
1485 /**
1486 * @param {boolean} accepted
1487 * @this {WebInspector.HeapProfileHeader}
1488 */
1489 function onOpen(accepted) {
1490 if (!accepted)
1491 return;
1492 if (this._failedToCreateTempFile) {
1493 WebInspector.console.error('Failed to open temp file with heap snapshot' );
1494 fileOutputStream.close();
1495 } else if (this._tempFile) {
1496 var delegate = new WebInspector.SaveSnapshotOutputStreamDelegate(this);
1497 this._tempFile.copyToOutputStream(fileOutputStream, delegate);
1498 } else {
1499 this._onTempFileReady = onOpen.bind(this, accepted);
1500 this._updateSaveProgress(0, 1);
1501 }
1502 }
1503 this._fileName = this._fileName || 'Heap-' + new Date().toISO8601Compact() + this._profileType.fileExtension();
1504 fileOutputStream.open(this._fileName, onOpen.bind(this));
1505 }
1506
1507 _updateSaveProgress(value, total) {
1508 var percentValue = ((total ? (value / total) : 0) * 100).toFixed(0);
1509 this.updateStatus(WebInspector.UIString('Saving\u2026 %d%%', percentValue));
1510 }
1511
1512 /**
1513 * @override
1514 * @param {!File} file
1515 */
1516 loadFromFile(file) {
1517 this.updateStatus(WebInspector.UIString('Loading\u2026'), true);
1518 this._setupWorker();
1519 var delegate = new WebInspector.HeapSnapshotLoadFromFileDelegate(this);
1520 var fileReader = this._createFileReader(file, delegate);
1521 fileReader.start(this._receiver);
1522 }
1523
1524 _createFileReader(file, delegate) {
1525 return new WebInspector.ChunkedFileReader(file, 10000000, delegate);
1526 }
1438 }; 1527 };
1439 1528
1440 WebInspector.HeapProfileHeader.prototype = { 1529 /**
1441 /** 1530 * @implements {WebInspector.OutputStreamDelegate}
1442 * @override 1531 * @unrestricted
1443 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegat e 1532 */
1444 * @return {!WebInspector.ProfileSidebarTreeElement} 1533 WebInspector.HeapSnapshotLoadFromFileDelegate = class {
1445 */ 1534 constructor(snapshotHeader) {
1446 createSidebarTreeElement: function(dataDisplayDelegate) 1535 this._snapshotHeader = snapshotHeader;
1447 { 1536 }
1448 return new WebInspector.ProfileSidebarTreeElement(dataDisplayDelegate, t his, "heap-snapshot-sidebar-tree-item"); 1537
1449 }, 1538 /**
1450 1539 * @override
1451 /** 1540 */
1452 * @override 1541 onTransferStarted() {
1453 * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegat e 1542 }
1454 * @return {!WebInspector.HeapSnapshotView} 1543
1455 */ 1544 /**
1456 createView: function(dataDisplayDelegate) 1545 * @override
1457 { 1546 * @param {!WebInspector.ChunkedReader} reader
1458 return new WebInspector.HeapSnapshotView(dataDisplayDelegate, this); 1547 */
1459 }, 1548 onChunkTransferred(reader) {
1460 1549 }
1461 _prepareToLoad: function() 1550
1462 { 1551 /**
1463 console.assert(!this._receiver, "Already loading"); 1552 * @override
1464 this._setupWorker(); 1553 */
1465 this.updateStatus(WebInspector.UIString("Loading\u2026"), true); 1554 onTransferFinished() {
1466 }, 1555 }
1467 1556
1468 _finishLoad: function() 1557 /**
1469 { 1558 * @override
1470 if (!this._wasDisposed) 1559 * @param {!WebInspector.ChunkedReader} reader
1471 this._receiver.close(); 1560 * @param {!Event} e
1472 if (this._bufferedWriter) { 1561 */
1473 this._bufferedWriter.finishWriting(this._didWriteToTempFile.bind(thi s)); 1562 onError(reader, e) {
1474 this._bufferedWriter = null; 1563 var subtitle;
1475 } 1564 switch (e.target.error.code) {
1476 }, 1565 case e.target.error.NOT_FOUND_ERR:
1477 1566 subtitle = WebInspector.UIString('\'%s\' not found.', reader.fileName()) ;
1478 _didWriteToTempFile: function(tempFile) 1567 break;
1479 { 1568 case e.target.error.NOT_READABLE_ERR:
1480 if (this._wasDisposed) { 1569 subtitle = WebInspector.UIString('\'%s\' is not readable', reader.fileNa me());
1481 if (tempFile) 1570 break;
1482 tempFile.remove(); 1571 case e.target.error.ABORT_ERR:
1483 return; 1572 return;
1484 } 1573 default:
1485 this._tempFile = tempFile; 1574 subtitle = WebInspector.UIString('\'%s\' error %d', reader.fileName(), e .target.error.code);
1486 if (!tempFile) 1575 }
1487 this._failedToCreateTempFile = true; 1576 this._snapshotHeader.updateStatus(subtitle);
1488 if (this._onTempFileReady) { 1577 }
1489 this._onTempFileReady();
1490 this._onTempFileReady = null;
1491 }
1492 },
1493
1494 _setupWorker: function()
1495 {
1496 /**
1497 * @this {WebInspector.HeapProfileHeader}
1498 */
1499 function setProfileWait(event)
1500 {
1501 this.updateStatus(null, event.data);
1502 }
1503 console.assert(!this._workerProxy, "HeapSnapshotWorkerProxy already exis ts");
1504 this._workerProxy = new WebInspector.HeapSnapshotWorkerProxy(this._handl eWorkerEvent.bind(this));
1505 this._workerProxy.addEventListener("wait", setProfileWait, this);
1506 this._receiver = this._workerProxy.createLoader(this.uid, this._snapshot Received.bind(this));
1507 },
1508
1509 /**
1510 * @param {string} eventName
1511 * @param {*} data
1512 */
1513 _handleWorkerEvent: function(eventName, data)
1514 {
1515 if (WebInspector.HeapSnapshotProgressEvent.BrokenSnapshot === eventName) {
1516 var error = /** @type {string} */ (data);
1517 WebInspector.console.error(error);
1518 return;
1519 }
1520
1521 if (WebInspector.HeapSnapshotProgressEvent.Update !== eventName)
1522 return;
1523 var subtitle = /** @type {string} */ (data);
1524 this.updateStatus(subtitle);
1525 },
1526
1527 /**
1528 * @override
1529 */
1530 dispose: function()
1531 {
1532 if (this._workerProxy)
1533 this._workerProxy.dispose();
1534 this.removeTempFile();
1535 this._wasDisposed = true;
1536 },
1537
1538 _didCompleteSnapshotTransfer: function()
1539 {
1540 if (!this._snapshotProxy)
1541 return;
1542 this.updateStatus(Number.bytesToString(this._snapshotProxy.totalSize), f alse);
1543 },
1544
1545 /**
1546 * @param {string} chunk
1547 */
1548 transferChunk: function(chunk)
1549 {
1550 if (!this._bufferedWriter)
1551 this._bufferedWriter = new WebInspector.DeferredTempFile("heap-profi ler", String(this.uid));
1552 this._bufferedWriter.write([chunk]);
1553
1554 ++this._totalNumberOfChunks;
1555 this._receiver.write(chunk);
1556 },
1557
1558 _snapshotReceived: function(snapshotProxy)
1559 {
1560 if (this._wasDisposed)
1561 return;
1562 this._receiver = null;
1563 this._snapshotProxy = snapshotProxy;
1564 this.maxJSObjectId = snapshotProxy.maxJSObjectId();
1565 this._didCompleteSnapshotTransfer();
1566 this._workerProxy.startCheckingForLongRunningCalls();
1567 this.notifySnapshotReceived();
1568 },
1569
1570 notifySnapshotReceived: function()
1571 {
1572 this._fulfillLoad(this._snapshotProxy);
1573 this._profileType._snapshotReceived(this);
1574 if (this.canSaveToFile())
1575 this.dispatchEventToListeners(WebInspector.ProfileHeader.Events.Prof ileReceived);
1576 },
1577
1578 // Hook point for tests.
1579 _wasShown: function()
1580 {
1581 },
1582
1583 /**
1584 * @override
1585 * @return {boolean}
1586 */
1587 canSaveToFile: function()
1588 {
1589 return !this.fromFile() && !!this._snapshotProxy;
1590 },
1591
1592 /**
1593 * @override
1594 */
1595 saveToFile: function()
1596 {
1597 var fileOutputStream = new WebInspector.FileOutputStream();
1598
1599 /**
1600 * @param {boolean} accepted
1601 * @this {WebInspector.HeapProfileHeader}
1602 */
1603 function onOpen(accepted)
1604 {
1605 if (!accepted)
1606 return;
1607 if (this._failedToCreateTempFile) {
1608 WebInspector.console.error("Failed to open temp file with heap s napshot");
1609 fileOutputStream.close();
1610 } else if (this._tempFile) {
1611 var delegate = new WebInspector.SaveSnapshotOutputStreamDelegate (this);
1612 this._tempFile.copyToOutputStream(fileOutputStream, delegate);
1613 } else {
1614 this._onTempFileReady = onOpen.bind(this, accepted);
1615 this._updateSaveProgress(0, 1);
1616 }
1617 }
1618 this._fileName = this._fileName || "Heap-" + new Date().toISO8601Compact () + this._profileType.fileExtension();
1619 fileOutputStream.open(this._fileName, onOpen.bind(this));
1620 },
1621
1622 _updateSaveProgress: function(value, total)
1623 {
1624 var percentValue = ((total ? (value / total) : 0) * 100).toFixed(0);
1625 this.updateStatus(WebInspector.UIString("Saving\u2026 %d%%", percentValu e));
1626 },
1627
1628 /**
1629 * @override
1630 * @param {!File} file
1631 */
1632 loadFromFile: function(file)
1633 {
1634 this.updateStatus(WebInspector.UIString("Loading\u2026"), true);
1635 this._setupWorker();
1636 var delegate = new WebInspector.HeapSnapshotLoadFromFileDelegate(this);
1637 var fileReader = this._createFileReader(file, delegate);
1638 fileReader.start(this._receiver);
1639 },
1640
1641 _createFileReader: function(file, delegate)
1642 {
1643 return new WebInspector.ChunkedFileReader(file, 10000000, delegate);
1644 },
1645
1646 __proto__: WebInspector.ProfileHeader.prototype
1647 }; 1578 };
1648 1579
1649 /** 1580 /**
1650 * @constructor
1651 * @implements {WebInspector.OutputStreamDelegate} 1581 * @implements {WebInspector.OutputStreamDelegate}
1582 * @unrestricted
1652 */ 1583 */
1653 WebInspector.HeapSnapshotLoadFromFileDelegate = function(snapshotHeader) 1584 WebInspector.SaveSnapshotOutputStreamDelegate = class {
1654 { 1585 /**
1655 this._snapshotHeader = snapshotHeader; 1586 * @param {!WebInspector.HeapProfileHeader} profileHeader
1587 */
1588 constructor(profileHeader) {
1589 this._profileHeader = profileHeader;
1590 }
1591
1592 /**
1593 * @override
1594 */
1595 onTransferStarted() {
1596 this._profileHeader._updateSaveProgress(0, 1);
1597 }
1598
1599 /**
1600 * @override
1601 */
1602 onTransferFinished() {
1603 this._profileHeader._didCompleteSnapshotTransfer();
1604 }
1605
1606 /**
1607 * @override
1608 * @param {!WebInspector.ChunkedReader} reader
1609 */
1610 onChunkTransferred(reader) {
1611 this._profileHeader._updateSaveProgress(reader.loadedSize(), reader.fileSize ());
1612 }
1613
1614 /**
1615 * @override
1616 * @param {!WebInspector.ChunkedReader} reader
1617 * @param {!Event} event
1618 */
1619 onError(reader, event) {
1620 WebInspector.console.error(
1621 'Failed to read heap snapshot from temp file: ' + /** @type {!ErrorEvent } */ (event).message);
1622 this.onTransferFinished();
1623 }
1656 }; 1624 };
1657 1625
1658 WebInspector.HeapSnapshotLoadFromFileDelegate.prototype = {
1659 /**
1660 * @override
1661 */
1662 onTransferStarted: function()
1663 {
1664 },
1665
1666 /**
1667 * @override
1668 * @param {!WebInspector.ChunkedReader} reader
1669 */
1670 onChunkTransferred: function(reader)
1671 {
1672 },
1673
1674 /**
1675 * @override
1676 */
1677 onTransferFinished: function()
1678 {
1679 },
1680
1681 /**
1682 * @override
1683 * @param {!WebInspector.ChunkedReader} reader
1684 * @param {!Event} e
1685 */
1686 onError: function(reader, e)
1687 {
1688 var subtitle;
1689 switch (e.target.error.code) {
1690 case e.target.error.NOT_FOUND_ERR:
1691 subtitle = WebInspector.UIString("'%s' not found.", reader.fileName( ));
1692 break;
1693 case e.target.error.NOT_READABLE_ERR:
1694 subtitle = WebInspector.UIString("'%s' is not readable", reader.file Name());
1695 break;
1696 case e.target.error.ABORT_ERR:
1697 return;
1698 default:
1699 subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code);
1700 }
1701 this._snapshotHeader.updateStatus(subtitle);
1702 }
1703 };
1704
1705 /** 1626 /**
1706 * @constructor 1627 * @unrestricted
1707 * @implements {WebInspector.OutputStreamDelegate}
1708 * @param {!WebInspector.HeapProfileHeader} profileHeader
1709 */ 1628 */
1710 WebInspector.SaveSnapshotOutputStreamDelegate = function(profileHeader) 1629 WebInspector.HeapTrackingOverviewGrid = class extends WebInspector.VBox {
1711 { 1630 /**
1712 this._profileHeader = profileHeader; 1631 * @param {!WebInspector.HeapProfileHeader} heapProfileHeader
1713 }; 1632 */
1714 1633 constructor(heapProfileHeader) {
1715 WebInspector.SaveSnapshotOutputStreamDelegate.prototype = { 1634 super();
1716 /** 1635 this.element.id = 'heap-recording-view';
1717 * @override 1636 this.element.classList.add('heap-tracking-overview');
1718 */ 1637
1719 onTransferStarted: function() 1638 this._overviewContainer = this.element.createChild('div', 'heap-overview-con tainer');
1720 { 1639 this._overviewGrid = new WebInspector.OverviewGrid('heap-recording');
1721 this._profileHeader._updateSaveProgress(0, 1); 1640 this._overviewGrid.element.classList.add('fill');
1722 }, 1641
1723 1642 this._overviewCanvas = this._overviewContainer.createChild('canvas', 'heap-r ecording-overview-canvas');
1724 /**
1725 * @override
1726 */
1727 onTransferFinished: function()
1728 {
1729 this._profileHeader._didCompleteSnapshotTransfer();
1730 },
1731
1732 /**
1733 * @override
1734 * @param {!WebInspector.ChunkedReader} reader
1735 */
1736 onChunkTransferred: function(reader)
1737 {
1738 this._profileHeader._updateSaveProgress(reader.loadedSize(), reader.file Size());
1739 },
1740
1741 /**
1742 * @override
1743 * @param {!WebInspector.ChunkedReader} reader
1744 * @param {!Event} event
1745 */
1746 onError: function(reader, event)
1747 {
1748 WebInspector.console.error("Failed to read heap snapshot from temp file: " + /** @type {!ErrorEvent} */ (event).message);
1749 this.onTransferFinished();
1750 }
1751 };
1752
1753 /**
1754 * @constructor
1755 * @extends {WebInspector.VBox}
1756 * @param {!WebInspector.HeapProfileHeader} heapProfileHeader
1757 */
1758 WebInspector.HeapTrackingOverviewGrid = function(heapProfileHeader)
1759 {
1760 WebInspector.VBox.call(this);
1761 this.element.id = "heap-recording-view";
1762 this.element.classList.add("heap-tracking-overview");
1763
1764 this._overviewContainer = this.element.createChild("div", "heap-overview-con tainer");
1765 this._overviewGrid = new WebInspector.OverviewGrid("heap-recording");
1766 this._overviewGrid.element.classList.add("fill");
1767
1768 this._overviewCanvas = this._overviewContainer.createChild("canvas", "heap-r ecording-overview-canvas");
1769 this._overviewContainer.appendChild(this._overviewGrid.element); 1643 this._overviewContainer.appendChild(this._overviewGrid.element);
1770 this._overviewCalculator = new WebInspector.HeapTrackingOverviewGrid.Overvie wCalculator(); 1644 this._overviewCalculator = new WebInspector.HeapTrackingOverviewGrid.Overvie wCalculator();
1771 this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowC hanged, this._onWindowChanged, this); 1645 this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowC hanged, this._onWindowChanged, this);
1772 1646
1773 this._profileSamples = heapProfileHeader.fromFile() ? new WebInspector.Track ingHeapSnapshotProfileType.Samples() : heapProfileHeader._profileSamples; 1647 this._profileSamples = heapProfileHeader.fromFile() ? new WebInspector.Track ingHeapSnapshotProfileType.Samples() :
1648 heapProfileHeader._pro fileSamples;
1774 this._profileType = heapProfileHeader.profileType(); 1649 this._profileType = heapProfileHeader.profileType();
1775 if (!heapProfileHeader.fromFile() && heapProfileHeader.profileType().profile BeingRecorded() === heapProfileHeader) { 1650 if (!heapProfileHeader.fromFile() && heapProfileHeader.profileType().profile BeingRecorded() === heapProfileHeader) {
1776 this._profileType.addEventListener(WebInspector.TrackingHeapSnapshotProf ileType.HeapStatsUpdate, this._onHeapStatsUpdate, this); 1651 this._profileType.addEventListener(
1777 this._profileType.addEventListener(WebInspector.TrackingHeapSnapshotProf ileType.TrackingStopped, this._onStopTracking, this); 1652 WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._on HeapStatsUpdate, this);
1653 this._profileType.addEventListener(
1654 WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped, this._on StopTracking, this);
1778 } 1655 }
1779 this._windowLeft = 0.0; 1656 this._windowLeft = 0.0;
1780 this._windowRight = 1.0; 1657 this._windowRight = 1.0;
1781 this._overviewGrid.setWindow(this._windowLeft, this._windowRight); 1658 this._overviewGrid.setWindow(this._windowLeft, this._windowRight);
1782 this._yScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale(); 1659 this._yScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale();
1783 this._xScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale(); 1660 this._xScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale();
1661 }
1662
1663 dispose() {
1664 this._onStopTracking();
1665 }
1666
1667 _onStopTracking() {
1668 this._profileType.removeEventListener(
1669 WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHe apStatsUpdate, this);
1670 this._profileType.removeEventListener(
1671 WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped, this._onSt opTracking, this);
1672 }
1673
1674 _onHeapStatsUpdate(event) {
1675 this._profileSamples = event.data;
1676 this._scheduleUpdate();
1677 }
1678
1679 /**
1680 * @param {?WebInspector.HeapSnapshotCommon.Samples} samples
1681 */
1682 _setSamples(samples) {
1683 if (!samples)
1684 return;
1685 console.assert(!this._profileSamples.timestamps.length, 'Should only call th is method when loading from file.');
1686 console.assert(samples.timestamps.length);
1687 this._profileSamples = new WebInspector.TrackingHeapSnapshotProfileType.Samp les();
1688 this._profileSamples.sizes = samples.sizes;
1689 this._profileSamples.ids = samples.lastAssignedIds;
1690 this._profileSamples.timestamps = samples.timestamps;
1691 this._profileSamples.max = samples.sizes;
1692 this._profileSamples.totalTime = /** @type{number} */ (samples.timestamps.pe ekLast());
1693 this.update();
1694 }
1695
1696 /**
1697 * @param {number} width
1698 * @param {number} height
1699 */
1700 _drawOverviewCanvas(width, height) {
1701 if (!this._profileSamples)
1702 return;
1703 var profileSamples = this._profileSamples;
1704 var sizes = profileSamples.sizes;
1705 var topSizes = profileSamples.max;
1706 var timestamps = profileSamples.timestamps;
1707 var startTime = timestamps[0];
1708 var endTime = timestamps[timestamps.length - 1];
1709
1710 var scaleFactor = this._xScale.nextScale(width / profileSamples.totalTime);
1711 var maxSize = 0;
1712 /**
1713 * @param {!Array.<number>} sizes
1714 * @param {function(number, number):void} callback
1715 */
1716 function aggregateAndCall(sizes, callback) {
1717 var size = 0;
1718 var currentX = 0;
1719 for (var i = 1; i < timestamps.length; ++i) {
1720 var x = Math.floor((timestamps[i] - startTime) * scaleFactor);
1721 if (x !== currentX) {
1722 if (size)
1723 callback(currentX, size);
1724 size = 0;
1725 currentX = x;
1726 }
1727 size += sizes[i];
1728 }
1729 callback(currentX, size);
1730 }
1731
1732 /**
1733 * @param {number} x
1734 * @param {number} size
1735 */
1736 function maxSizeCallback(x, size) {
1737 maxSize = Math.max(maxSize, size);
1738 }
1739
1740 aggregateAndCall(sizes, maxSizeCallback);
1741
1742 var yScaleFactor = this._yScale.nextScale(maxSize ? height / (maxSize * 1.1) : 0.0);
1743
1744 this._overviewCanvas.width = width * window.devicePixelRatio;
1745 this._overviewCanvas.height = height * window.devicePixelRatio;
1746 this._overviewCanvas.style.width = width + 'px';
1747 this._overviewCanvas.style.height = height + 'px';
1748
1749 var context = this._overviewCanvas.getContext('2d');
1750 context.scale(window.devicePixelRatio, window.devicePixelRatio);
1751
1752 context.beginPath();
1753 context.lineWidth = 2;
1754 context.strokeStyle = 'rgba(192, 192, 192, 0.6)';
1755 var currentX = (endTime - startTime) * scaleFactor;
1756 context.moveTo(currentX, height - 1);
1757 context.lineTo(currentX, 0);
1758 context.stroke();
1759 context.closePath();
1760
1761 var gridY;
1762 var gridValue;
1763 var gridLabelHeight = 14;
1764 if (yScaleFactor) {
1765 const maxGridValue = (height - gridLabelHeight) / yScaleFactor;
1766 // The round value calculation is a bit tricky, because
1767 // it has a form k*10^n*1024^m, where k=[1,5], n=[0..3], m is an integer,
1768 // e.g. a round value 10KB is 10240 bytes.
1769 gridValue = Math.pow(1024, Math.floor(Math.log(maxGridValue) / Math.log(10 24)));
1770 gridValue *= Math.pow(10, Math.floor(Math.log(maxGridValue / gridValue) / Math.LN10));
1771 if (gridValue * 5 <= maxGridValue)
1772 gridValue *= 5;
1773 gridY = Math.round(height - gridValue * yScaleFactor - 0.5) + 0.5;
1774 context.beginPath();
1775 context.lineWidth = 1;
1776 context.strokeStyle = 'rgba(0, 0, 0, 0.2)';
1777 context.moveTo(0, gridY);
1778 context.lineTo(width, gridY);
1779 context.stroke();
1780 context.closePath();
1781 }
1782
1783 /**
1784 * @param {number} x
1785 * @param {number} size
1786 */
1787 function drawBarCallback(x, size) {
1788 context.moveTo(x, height - 1);
1789 context.lineTo(x, Math.round(height - size * yScaleFactor - 1));
1790 }
1791
1792 context.beginPath();
1793 context.lineWidth = 2;
1794 context.strokeStyle = 'rgba(192, 192, 192, 0.6)';
1795 aggregateAndCall(topSizes, drawBarCallback);
1796 context.stroke();
1797 context.closePath();
1798
1799 context.beginPath();
1800 context.lineWidth = 2;
1801 context.strokeStyle = 'rgba(0, 0, 192, 0.8)';
1802 aggregateAndCall(sizes, drawBarCallback);
1803 context.stroke();
1804 context.closePath();
1805
1806 if (gridValue) {
1807 var label = Number.bytesToString(gridValue);
1808 var labelPadding = 4;
1809 var labelX = 0;
1810 var labelY = gridY - 0.5;
1811 var labelWidth = 2 * labelPadding + context.measureText(label).width;
1812 context.beginPath();
1813 context.textBaseline = 'bottom';
1814 context.font = '10px ' + window.getComputedStyle(this.element, null).getPr opertyValue('font-family');
1815 context.fillStyle = 'rgba(255, 255, 255, 0.75)';
1816 context.fillRect(labelX, labelY - gridLabelHeight, labelWidth, gridLabelHe ight);
1817 context.fillStyle = 'rgb(64, 64, 64)';
1818 context.fillText(label, labelX + labelPadding, labelY);
1819 context.fill();
1820 context.closePath();
1821 }
1822 }
1823
1824 /**
1825 * @override
1826 */
1827 onResize() {
1828 this._updateOverviewCanvas = true;
1829 this._scheduleUpdate();
1830 }
1831
1832 _onWindowChanged() {
1833 if (!this._updateGridTimerId)
1834 this._updateGridTimerId = setTimeout(this._updateGrid.bind(this), 10);
1835 }
1836
1837 _scheduleUpdate() {
1838 if (this._updateTimerId)
1839 return;
1840 this._updateTimerId = setTimeout(this.update.bind(this), 10);
1841 }
1842
1843 _updateBoundaries() {
1844 this._windowLeft = this._overviewGrid.windowLeft();
1845 this._windowRight = this._overviewGrid.windowRight();
1846 this._windowWidth = this._windowRight - this._windowLeft;
1847 }
1848
1849 update() {
1850 this._updateTimerId = null;
1851 if (!this.isShowing())
1852 return;
1853 this._updateBoundaries();
1854 this._overviewCalculator._updateBoundaries(this);
1855 this._overviewGrid.updateDividers(this._overviewCalculator);
1856 this._drawOverviewCanvas(this._overviewContainer.clientWidth, this._overview Container.clientHeight - 20);
1857 }
1858
1859 _updateGrid() {
1860 this._updateGridTimerId = 0;
1861 this._updateBoundaries();
1862 var ids = this._profileSamples.ids;
1863 var timestamps = this._profileSamples.timestamps;
1864 var sizes = this._profileSamples.sizes;
1865 var startTime = timestamps[0];
1866 var totalTime = this._profileSamples.totalTime;
1867 var timeLeft = startTime + totalTime * this._windowLeft;
1868 var timeRight = startTime + totalTime * this._windowRight;
1869 var minId = 0;
1870 var maxId = ids[ids.length - 1] + 1;
1871 var size = 0;
1872 for (var i = 0; i < timestamps.length; ++i) {
1873 if (!timestamps[i])
1874 continue;
1875 if (timestamps[i] > timeRight)
1876 break;
1877 maxId = ids[i];
1878 if (timestamps[i] < timeLeft) {
1879 minId = ids[i];
1880 continue;
1881 }
1882 size += sizes[i];
1883 }
1884
1885 this.dispatchEventToListeners(
1886 WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged, {minId: minId, ma xId: maxId, size: size});
1887 }
1784 }; 1888 };
1785 1889
1786 WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged = "IdsRangeChanged"; 1890 WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged = 'IdsRangeChanged';
1787
1788 WebInspector.HeapTrackingOverviewGrid.prototype = {
1789 dispose: function()
1790 {
1791 this._onStopTracking();
1792 },
1793
1794 _onStopTracking: function()
1795 {
1796 this._profileType.removeEventListener(WebInspector.TrackingHeapSnapshotP rofileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
1797 this._profileType.removeEventListener(WebInspector.TrackingHeapSnapshotP rofileType.TrackingStopped, this._onStopTracking, this);
1798 },
1799
1800 _onHeapStatsUpdate: function(event)
1801 {
1802 this._profileSamples = event.data;
1803 this._scheduleUpdate();
1804 },
1805
1806 /**
1807 * @param {?WebInspector.HeapSnapshotCommon.Samples} samples
1808 */
1809 _setSamples: function(samples)
1810 {
1811 if (!samples)
1812 return;
1813 console.assert(!this._profileSamples.timestamps.length, "Should only cal l this method when loading from file.");
1814 console.assert(samples.timestamps.length);
1815 this._profileSamples = new WebInspector.TrackingHeapSnapshotProfileType. Samples();
1816 this._profileSamples.sizes = samples.sizes;
1817 this._profileSamples.ids = samples.lastAssignedIds;
1818 this._profileSamples.timestamps = samples.timestamps;
1819 this._profileSamples.max = samples.sizes;
1820 this._profileSamples.totalTime = /** @type{number} */(samples.timestamps .peekLast());
1821 this.update();
1822 },
1823
1824 /**
1825 * @param {number} width
1826 * @param {number} height
1827 */
1828 _drawOverviewCanvas: function(width, height)
1829 {
1830 if (!this._profileSamples)
1831 return;
1832 var profileSamples = this._profileSamples;
1833 var sizes = profileSamples.sizes;
1834 var topSizes = profileSamples.max;
1835 var timestamps = profileSamples.timestamps;
1836 var startTime = timestamps[0];
1837 var endTime = timestamps[timestamps.length - 1];
1838
1839 var scaleFactor = this._xScale.nextScale(width / profileSamples.totalTim e);
1840 var maxSize = 0;
1841 /**
1842 * @param {!Array.<number>} sizes
1843 * @param {function(number, number):void} callback
1844 */
1845 function aggregateAndCall(sizes, callback)
1846 {
1847 var size = 0;
1848 var currentX = 0;
1849 for (var i = 1; i < timestamps.length; ++i) {
1850 var x = Math.floor((timestamps[i] - startTime) * scaleFactor);
1851 if (x !== currentX) {
1852 if (size)
1853 callback(currentX, size);
1854 size = 0;
1855 currentX = x;
1856 }
1857 size += sizes[i];
1858 }
1859 callback(currentX, size);
1860 }
1861
1862 /**
1863 * @param {number} x
1864 * @param {number} size
1865 */
1866 function maxSizeCallback(x, size)
1867 {
1868 maxSize = Math.max(maxSize, size);
1869 }
1870
1871 aggregateAndCall(sizes, maxSizeCallback);
1872
1873 var yScaleFactor = this._yScale.nextScale(maxSize ? height / (maxSize * 1.1) : 0.0);
1874
1875 this._overviewCanvas.width = width * window.devicePixelRatio;
1876 this._overviewCanvas.height = height * window.devicePixelRatio;
1877 this._overviewCanvas.style.width = width + "px";
1878 this._overviewCanvas.style.height = height + "px";
1879
1880 var context = this._overviewCanvas.getContext("2d");
1881 context.scale(window.devicePixelRatio, window.devicePixelRatio);
1882
1883 context.beginPath();
1884 context.lineWidth = 2;
1885 context.strokeStyle = "rgba(192, 192, 192, 0.6)";
1886 var currentX = (endTime - startTime) * scaleFactor;
1887 context.moveTo(currentX, height - 1);
1888 context.lineTo(currentX, 0);
1889 context.stroke();
1890 context.closePath();
1891
1892 var gridY;
1893 var gridValue;
1894 var gridLabelHeight = 14;
1895 if (yScaleFactor) {
1896 const maxGridValue = (height - gridLabelHeight) / yScaleFactor;
1897 // The round value calculation is a bit tricky, because
1898 // it has a form k*10^n*1024^m, where k=[1,5], n=[0..3], m is an int eger,
1899 // e.g. a round value 10KB is 10240 bytes.
1900 gridValue = Math.pow(1024, Math.floor(Math.log(maxGridValue) / Math. log(1024)));
1901 gridValue *= Math.pow(10, Math.floor(Math.log(maxGridValue / gridVal ue) / Math.LN10));
1902 if (gridValue * 5 <= maxGridValue)
1903 gridValue *= 5;
1904 gridY = Math.round(height - gridValue * yScaleFactor - 0.5) + 0.5;
1905 context.beginPath();
1906 context.lineWidth = 1;
1907 context.strokeStyle = "rgba(0, 0, 0, 0.2)";
1908 context.moveTo(0, gridY);
1909 context.lineTo(width, gridY);
1910 context.stroke();
1911 context.closePath();
1912 }
1913
1914 /**
1915 * @param {number} x
1916 * @param {number} size
1917 */
1918 function drawBarCallback(x, size)
1919 {
1920 context.moveTo(x, height - 1);
1921 context.lineTo(x, Math.round(height - size * yScaleFactor - 1));
1922 }
1923
1924 context.beginPath();
1925 context.lineWidth = 2;
1926 context.strokeStyle = "rgba(192, 192, 192, 0.6)";
1927 aggregateAndCall(topSizes, drawBarCallback);
1928 context.stroke();
1929 context.closePath();
1930
1931 context.beginPath();
1932 context.lineWidth = 2;
1933 context.strokeStyle = "rgba(0, 0, 192, 0.8)";
1934 aggregateAndCall(sizes, drawBarCallback);
1935 context.stroke();
1936 context.closePath();
1937
1938 if (gridValue) {
1939 var label = Number.bytesToString(gridValue);
1940 var labelPadding = 4;
1941 var labelX = 0;
1942 var labelY = gridY - 0.5;
1943 var labelWidth = 2 * labelPadding + context.measureText(label).width ;
1944 context.beginPath();
1945 context.textBaseline = "bottom";
1946 context.font = "10px " + window.getComputedStyle(this.element, null) .getPropertyValue("font-family");
1947 context.fillStyle = "rgba(255, 255, 255, 0.75)";
1948 context.fillRect(labelX, labelY - gridLabelHeight, labelWidth, gridL abelHeight);
1949 context.fillStyle = "rgb(64, 64, 64)";
1950 context.fillText(label, labelX + labelPadding, labelY);
1951 context.fill();
1952 context.closePath();
1953 }
1954 },
1955
1956 onResize: function()
1957 {
1958 this._updateOverviewCanvas = true;
1959 this._scheduleUpdate();
1960 },
1961
1962 _onWindowChanged: function()
1963 {
1964 if (!this._updateGridTimerId)
1965 this._updateGridTimerId = setTimeout(this._updateGrid.bind(this), 10 );
1966 },
1967
1968 _scheduleUpdate: function()
1969 {
1970 if (this._updateTimerId)
1971 return;
1972 this._updateTimerId = setTimeout(this.update.bind(this), 10);
1973 },
1974
1975 _updateBoundaries: function()
1976 {
1977 this._windowLeft = this._overviewGrid.windowLeft();
1978 this._windowRight = this._overviewGrid.windowRight();
1979 this._windowWidth = this._windowRight - this._windowLeft;
1980 },
1981
1982 update: function()
1983 {
1984 this._updateTimerId = null;
1985 if (!this.isShowing())
1986 return;
1987 this._updateBoundaries();
1988 this._overviewCalculator._updateBoundaries(this);
1989 this._overviewGrid.updateDividers(this._overviewCalculator);
1990 this._drawOverviewCanvas(this._overviewContainer.clientWidth, this._over viewContainer.clientHeight - 20);
1991 },
1992
1993 _updateGrid: function()
1994 {
1995 this._updateGridTimerId = 0;
1996 this._updateBoundaries();
1997 var ids = this._profileSamples.ids;
1998 var timestamps = this._profileSamples.timestamps;
1999 var sizes = this._profileSamples.sizes;
2000 var startTime = timestamps[0];
2001 var totalTime = this._profileSamples.totalTime;
2002 var timeLeft = startTime + totalTime * this._windowLeft;
2003 var timeRight = startTime + totalTime * this._windowRight;
2004 var minId = 0;
2005 var maxId = ids[ids.length - 1] + 1;
2006 var size = 0;
2007 for (var i = 0; i < timestamps.length; ++i) {
2008 if (!timestamps[i])
2009 continue;
2010 if (timestamps[i] > timeRight)
2011 break;
2012 maxId = ids[i];
2013 if (timestamps[i] < timeLeft) {
2014 minId = ids[i];
2015 continue;
2016 }
2017 size += sizes[i];
2018 }
2019
2020 this.dispatchEventToListeners(WebInspector.HeapTrackingOverviewGrid.IdsR angeChanged, {minId: minId, maxId: maxId, size: size});
2021 },
2022
2023 __proto__: WebInspector.VBox.prototype
2024 };
2025
2026 1891
2027 /** 1892 /**
2028 * @constructor 1893 * @unrestricted
2029 */ 1894 */
2030 WebInspector.HeapTrackingOverviewGrid.SmoothScale = function() 1895 WebInspector.HeapTrackingOverviewGrid.SmoothScale = class {
2031 { 1896 constructor() {
2032 this._lastUpdate = 0; 1897 this._lastUpdate = 0;
2033 this._currentScale = 0.0; 1898 this._currentScale = 0.0;
1899 }
1900
1901 /**
1902 * @param {number} target
1903 * @return {number}
1904 */
1905 nextScale(target) {
1906 target = target || this._currentScale;
1907 if (this._currentScale) {
1908 var now = Date.now();
1909 var timeDeltaMs = now - this._lastUpdate;
1910 this._lastUpdate = now;
1911 var maxChangePerSec = 20;
1912 var maxChangePerDelta = Math.pow(maxChangePerSec, timeDeltaMs / 1000);
1913 var scaleChange = target / this._currentScale;
1914 this._currentScale *= Number.constrain(scaleChange, 1 / maxChangePerDelta, maxChangePerDelta);
1915 } else {
1916 this._currentScale = target;
1917 }
1918 return this._currentScale;
1919 }
2034 }; 1920 };
2035 1921
2036 WebInspector.HeapTrackingOverviewGrid.SmoothScale.prototype = { 1922 /**
2037 /** 1923 * @implements {WebInspector.TimelineGrid.Calculator}
2038 * @param {number} target 1924 * @unrestricted
2039 * @return {number} 1925 */
2040 */ 1926 WebInspector.HeapTrackingOverviewGrid.OverviewCalculator = class {
2041 nextScale: function(target) { 1927 /**
2042 target = target || this._currentScale; 1928 * @override
2043 if (this._currentScale) { 1929 * @return {number}
2044 var now = Date.now(); 1930 */
2045 var timeDeltaMs = now - this._lastUpdate; 1931 paddingLeft() {
2046 this._lastUpdate = now; 1932 return 0;
2047 var maxChangePerSec = 20; 1933 }
2048 var maxChangePerDelta = Math.pow(maxChangePerSec, timeDeltaMs / 1000 ); 1934
2049 var scaleChange = target / this._currentScale; 1935 /**
2050 this._currentScale *= Number.constrain(scaleChange, 1 / maxChangePer Delta, maxChangePerDelta); 1936 * @param {!WebInspector.HeapTrackingOverviewGrid} chart
2051 } else { 1937 */
2052 this._currentScale = target; 1938 _updateBoundaries(chart) {
2053 } 1939 this._minimumBoundaries = 0;
2054 return this._currentScale; 1940 this._maximumBoundaries = chart._profileSamples.totalTime;
2055 } 1941 this._xScaleFactor = chart._overviewContainer.clientWidth / this._maximumBou ndaries;
1942 }
1943
1944 /**
1945 * @override
1946 * @param {number} time
1947 * @return {number}
1948 */
1949 computePosition(time) {
1950 return (time - this._minimumBoundaries) * this._xScaleFactor;
1951 }
1952
1953 /**
1954 * @override
1955 * @param {number} value
1956 * @param {number=} precision
1957 * @return {string}
1958 */
1959 formatValue(value, precision) {
1960 return Number.secondsToString(value / 1000, !!precision);
1961 }
1962
1963 /**
1964 * @override
1965 * @return {number}
1966 */
1967 maximumBoundary() {
1968 return this._maximumBoundaries;
1969 }
1970
1971 /**
1972 * @override
1973 * @return {number}
1974 */
1975 minimumBoundary() {
1976 return this._minimumBoundaries;
1977 }
1978
1979 /**
1980 * @override
1981 * @return {number}
1982 */
1983 zeroTime() {
1984 return this._minimumBoundaries;
1985 }
1986
1987 /**
1988 * @override
1989 * @return {number}
1990 */
1991 boundarySpan() {
1992 return this._maximumBoundaries - this._minimumBoundaries;
1993 }
2056 }; 1994 };
2057 1995
2058
2059 /** 1996 /**
2060 * @constructor 1997 * @unrestricted
2061 * @implements {WebInspector.TimelineGrid.Calculator}
2062 */ 1998 */
2063 WebInspector.HeapTrackingOverviewGrid.OverviewCalculator = function() 1999 WebInspector.HeapSnapshotStatisticsView = class extends WebInspector.VBox {
2064 { 2000 constructor() {
2065 }; 2001 super();
2066
2067 WebInspector.HeapTrackingOverviewGrid.OverviewCalculator.prototype = {
2068 /**
2069 * @override
2070 * @return {number}
2071 */
2072 paddingLeft: function()
2073 {
2074 return 0;
2075 },
2076
2077 /**
2078 * @param {!WebInspector.HeapTrackingOverviewGrid} chart
2079 */
2080 _updateBoundaries: function(chart)
2081 {
2082 this._minimumBoundaries = 0;
2083 this._maximumBoundaries = chart._profileSamples.totalTime;
2084 this._xScaleFactor = chart._overviewContainer.clientWidth / this._maximu mBoundaries;
2085 },
2086
2087 /**
2088 * @override
2089 * @param {number} time
2090 * @return {number}
2091 */
2092 computePosition: function(time)
2093 {
2094 return (time - this._minimumBoundaries) * this._xScaleFactor;
2095 },
2096
2097 /**
2098 * @override
2099 * @param {number} value
2100 * @param {number=} precision
2101 * @return {string}
2102 */
2103 formatValue: function(value, precision)
2104 {
2105 return Number.secondsToString(value / 1000, !!precision);
2106 },
2107
2108 /**
2109 * @override
2110 * @return {number}
2111 */
2112 maximumBoundary: function()
2113 {
2114 return this._maximumBoundaries;
2115 },
2116
2117 /**
2118 * @override
2119 * @return {number}
2120 */
2121 minimumBoundary: function()
2122 {
2123 return this._minimumBoundaries;
2124 },
2125
2126 /**
2127 * @override
2128 * @return {number}
2129 */
2130 zeroTime: function()
2131 {
2132 return this._minimumBoundaries;
2133 },
2134
2135 /**
2136 * @override
2137 * @return {number}
2138 */
2139 boundarySpan: function()
2140 {
2141 return this._maximumBoundaries - this._minimumBoundaries;
2142 }
2143 };
2144
2145
2146 /**
2147 * @constructor
2148 * @extends {WebInspector.VBox}
2149 */
2150 WebInspector.HeapSnapshotStatisticsView = function()
2151 {
2152 WebInspector.VBox.call(this);
2153 this.setMinimumSize(50, 25); 2002 this.setMinimumSize(50, 25);
2154 this._pieChart = new WebInspector.PieChart(150, WebInspector.HeapSnapshotSta tisticsView._valueFormatter, true); 2003 this._pieChart = new WebInspector.PieChart(150, WebInspector.HeapSnapshotSta tisticsView._valueFormatter, true);
2155 this._pieChart.element.classList.add("heap-snapshot-stats-pie-chart"); 2004 this._pieChart.element.classList.add('heap-snapshot-stats-pie-chart');
2156 this.element.appendChild(this._pieChart.element); 2005 this.element.appendChild(this._pieChart.element);
2157 this._labels = this.element.createChild("div", "heap-snapshot-stats-legend") ; 2006 this._labels = this.element.createChild('div', 'heap-snapshot-stats-legend') ;
2007 }
2008
2009 /**
2010 * @param {number} value
2011 * @return {string}
2012 */
2013 static _valueFormatter(value) {
2014 return WebInspector.UIString('%s KB', Number.withThousandsSeparator(Math.rou nd(value / 1024)));
2015 }
2016
2017 /**
2018 * @param {number} value
2019 */
2020 setTotal(value) {
2021 this._pieChart.setTotal(value);
2022 }
2023
2024 /**
2025 * @param {number} value
2026 * @param {string} name
2027 * @param {string=} color
2028 */
2029 addRecord(value, name, color) {
2030 if (color)
2031 this._pieChart.addSlice(value, color);
2032
2033 var node = this._labels.createChild('div');
2034 var swatchDiv = node.createChild('div', 'heap-snapshot-stats-swatch');
2035 var nameDiv = node.createChild('div', 'heap-snapshot-stats-name');
2036 var sizeDiv = node.createChild('div', 'heap-snapshot-stats-size');
2037 if (color)
2038 swatchDiv.style.backgroundColor = color;
2039 else
2040 swatchDiv.classList.add('heap-snapshot-stats-empty-swatch');
2041 nameDiv.textContent = name;
2042 sizeDiv.textContent = WebInspector.HeapSnapshotStatisticsView._valueFormatte r(value);
2043 }
2158 }; 2044 };
2159 2045
2046
2160 /** 2047 /**
2161 * @param {number} value 2048 * @unrestricted
2162 * @return {string}
2163 */ 2049 */
2164 WebInspector.HeapSnapshotStatisticsView._valueFormatter = function(value) 2050 WebInspector.HeapAllocationStackView = class extends WebInspector.Widget {
2165 { 2051 /**
2166 return WebInspector.UIString("%s KB", Number.withThousandsSeparator(Math.rou nd(value / 1024))); 2052 * @param {?WebInspector.Target} target
2167 }; 2053 */
2168 2054 constructor(target) {
2169 WebInspector.HeapSnapshotStatisticsView.prototype = { 2055 super();
2170 /**
2171 * @param {number} value
2172 */
2173 setTotal: function(value)
2174 {
2175 this._pieChart.setTotal(value);
2176 },
2177
2178 /**
2179 * @param {number} value
2180 * @param {string} name
2181 * @param {string=} color
2182 */
2183 addRecord: function(value, name, color)
2184 {
2185 if (color)
2186 this._pieChart.addSlice(value, color);
2187
2188 var node = this._labels.createChild("div");
2189 var swatchDiv = node.createChild("div", "heap-snapshot-stats-swatch");
2190 var nameDiv = node.createChild("div", "heap-snapshot-stats-name");
2191 var sizeDiv = node.createChild("div", "heap-snapshot-stats-size");
2192 if (color)
2193 swatchDiv.style.backgroundColor = color;
2194 else
2195 swatchDiv.classList.add("heap-snapshot-stats-empty-swatch");
2196 nameDiv.textContent = name;
2197 sizeDiv.textContent = WebInspector.HeapSnapshotStatisticsView._valueForm atter(value);
2198 },
2199
2200 __proto__: WebInspector.VBox.prototype
2201 };
2202
2203 /**
2204 * @constructor
2205 * @extends {WebInspector.Widget}
2206 * @param {?WebInspector.Target} target
2207 */
2208 WebInspector.HeapAllocationStackView = function(target)
2209 {
2210 WebInspector.Widget.call(this);
2211 this._target = target; 2056 this._target = target;
2212 this._linkifier = new WebInspector.Linkifier(); 2057 this._linkifier = new WebInspector.Linkifier();
2058 }
2059
2060 /**
2061 * @param {!WebInspector.HeapSnapshotProxy} snapshot
2062 * @param {number} snapshotNodeIndex
2063 */
2064 setAllocatedObject(snapshot, snapshotNodeIndex) {
2065 this.clear();
2066 snapshot.allocationStack(snapshotNodeIndex, this._didReceiveAllocationStack. bind(this));
2067 }
2068
2069 clear() {
2070 this.element.removeChildren();
2071 this._linkifier.reset();
2072 }
2073
2074 /**
2075 * @param {?Array.<!WebInspector.HeapSnapshotCommon.AllocationStackFrame>} fra mes
2076 */
2077 _didReceiveAllocationStack(frames) {
2078 if (!frames) {
2079 var stackDiv = this.element.createChild('div', 'no-heap-allocation-stack') ;
2080 stackDiv.createTextChild(WebInspector.UIString(
2081 'Stack was not recorded for this object because it had been allocated before this profile recording started.'));
2082 return;
2083 }
2084
2085 var stackDiv = this.element.createChild('div', 'heap-allocation-stack');
2086 for (var i = 0; i < frames.length; i++) {
2087 var frame = frames[i];
2088 var frameDiv = stackDiv.createChild('div', 'stack-frame');
2089 var name = frameDiv.createChild('div');
2090 name.textContent = WebInspector.beautifyFunctionName(frame.functionName);
2091 if (frame.scriptId) {
2092 var urlElement = this._linkifier.linkifyScriptLocation(
2093 this._target, String(frame.scriptId), frame.scriptName, frame.line - 1, frame.column - 1);
2094 frameDiv.appendChild(urlElement);
2095 }
2096 }
2097 }
2213 }; 2098 };
2214
2215 WebInspector.HeapAllocationStackView.prototype = {
2216 /**
2217 * @param {!WebInspector.HeapSnapshotProxy} snapshot
2218 * @param {number} snapshotNodeIndex
2219 */
2220 setAllocatedObject: function(snapshot, snapshotNodeIndex)
2221 {
2222 this.clear();
2223 snapshot.allocationStack(snapshotNodeIndex, this._didReceiveAllocationSt ack.bind(this));
2224 },
2225
2226 clear: function()
2227 {
2228 this.element.removeChildren();
2229 this._linkifier.reset();
2230 },
2231
2232 /**
2233 * @param {?Array.<!WebInspector.HeapSnapshotCommon.AllocationStackFrame>} f rames
2234 */
2235 _didReceiveAllocationStack: function(frames)
2236 {
2237 if (!frames) {
2238 var stackDiv = this.element.createChild("div", "no-heap-allocation-s tack");
2239 stackDiv.createTextChild(WebInspector.UIString("Stack was not record ed for this object because it had been allocated before this profile recording s tarted."));
2240 return;
2241 }
2242
2243 var stackDiv = this.element.createChild("div", "heap-allocation-stack");
2244 for (var i = 0; i < frames.length; i++) {
2245 var frame = frames[i];
2246 var frameDiv = stackDiv.createChild("div", "stack-frame");
2247 var name = frameDiv.createChild("div");
2248 name.textContent = WebInspector.beautifyFunctionName(frame.functionN ame);
2249 if (frame.scriptId) {
2250 var urlElement = this._linkifier.linkifyScriptLocation(this._tar get, String(frame.scriptId), frame.scriptName, frame.line - 1, frame.column - 1) ;
2251 frameDiv.appendChild(urlElement);
2252 }
2253 }
2254 },
2255
2256 __proto__: WebInspector.Widget.prototype
2257 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698