12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844 |
- /*
- * Copyright (C) 2011 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /**
- * @constructor
- * @extends {WebInspector.View}
- * @param {!WebInspector.ProfilesPanel} parent
- * @param {!WebInspector.HeapProfileHeader} profile
- */
- WebInspector.HeapSnapshotView = function(parent, profile)
- {
- WebInspector.View.call(this);
- this.element.addStyleClass("heap-snapshot-view");
- this.parent = parent;
- this.parent.addEventListener("profile added", this._onProfileHeaderAdded, this);
- if (profile._profileType.id === WebInspector.TrackingHeapSnapshotProfileType.TypeId) {
- this._trackingOverviewGrid = new WebInspector.HeapTrackingOverviewGrid(profile);
- this._trackingOverviewGrid.addEventListener(WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged, this._onIdsRangeChanged.bind(this));
- this._trackingOverviewGrid.show(this.element);
- }
- this.viewsContainer = document.createElement("div");
- this.viewsContainer.addStyleClass("views-container");
- this.element.appendChild(this.viewsContainer);
- this.containmentView = new WebInspector.View();
- this.containmentView.element.addStyleClass("view");
- this.containmentDataGrid = new WebInspector.HeapSnapshotContainmentDataGrid();
- this.containmentDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
- this.containmentDataGrid.show(this.containmentView.element);
- this.containmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
- this.constructorsView = new WebInspector.View();
- this.constructorsView.element.addStyleClass("view");
- this.constructorsView.element.appendChild(this._createToolbarWithClassNameFilter());
- this.constructorsDataGrid = new WebInspector.HeapSnapshotConstructorsDataGrid();
- this.constructorsDataGrid.element.addStyleClass("class-view-grid");
- this.constructorsDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
- this.constructorsDataGrid.show(this.constructorsView.element);
- this.constructorsDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
- this.dataGrid = /** @type {WebInspector.HeapSnapshotSortableDataGrid} */ (this.constructorsDataGrid);
- this.currentView = this.constructorsView;
- this.currentView.show(this.viewsContainer);
- this.diffView = new WebInspector.View();
- this.diffView.element.addStyleClass("view");
- this.diffView.element.appendChild(this._createToolbarWithClassNameFilter());
- this.diffDataGrid = new WebInspector.HeapSnapshotDiffDataGrid();
- this.diffDataGrid.element.addStyleClass("class-view-grid");
- this.diffDataGrid.show(this.diffView.element);
- this.diffDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
- this.dominatorView = new WebInspector.View();
- this.dominatorView.element.addStyleClass("view");
- this.dominatorDataGrid = new WebInspector.HeapSnapshotDominatorsDataGrid();
- this.dominatorDataGrid.element.addEventListener("mousedown", this._mouseDownInContentsGrid.bind(this), true);
- this.dominatorDataGrid.show(this.dominatorView.element);
- this.dominatorDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._selectionChanged, this);
- this.retainmentViewHeader = document.createElement("div");
- this.retainmentViewHeader.addStyleClass("retainers-view-header");
- WebInspector.installDragHandle(this.retainmentViewHeader, this._startRetainersHeaderDragging.bind(this), this._retainersHeaderDragging.bind(this), this._endRetainersHeaderDragging.bind(this), "row-resize");
- var retainingPathsTitleDiv = document.createElement("div");
- retainingPathsTitleDiv.className = "title";
- var retainingPathsTitle = document.createElement("span");
- retainingPathsTitle.textContent = WebInspector.UIString("Object's retaining tree");
- retainingPathsTitleDiv.appendChild(retainingPathsTitle);
- this.retainmentViewHeader.appendChild(retainingPathsTitleDiv);
- this.element.appendChild(this.retainmentViewHeader);
- this.retainmentView = new WebInspector.View();
- this.retainmentView.element.addStyleClass("view");
- this.retainmentView.element.addStyleClass("retaining-paths-view");
- this.retainmentDataGrid = new WebInspector.HeapSnapshotRetainmentDataGrid();
- this.retainmentDataGrid.show(this.retainmentView.element);
- this.retainmentDataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._inspectedObjectChanged, this);
- this.retainmentView.show(this.element);
- this.retainmentDataGrid.reset();
- this.viewSelect = new WebInspector.StatusBarComboBox(this._onSelectedViewChanged.bind(this));
- this.views = [{title: "Summary", view: this.constructorsView, grid: this.constructorsDataGrid},
- {title: "Comparison", view: this.diffView, grid: this.diffDataGrid},
- {title: "Containment", view: this.containmentView, grid: this.containmentDataGrid}];
- if (WebInspector.settings.showAdvancedHeapSnapshotProperties.get())
- this.views.push({title: "Dominators", view: this.dominatorView, grid: this.dominatorDataGrid});
- this.views.current = 0;
- for (var i = 0; i < this.views.length; ++i)
- this.viewSelect.createOption(WebInspector.UIString(this.views[i].title));
- this._profileUid = profile.uid;
- this._profileTypeId = profile.profileType().id;
- this.baseSelect = new WebInspector.StatusBarComboBox(this._changeBase.bind(this));
- this.baseSelect.element.addStyleClass("hidden");
- this._updateBaseOptions();
- this.filterSelect = new WebInspector.StatusBarComboBox(this._changeFilter.bind(this));
- this._updateFilterOptions();
- this.selectedSizeText = new WebInspector.StatusBarText("");
- this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefined, true);
- this.profile.load(profileCallback.bind(this));
- function profileCallback(heapSnapshotProxy)
- {
- var list = this._profiles();
- var profileIndex;
- for (var i = 0; i < list.length; ++i) {
- if (list[i].uid === this._profileUid) {
- profileIndex = i;
- break;
- }
- }
- if (profileIndex > 0)
- this.baseSelect.setSelectedIndex(profileIndex - 1);
- else
- this.baseSelect.setSelectedIndex(profileIndex);
- this.dataGrid.setDataSource(heapSnapshotProxy);
- }
- }
- WebInspector.HeapSnapshotView.prototype = {
- _onIdsRangeChanged: function(event)
- {
- var minId = event.data.minId;
- var maxId = event.data.maxId;
- this.selectedSizeText.setText(WebInspector.UIString("Selected size: %s", Number.bytesToString(event.data.size)));
- if (this.constructorsDataGrid.snapshot)
- this.constructorsDataGrid.setSelectionRange(minId, maxId);
- },
- dispose: function()
- {
- this.parent.removeEventListener("profile added", this._onProfileHeaderAdded, this);
- this.profile.dispose();
- if (this.baseProfile)
- this.baseProfile.dispose();
- this.containmentDataGrid.dispose();
- this.constructorsDataGrid.dispose();
- this.diffDataGrid.dispose();
- this.dominatorDataGrid.dispose();
- this.retainmentDataGrid.dispose();
- },
- get statusBarItems()
- {
- return [this.viewSelect.element, this.baseSelect.element, this.filterSelect.element, this.selectedSizeText.element];
- },
- get profile()
- {
- return this.parent.getProfile(this._profileTypeId, this._profileUid);
- },
- get baseProfile()
- {
- return this.parent.getProfile(this._profileTypeId, this._baseProfileUid);
- },
- wasShown: function()
- {
- // FIXME: load base and current snapshots in parallel
- this.profile.load(profileCallback.bind(this));
- function profileCallback() {
- this.profile._wasShown();
- if (this.baseProfile)
- this.baseProfile.load(function() { });
- }
- },
- willHide: function()
- {
- this._currentSearchResultIndex = -1;
- this._popoverHelper.hidePopover();
- if (this.helpPopover && this.helpPopover.isShowing())
- this.helpPopover.hide();
- },
- onResize: function()
- {
- var height = this.retainmentView.element.clientHeight;
- this._updateRetainmentViewHeight(height);
- },
- searchCanceled: function()
- {
- if (this._searchResults) {
- for (var i = 0; i < this._searchResults.length; ++i) {
- var node = this._searchResults[i].node;
- delete node._searchMatched;
- node.refresh();
- }
- }
- delete this._searchFinishedCallback;
- this._currentSearchResultIndex = -1;
- this._searchResults = [];
- },
- /**
- * @param {string} query
- * @param {function(!WebInspector.View, number)} finishedCallback
- */
- performSearch: function(query, finishedCallback)
- {
- // Call searchCanceled since it will reset everything we need before doing a new search.
- this.searchCanceled();
- query = query.trim();
- if (!query)
- return;
- if (this.currentView !== this.constructorsView && this.currentView !== this.diffView)
- return;
- this._searchFinishedCallback = finishedCallback;
- var nameRegExp = createPlainTextSearchRegex(query, "i");
- var snapshotNodeId = null;
- function matchesByName(gridNode) {
- return ("_name" in gridNode) && nameRegExp.test(gridNode._name);
- }
- function matchesById(gridNode) {
- return ("snapshotNodeId" in gridNode) && gridNode.snapshotNodeId === snapshotNodeId;
- }
- var matchPredicate;
- if (query.charAt(0) !== "@")
- matchPredicate = matchesByName;
- else {
- snapshotNodeId = parseInt(query.substring(1), 10);
- matchPredicate = matchesById;
- }
- function matchesQuery(gridNode)
- {
- delete gridNode._searchMatched;
- if (matchPredicate(gridNode)) {
- gridNode._searchMatched = true;
- gridNode.refresh();
- return true;
- }
- return false;
- }
- var current = this.dataGrid.rootNode().children[0];
- var depth = 0;
- var info = {};
- // Restrict to type nodes and instances.
- const maxDepth = 1;
- while (current) {
- if (matchesQuery(current))
- this._searchResults.push({ node: current });
- current = current.traverseNextNode(false, null, (depth >= maxDepth), info);
- depth += info.depthChange;
- }
- finishedCallback(this, this._searchResults.length);
- },
- jumpToFirstSearchResult: function()
- {
- if (!this._searchResults || !this._searchResults.length)
- return;
- this._currentSearchResultIndex = 0;
- this._jumpToSearchResult(this._currentSearchResultIndex);
- },
- jumpToLastSearchResult: function()
- {
- if (!this._searchResults || !this._searchResults.length)
- return;
- this._currentSearchResultIndex = (this._searchResults.length - 1);
- this._jumpToSearchResult(this._currentSearchResultIndex);
- },
- jumpToNextSearchResult: function()
- {
- if (!this._searchResults || !this._searchResults.length)
- return;
- if (++this._currentSearchResultIndex >= this._searchResults.length)
- this._currentSearchResultIndex = 0;
- this._jumpToSearchResult(this._currentSearchResultIndex);
- },
- jumpToPreviousSearchResult: function()
- {
- if (!this._searchResults || !this._searchResults.length)
- return;
- if (--this._currentSearchResultIndex < 0)
- this._currentSearchResultIndex = (this._searchResults.length - 1);
- this._jumpToSearchResult(this._currentSearchResultIndex);
- },
- showingFirstSearchResult: function()
- {
- return (this._currentSearchResultIndex === 0);
- },
- showingLastSearchResult: function()
- {
- return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
- },
- _jumpToSearchResult: function(index)
- {
- var searchResult = this._searchResults[index];
- if (!searchResult)
- return;
- var node = searchResult.node;
- node.revealAndSelect();
- },
- refreshVisibleData: function()
- {
- var child = this.dataGrid.rootNode().children[0];
- while (child) {
- child.refresh();
- child = child.traverseNextNode(false, null, true);
- }
- },
- _changeBase: function()
- {
- if (this._baseProfileUid === this._profiles()[this.baseSelect.selectedIndex()].uid)
- return;
- this._baseProfileUid = this._profiles()[this.baseSelect.selectedIndex()].uid;
- var dataGrid = /** @type {WebInspector.HeapSnapshotDiffDataGrid} */ (this.dataGrid);
- // Change set base data source only if main data source is already set.
- if (dataGrid.snapshot)
- this.baseProfile.load(dataGrid.setBaseDataSource.bind(dataGrid));
- if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
- return;
- // The current search needs to be performed again. First negate out previous match
- // count by calling the search finished callback with a negative number of matches.
- // Then perform the search again with the same query and callback.
- this._searchFinishedCallback(this, -this._searchResults.length);
- this.performSearch(this.currentQuery, this._searchFinishedCallback);
- },
- _changeFilter: function()
- {
- var profileIndex = this.filterSelect.selectedIndex() - 1;
- this.dataGrid.filterSelectIndexChanged(this._profiles(), profileIndex);
- WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
- action: WebInspector.UserMetrics.UserActionNames.HeapSnapshotFilterChanged,
- label: this.filterSelect.selectedOption().label
- });
- if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
- return;
- // The current search needs to be performed again. First negate out previous match
- // count by calling the search finished callback with a negative number of matches.
- // Then perform the search again with the same query and callback.
- this._searchFinishedCallback(this, -this._searchResults.length);
- this.performSearch(this.currentQuery, this._searchFinishedCallback);
- },
- _createToolbarWithClassNameFilter: function()
- {
- var toolbar = document.createElement("div");
- toolbar.addStyleClass("class-view-toolbar");
- var classNameFilter = document.createElement("input");
- classNameFilter.addStyleClass("class-name-filter");
- classNameFilter.setAttribute("placeholder", WebInspector.UIString("Class filter"));
- classNameFilter.addEventListener("keyup", this._changeNameFilter.bind(this, classNameFilter), false);
- toolbar.appendChild(classNameFilter);
- return toolbar;
- },
- _changeNameFilter: function(classNameInputElement)
- {
- var filter = classNameInputElement.value;
- this.dataGrid.changeNameFilter(filter);
- },
- /**
- * @return {!Array.<!WebInspector.ProfileHeader>}
- */
- _profiles: function()
- {
- return this.parent.getProfileType(this._profileTypeId).getProfiles();
- },
- /**
- * @param {WebInspector.ContextMenu} contextMenu
- * @param {Event} event
- */
- populateContextMenu: function(contextMenu, event)
- {
- this.dataGrid.populateContextMenu(this.parent, contextMenu, event);
- },
- _selectionChanged: function(event)
- {
- var selectedNode = event.target.selectedNode;
- this._setRetainmentDataGridSource(selectedNode);
- this._inspectedObjectChanged(event);
- },
- _inspectedObjectChanged: function(event)
- {
- var selectedNode = event.target.selectedNode;
- if (!this.profile.fromFile() && selectedNode instanceof WebInspector.HeapSnapshotGenericObjectNode)
- ConsoleAgent.addInspectedHeapObject(selectedNode.snapshotNodeId);
- },
- _setRetainmentDataGridSource: function(nodeItem)
- {
- if (nodeItem && nodeItem.snapshotNodeIndex)
- this.retainmentDataGrid.setDataSource(nodeItem.isDeletedNode ? nodeItem.dataGrid.baseSnapshot : nodeItem.dataGrid.snapshot, nodeItem.snapshotNodeIndex);
- else
- this.retainmentDataGrid.reset();
- },
- _mouseDownInContentsGrid: function(event)
- {
- if (event.detail < 2)
- return;
- var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
- if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("shallowSize-column") && !cell.hasStyleClass("retainedSize-column")))
- return;
- event.consume(true);
- },
- changeView: function(viewTitle, callback)
- {
- var viewIndex = null;
- for (var i = 0; i < this.views.length; ++i) {
- if (this.views[i].title === viewTitle) {
- viewIndex = i;
- break;
- }
- }
- if (this.views.current === viewIndex || viewIndex == null) {
- setTimeout(callback, 0);
- return;
- }
- function dataGridContentShown(event)
- {
- var dataGrid = event.data;
- dataGrid.removeEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
- if (dataGrid === this.dataGrid)
- callback();
- }
- this.views[viewIndex].grid.addEventListener(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, dataGridContentShown, this);
- this.viewSelect.setSelectedIndex(viewIndex);
- this._changeView(viewIndex);
- },
- _updateDataSourceAndView: function()
- {
- var dataGrid = this.dataGrid;
- if (dataGrid.snapshot)
- return;
- this.profile.load(didLoadSnapshot.bind(this));
- function didLoadSnapshot(snapshotProxy)
- {
- if (this.dataGrid !== dataGrid)
- return;
- if (dataGrid.snapshot !== snapshotProxy)
- dataGrid.setDataSource(snapshotProxy);
- if (dataGrid === this.diffDataGrid) {
- if (!this._baseProfileUid)
- this._baseProfileUid = this._profiles()[this.baseSelect.selectedIndex()].uid;
- this.baseProfile.load(didLoadBaseSnaphot.bind(this));
- }
- }
- function didLoadBaseSnaphot(baseSnapshotProxy)
- {
- if (this.diffDataGrid.baseSnapshot !== baseSnapshotProxy)
- this.diffDataGrid.setBaseDataSource(baseSnapshotProxy);
- }
- },
- _onSelectedViewChanged: function(event)
- {
- this._changeView(event.target.selectedIndex);
- },
- _updateSelectorsVisibility: function()
- {
- if (this.currentView === this.diffView)
- this.baseSelect.element.removeStyleClass("hidden");
- else
- this.baseSelect.element.addStyleClass("hidden");
- if (this.currentView === this.constructorsView) {
- if (this._trackingOverviewGrid) {
- this._trackingOverviewGrid.element.removeStyleClass("hidden");
- this._trackingOverviewGrid.update();
- this.viewsContainer.addStyleClass("reserve-80px-at-top");
- }
- this.filterSelect.element.removeStyleClass("hidden");
- } else {
- this.filterSelect.element.addStyleClass("hidden");
- if (this._trackingOverviewGrid) {
- this._trackingOverviewGrid.element.addStyleClass("hidden");
- this.viewsContainer.removeStyleClass("reserve-80px-at-top");
- }
- }
- },
- _changeView: function(selectedIndex)
- {
- if (selectedIndex === this.views.current)
- return;
- this.views.current = selectedIndex;
- this.currentView.detach();
- var view = this.views[this.views.current];
- this.currentView = view.view;
- this.dataGrid = view.grid;
- this.currentView.show(this.viewsContainer);
- this.refreshVisibleData();
- this.dataGrid.updateWidths();
- this._updateSelectorsVisibility();
- this._updateDataSourceAndView();
- if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
- return;
- // The current search needs to be performed again. First negate out previous match
- // count by calling the search finished callback with a negative number of matches.
- // Then perform the search again the with same query and callback.
- this._searchFinishedCallback(this, -this._searchResults.length);
- this.performSearch(this.currentQuery, this._searchFinishedCallback);
- },
- _getHoverAnchor: function(target)
- {
- var span = target.enclosingNodeOrSelfWithNodeName("span");
- if (!span)
- return;
- var row = target.enclosingNodeOrSelfWithNodeName("tr");
- if (!row)
- return;
- span.node = row._dataGridNode;
- return span;
- },
- _resolveObjectForPopover: function(element, showCallback, objectGroupName)
- {
- if (this.profile.fromFile())
- return;
- element.node.queryObjectContent(showCallback, objectGroupName);
- },
- /**
- * @return {boolean}
- */
- _startRetainersHeaderDragging: function(event)
- {
- if (!this.isShowing())
- return false;
- this._previousDragPosition = event.pageY;
- return true;
- },
- _retainersHeaderDragging: function(event)
- {
- var height = this.retainmentView.element.clientHeight;
- height += this._previousDragPosition - event.pageY;
- this._previousDragPosition = event.pageY;
- this._updateRetainmentViewHeight(height);
- event.consume(true);
- },
- _endRetainersHeaderDragging: function(event)
- {
- delete this._previousDragPosition;
- event.consume();
- },
- _updateRetainmentViewHeight: function(height)
- {
- height = Number.constrain(height, Preferences.minConsoleHeight, this.element.clientHeight - Preferences.minConsoleHeight);
- this.viewsContainer.style.bottom = (height + this.retainmentViewHeader.clientHeight) + "px";
- if (this._trackingOverviewGrid && this.currentView === this.constructorsView)
- this.viewsContainer.addStyleClass("reserve-80px-at-top");
- this.retainmentView.element.style.height = height + "px";
- this.retainmentViewHeader.style.bottom = height + "px";
- this.currentView.doResize();
- },
- _updateBaseOptions: function()
- {
- var list = this._profiles();
- // We're assuming that snapshots can only be added.
- if (this.baseSelect.size() === list.length)
- return;
- for (var i = this.baseSelect.size(), n = list.length; i < n; ++i) {
- var title = list[i].title;
- if (WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(title))
- title = WebInspector.UIString("Snapshot %d", WebInspector.ProfilesPanelDescriptor.userInitiatedProfileIndex(title));
- this.baseSelect.createOption(title);
- }
- },
- _updateFilterOptions: function()
- {
- var list = this._profiles();
- // We're assuming that snapshots can only be added.
- if (this.filterSelect.size() - 1 === list.length)
- return;
- if (!this.filterSelect.size())
- this.filterSelect.createOption(WebInspector.UIString("All objects"));
- if (this.profile.fromFile())
- return;
- for (var i = this.filterSelect.size() - 1, n = list.length; i < n; ++i) {
- var profile = list[i];
- var title = list[i].title;
- if (WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(title)) {
- var profileIndex = WebInspector.ProfilesPanelDescriptor.userInitiatedProfileIndex(title);
- if (!i)
- title = WebInspector.UIString("Objects allocated before Snapshot %d", profileIndex);
- else
- title = WebInspector.UIString("Objects allocated between Snapshots %d and %d", profileIndex - 1, profileIndex);
- }
- this.filterSelect.createOption(title);
- }
- },
- /**
- * @param {WebInspector.Event} event
- */
- _onProfileHeaderAdded: function(event)
- {
- if (!event.data || event.data.type !== this._profileTypeId)
- return;
- this._updateBaseOptions();
- this._updateFilterOptions();
- },
- __proto__: WebInspector.View.prototype
- }
- /**
- * @constructor
- * @implements {HeapProfilerAgent.Dispatcher}
- */
- WebInspector.HeapProfilerDispatcher = function()
- {
- this._dispatchers = [];
- InspectorBackend.registerHeapProfilerDispatcher(this);
- }
- WebInspector.HeapProfilerDispatcher.prototype = {
- /**
- * @param {HeapProfilerAgent.Dispatcher} dispatcher
- */
- register: function(dispatcher)
- {
- this._dispatchers.push(dispatcher);
- },
- _genericCaller: function(eventName)
- {
- var args = Array.prototype.slice.call(arguments.callee.caller.arguments);
- for (var i = 0; i < this._dispatchers.length; ++i)
- this._dispatchers[i][eventName].apply(this._dispatchers[i], args);
- },
- /**
- * @override
- * @param {Array.<number>} samples
- */
- heapStatsUpdate: function(samples)
- {
- this._genericCaller("heapStatsUpdate");
- },
- /**
- * @override
- * @param {number} lastSeenObjectId
- * @param {number} timestamp
- */
- lastSeenObjectId: function(lastSeenObjectId, timestamp)
- {
- this._genericCaller("lastSeenObjectId");
- },
- /**
- * @param {HeapProfilerAgent.ProfileHeader} profileHeader
- */
- addProfileHeader: function(profileHeader)
- {
- this._genericCaller("addProfileHeader");
- },
- /**
- * @override
- * @param {number} uid
- * @param {string} chunk
- */
- addHeapSnapshotChunk: function(uid, chunk)
- {
- this._genericCaller("addHeapSnapshotChunk");
- },
- /**
- * @override
- * @param {number} uid
- */
- finishHeapSnapshot: function(uid)
- {
- this._genericCaller("finishHeapSnapshot");
- },
- /**
- * @override
- * @param {number} done
- * @param {number} total
- */
- reportHeapSnapshotProgress: function(done, total)
- {
- this._genericCaller("reportHeapSnapshotProgress");
- },
- /**
- * @override
- */
- resetProfiles: function()
- {
- this._genericCaller("resetProfiles");
- }
- }
- WebInspector.HeapProfilerDispatcher._dispatcher = new WebInspector.HeapProfilerDispatcher();
- /**
- * @constructor
- * @extends {WebInspector.ProfileType}
- * @implements {HeapProfilerAgent.Dispatcher}
- */
- WebInspector.HeapSnapshotProfileType = function()
- {
- WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("Take Heap Snapshot"));
- WebInspector.HeapProfilerDispatcher._dispatcher.register(this);
- }
- WebInspector.HeapSnapshotProfileType.TypeId = "HEAP";
- WebInspector.HeapSnapshotProfileType.SnapshotReceived = "SnapshotReceived";
- WebInspector.HeapSnapshotProfileType.prototype = {
- /**
- * @override
- * @return {string}
- */
- fileExtension: function()
- {
- return ".heapsnapshot";
- },
- get buttonTooltip()
- {
- return WebInspector.UIString("Take heap snapshot.");
- },
- /**
- * @override
- * @return {boolean}
- */
- isInstantProfile: function()
- {
- return true;
- },
- /**
- * @override
- * @return {boolean}
- */
- buttonClicked: function()
- {
- this._takeHeapSnapshot(function() {});
- WebInspector.userMetrics.ProfilesHeapProfileTaken.record();
- return false;
- },
- /**
- * @override
- * @param {Array.<number>} samples
- */
- heapStatsUpdate: function(samples)
- {
- },
- /**
- * @override
- * @param {number} lastSeenObjectId
- * @param {number} timestamp
- */
- lastSeenObjectId: function(lastSeenObjectId, timestamp)
- {
- },
- get treeItemTitle()
- {
- return WebInspector.UIString("HEAP SNAPSHOTS");
- },
- get description()
- {
- return WebInspector.UIString("Heap snapshot profiles show memory distribution among your page's JavaScript objects and related DOM nodes.");
- },
- /**
- * @override
- * @param {string=} title
- * @return {!WebInspector.ProfileHeader}
- */
- createTemporaryProfile: function(title)
- {
- title = title || WebInspector.UIString("Snapshotting\u2026");
- return new WebInspector.HeapProfileHeader(this, title);
- },
- /**
- * @override
- * @param {HeapProfilerAgent.ProfileHeader} profile
- * @return {!WebInspector.ProfileHeader}
- */
- createProfile: function(profile)
- {
- return new WebInspector.HeapProfileHeader(this, profile.title, profile.uid, profile.maxJSObjectId || 0);
- },
- _takeHeapSnapshot: function(callback)
- {
- var temporaryProfile = this.findTemporaryProfile();
- if (!temporaryProfile)
- this.addProfile(this.createTemporaryProfile());
- HeapProfilerAgent.takeHeapSnapshot(true, callback);
- },
- /**
- * @param {HeapProfilerAgent.ProfileHeader} profileHeader
- */
- addProfileHeader: function(profileHeader)
- {
- if (!this.findTemporaryProfile())
- return;
- var profile = this.createProfile(profileHeader);
- profile._profileSamples = this._profileSamples;
- this._profileSamples = null;
- this.addProfile(profile);
- },
- /**
- * @override
- * @param {number} uid
- * @param {string} chunk
- */
- addHeapSnapshotChunk: function(uid, chunk)
- {
- var profile = this._profilesIdMap[this._makeKey(uid)];
- if (profile)
- profile.transferChunk(chunk);
- },
- /**
- * @override
- * @param {number} uid
- */
- finishHeapSnapshot: function(uid)
- {
- var profile = this._profilesIdMap[this._makeKey(uid)];
- if (profile)
- profile.finishHeapSnapshot();
- },
- /**
- * @override
- * @param {number} done
- * @param {number} total
- */
- reportHeapSnapshotProgress: function(done, total)
- {
- var profile = this.findTemporaryProfile();
- if (profile)
- this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProgressUpdated, {"profile": profile, "done": done, "total": total});
- },
- /**
- * @override
- */
- resetProfiles: function()
- {
- this._reset();
- },
- /**
- * @override
- * @param {!WebInspector.ProfileHeader} profile
- */
- removeProfile: function(profile)
- {
- WebInspector.ProfileType.prototype.removeProfile.call(this, profile);
- if (!profile.isTemporary)
- HeapProfilerAgent.removeProfile(profile.uid);
- },
- /**
- * @override
- * @param {function(this:WebInspector.ProfileType, ?string, Array.<HeapProfilerAgent.ProfileHeader>)} populateCallback
- */
- _requestProfilesFromBackend: function(populateCallback)
- {
- HeapProfilerAgent.getProfileHeaders(populateCallback);
- },
- _snapshotReceived: function(profile)
- {
- this.dispatchEventToListeners(WebInspector.HeapSnapshotProfileType.SnapshotReceived, profile);
- },
- __proto__: WebInspector.ProfileType.prototype
- }
- /**
- * @constructor
- * @extends {WebInspector.HeapSnapshotProfileType}
- * @param {WebInspector.ProfilesPanel} profilesPanel
- */
- WebInspector.TrackingHeapSnapshotProfileType = function(profilesPanel)
- {
- WebInspector.ProfileType.call(this, WebInspector.TrackingHeapSnapshotProfileType.TypeId, WebInspector.UIString("Record Heap Allocations"));
- this._profilesPanel = profilesPanel;
- WebInspector.HeapProfilerDispatcher._dispatcher.register(this);
- }
- WebInspector.TrackingHeapSnapshotProfileType.TypeId = "HEAP-RECORD";
- WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate = "HeapStatsUpdate";
- WebInspector.TrackingHeapSnapshotProfileType.TrackingStarted = "TrackingStarted";
- WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped = "TrackingStopped";
- WebInspector.TrackingHeapSnapshotProfileType.prototype = {
- /**
- * @override
- * @param {Array.<number>} samples
- */
- heapStatsUpdate: function(samples)
- {
- if (!this._profileSamples)
- return;
- var index;
- for (var i = 0; i < samples.length; i += 3) {
- index = samples[i];
- var count = samples[i+1];
- var size = samples[i+2];
- this._profileSamples.sizes[index] = size;
- if (!this._profileSamples.max[index] || size > this._profileSamples.max[index])
- this._profileSamples.max[index] = size;
- }
- this._lastUpdatedIndex = index;
- },
- /**
- * @override
- * @param {number} lastSeenObjectId
- * @param {number} timestamp
- */
- lastSeenObjectId: function(lastSeenObjectId, timestamp)
- {
- var profileSamples = this._profileSamples;
- if (!profileSamples)
- return;
- var currentIndex = Math.max(profileSamples.ids.length, profileSamples.max.length - 1);
- profileSamples.ids[currentIndex] = lastSeenObjectId;
- if (!profileSamples.max[currentIndex]) {
- profileSamples.max[currentIndex] = 0;
- profileSamples.sizes[currentIndex] = 0;
- }
- profileSamples.timestamps[currentIndex] = timestamp;
- if (profileSamples.totalTime < timestamp - profileSamples.timestamps[0])
- profileSamples.totalTime *= 2;
- this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._profileSamples);
- var profile = this.findTemporaryProfile();
- profile.sidebarElement.wait = true;
- if (profile.sidebarElement && !profile.sidebarElement.wait)
- profile.sidebarElement.wait = true;
- },
- /**
- * @override
- * @return {boolean}
- */
- hasTemporaryView: function()
- {
- return true;
- },
- get buttonTooltip()
- {
- return this._recording ? WebInspector.UIString("Stop recording heap profile.") : WebInspector.UIString("Start recording heap profile.");
- },
- /**
- * @override
- * @return {boolean}
- */
- isInstantProfile: function()
- {
- return false;
- },
- /**
- * @override
- * @return {boolean}
- */
- buttonClicked: function()
- {
- return this._toggleRecording();
- },
- _startRecordingProfile: function()
- {
- this._lastSeenIndex = -1;
- this._profileSamples = {
- 'sizes': [],
- 'ids': [],
- 'timestamps': [],
- 'max': [],
- 'totalTime': 30000
- };
- this._recording = true;
- HeapProfilerAgent.startTrackingHeapObjects();
- this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.TrackingStarted);
- },
- _stopRecordingProfile: function()
- {
- HeapProfilerAgent.stopTrackingHeapObjects();
- HeapProfilerAgent.takeHeapSnapshot(true);
- this._recording = false;
- this.dispatchEventToListeners(WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped);
- },
- _toggleRecording: function()
- {
- if (this._recording)
- this._stopRecordingProfile();
- else
- this._startRecordingProfile();
- return this._recording;
- },
- get treeItemTitle()
- {
- return WebInspector.UIString("HEAP TIMELINES");
- },
- get description()
- {
- return WebInspector.UIString("Record JavaScript object allocations over time. Use this profile type to isolate memory leaks.");
- },
- _reset: function()
- {
- WebInspector.HeapSnapshotProfileType.prototype._reset.call(this);
- if (this._recording)
- this._stopRecordingProfile();
- this._profileSamples = null;
- this._lastSeenIndex = -1;
- },
- /**
- * @override
- * @param {string=} title
- * @return {!WebInspector.ProfileHeader}
- */
- createTemporaryProfile: function(title)
- {
- title = title || WebInspector.UIString("Recording\u2026");
- return new WebInspector.HeapProfileHeader(this, title);
- },
- /**
- * @override
- * @param {function(this:WebInspector.ProfileType, ?string, Array.<HeapProfilerAgent.ProfileHeader>)} populateCallback
- */
- _requestProfilesFromBackend: function(populateCallback)
- {
- },
- __proto__: WebInspector.HeapSnapshotProfileType.prototype
- }
- /**
- * @constructor
- * @extends {WebInspector.ProfileHeader}
- * @param {!WebInspector.ProfileType} type
- * @param {string} title
- * @param {number=} uid
- * @param {number=} maxJSObjectId
- */
- WebInspector.HeapProfileHeader = function(type, title, uid, maxJSObjectId)
- {
- WebInspector.ProfileHeader.call(this, type, title, uid);
- this.maxJSObjectId = maxJSObjectId;
- /**
- * @type {WebInspector.OutputStream}
- */
- this._receiver = null;
- /**
- * @type {WebInspector.HeapSnapshotProxy}
- */
- this._snapshotProxy = null;
- this._totalNumberOfChunks = 0;
- this._transferHandler = null;
- }
- WebInspector.HeapProfileHeader.prototype = {
- /**
- * @override
- */
- createSidebarTreeElement: function()
- {
- return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item");
- },
- /**
- * @override
- * @param {!WebInspector.ProfilesPanel} profilesPanel
- */
- createView: function(profilesPanel)
- {
- return new WebInspector.HeapSnapshotView(profilesPanel, this);
- },
- /**
- * @override
- * @param {function(WebInspector.HeapSnapshotProxy):void} callback
- */
- load: function(callback)
- {
- if (this.uid === -1)
- return;
- if (this._snapshotProxy) {
- callback(this._snapshotProxy);
- return;
- }
- this._numberOfChunks = 0;
- if (!this._receiver) {
- this._setupWorker();
- this._transferHandler = new WebInspector.BackendSnapshotLoader(this);
- this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
- this.sidebarElement.wait = true;
- this.startSnapshotTransfer();
- }
- var loaderProxy = /** @type {WebInspector.HeapSnapshotLoaderProxy} */ (this._receiver);
- loaderProxy.addConsumer(callback);
- },
- startSnapshotTransfer: function()
- {
- HeapProfilerAgent.getHeapSnapshot(this.uid);
- },
- snapshotConstructorName: function()
- {
- return "JSHeapSnapshot";
- },
- snapshotProxyConstructor: function()
- {
- return WebInspector.HeapSnapshotProxy;
- },
- _setupWorker: function()
- {
- function setProfileWait(event)
- {
- this.sidebarElement.wait = event.data;
- }
- var worker = new WebInspector.HeapSnapshotWorkerProxy(this._handleWorkerEvent.bind(this));
- worker.addEventListener("wait", setProfileWait, this);
- var loaderProxy = worker.createLoader(this.snapshotConstructorName(), this.snapshotProxyConstructor());
- loaderProxy.addConsumer(this._snapshotReceived.bind(this));
- this._receiver = loaderProxy;
- },
- /**
- * @param{string} eventName
- * @param{*} data
- */
- _handleWorkerEvent: function(eventName, data)
- {
- if (WebInspector.HeapSnapshotProgress.Event.Update !== eventName)
- return;
- this._updateSubtitle(data);
- },
- /**
- * @override
- */
- dispose: function()
- {
- if (this._receiver)
- this._receiver.close();
- else if (this._snapshotProxy)
- this._snapshotProxy.dispose();
- if (this._view) {
- var view = this._view;
- this._view = null;
- view.dispose();
- }
- },
- _updateSubtitle: function(value)
- {
- this.sidebarElement.subtitle = value;
- },
- _didCompleteSnapshotTransfer: function()
- {
- this.sidebarElement.subtitle = Number.bytesToString(this._snapshotProxy.totalSize);
- this.sidebarElement.wait = false;
- },
- /**
- * @param {string} chunk
- */
- transferChunk: function(chunk)
- {
- this._transferHandler.transferChunk(chunk);
- },
- _snapshotReceived: function(snapshotProxy)
- {
- this._receiver = null;
- if (snapshotProxy)
- this._snapshotProxy = snapshotProxy;
- this._didCompleteSnapshotTransfer();
- var worker = /** @type {WebInspector.HeapSnapshotWorkerProxy} */ (this._snapshotProxy.worker);
- this.isTemporary = false;
- worker.startCheckingForLongRunningCalls();
- this.notifySnapshotReceived();
- },
- notifySnapshotReceived: function()
- {
- this._profileType._snapshotReceived(this);
- },
- finishHeapSnapshot: function()
- {
- if (this._transferHandler) {
- this._transferHandler.finishTransfer();
- this._totalNumberOfChunks = this._transferHandler._totalNumberOfChunks;
- }
- },
- // Hook point for tests.
- _wasShown: function()
- {
- },
- /**
- * @override
- * @return {boolean}
- */
- canSaveToFile: function()
- {
- return !this.fromFile() && !!this._snapshotProxy && !this._receiver;
- },
- /**
- * @override
- */
- saveToFile: function()
- {
- var fileOutputStream = new WebInspector.FileOutputStream();
- function onOpen()
- {
- this._receiver = fileOutputStream;
- this._transferHandler = new WebInspector.SaveSnapshotHandler(this);
- HeapProfilerAgent.getHeapSnapshot(this.uid);
- }
- this._fileName = this._fileName || "Heap-" + new Date().toISO8601Compact() + this._profileType.fileExtension();
- fileOutputStream.open(this._fileName, onOpen.bind(this));
- },
- /**
- * @override
- * @param {File} file
- */
- loadFromFile: function(file)
- {
- this.title = file.name;
- this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
- this.sidebarElement.wait = true;
- this._setupWorker();
- var delegate = new WebInspector.HeapSnapshotLoadFromFileDelegate(this);
- var fileReader = this._createFileReader(file, delegate);
- fileReader.start(this._receiver);
- },
- _createFileReader: function(file, delegate)
- {
- return new WebInspector.ChunkedFileReader(file, 10000000, delegate);
- },
- __proto__: WebInspector.ProfileHeader.prototype
- }
- /**
- * @constructor
- * @param {WebInspector.HeapProfileHeader} header
- * @param {string} title
- */
- WebInspector.SnapshotTransferHandler = function(header, title)
- {
- this._numberOfChunks = 0;
- this._savedChunks = 0;
- this._header = header;
- this._totalNumberOfChunks = 0;
- this._title = title;
- }
- WebInspector.SnapshotTransferHandler.prototype = {
- /**
- * @param {string} chunk
- */
- transferChunk: function(chunk)
- {
- ++this._numberOfChunks;
- this._header._receiver.write(chunk, this._didTransferChunk.bind(this));
- },
- finishTransfer: function()
- {
- },
- _didTransferChunk: function()
- {
- this._updateProgress(++this._savedChunks, this._totalNumberOfChunks);
- },
- _updateProgress: function(value, total)
- {
- }
- }
- /**
- * @constructor
- * @param {WebInspector.HeapProfileHeader} header
- * @extends {WebInspector.SnapshotTransferHandler}
- */
- WebInspector.SaveSnapshotHandler = function(header)
- {
- WebInspector.SnapshotTransferHandler.call(this, header, "Saving\u2026 %d\%");
- this._totalNumberOfChunks = header._totalNumberOfChunks;
- this._updateProgress(0, this._totalNumberOfChunks);
- }
- WebInspector.SaveSnapshotHandler.prototype = {
- _updateProgress: function(value, total)
- {
- var percentValue = ((total ? (value / total) : 0) * 100).toFixed(0);
- this._header._updateSubtitle(WebInspector.UIString(this._title, percentValue));
- if (value === total) {
- this._header._receiver.close();
- this._header._didCompleteSnapshotTransfer();
- }
- },
- __proto__: WebInspector.SnapshotTransferHandler.prototype
- }
- /**
- * @constructor
- * @param {WebInspector.HeapProfileHeader} header
- * @extends {WebInspector.SnapshotTransferHandler}
- */
- WebInspector.BackendSnapshotLoader = function(header)
- {
- WebInspector.SnapshotTransferHandler.call(this, header, "Loading\u2026 %d\%");
- }
- WebInspector.BackendSnapshotLoader.prototype = {
- finishTransfer: function()
- {
- this._header._receiver.close(this._didFinishTransfer.bind(this));
- this._totalNumberOfChunks = this._numberOfChunks;
- },
- _didFinishTransfer: function()
- {
- console.assert(this._totalNumberOfChunks === this._savedChunks, "Not all chunks were transfered.");
- },
- __proto__: WebInspector.SnapshotTransferHandler.prototype
- }
- /**
- * @constructor
- * @implements {WebInspector.OutputStreamDelegate}
- */
- WebInspector.HeapSnapshotLoadFromFileDelegate = function(snapshotHeader)
- {
- this._snapshotHeader = snapshotHeader;
- }
- WebInspector.HeapSnapshotLoadFromFileDelegate.prototype = {
- onTransferStarted: function()
- {
- },
- /**
- * @param {WebInspector.ChunkedReader} reader
- */
- onChunkTransferred: function(reader)
- {
- },
- onTransferFinished: function()
- {
- },
- /**
- * @param {WebInspector.ChunkedReader} reader
- */
- onError: function (reader, e)
- {
- switch(e.target.error.code) {
- case e.target.error.NOT_FOUND_ERR:
- this._snapshotHeader._updateSubtitle(WebInspector.UIString("'%s' not found.", reader.fileName()));
- break;
- case e.target.error.NOT_READABLE_ERR:
- this._snapshotHeader._updateSubtitle(WebInspector.UIString("'%s' is not readable", reader.fileName()));
- break;
- case e.target.error.ABORT_ERR:
- break;
- default:
- this._snapshotHeader._updateSubtitle(WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code));
- }
- }
- }
- /**
- * @constructor
- * @extends {WebInspector.View}
- * @param {!WebInspector.HeapProfileHeader} heapProfileHeader
- */
- WebInspector.HeapTrackingOverviewGrid = function(heapProfileHeader)
- {
- WebInspector.View.call(this);
- this.registerRequiredCSS("flameChart.css");
- this.element.id = "heap-recording-view";
- this._overviewContainer = this.element.createChild("div", "overview-container");
- this._overviewGrid = new WebInspector.OverviewGrid("heap-recording");
- this._overviewCanvas = this._overviewContainer.createChild("canvas", "heap-recording-overview-canvas");
- this._overviewContainer.appendChild(this._overviewGrid.element);
- this._overviewCalculator = new WebInspector.HeapTrackingOverviewGrid.OverviewCalculator();
- this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this);
- this._profileSamples = heapProfileHeader._profileSamples || heapProfileHeader._profileType._profileSamples;
- if (heapProfileHeader.isTemporary) {
- this._profileType = heapProfileHeader._profileType;
- this._profileType.addEventListener(WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
- this._profileType.addEventListener(WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped, this._onStopTracking, this);
- }
- var timestamps = this._profileSamples.timestamps;
- var totalTime = this._profileSamples.totalTime;
- this._windowLeft = 0.0;
- this._windowRight = totalTime && timestamps.length ? (timestamps[timestamps.length - 1] - timestamps[0]) / totalTime : 1.0;
- this._overviewGrid.setWindow(this._windowLeft, this._windowRight);
- this._yScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale();
- this._xScale = new WebInspector.HeapTrackingOverviewGrid.SmoothScale();
- }
- WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged = "IdsRangeChanged";
- WebInspector.HeapTrackingOverviewGrid.prototype = {
- _onStopTracking: function(event)
- {
- this._profileType.removeEventListener(WebInspector.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
- this._profileType.removeEventListener(WebInspector.TrackingHeapSnapshotProfileType.TrackingStopped, this._onStopTracking, this);
- },
- _onHeapStatsUpdate: function(event)
- {
- this._profileSamples = event.data;
- this._scheduleUpdate();
- },
- /**
- * @param {number} width
- * @param {number} height
- */
- _drawOverviewCanvas: function(width, height)
- {
- if (!this._profileSamples)
- return;
- var profileSamples = this._profileSamples;
- var sizes = profileSamples.sizes;
- var topSizes = profileSamples.max;
- var timestamps = profileSamples.timestamps;
- var startTime = timestamps[0];
- var endTime = timestamps[timestamps.length - 1];
- var scaleFactor = this._xScale.nextScale(width / profileSamples.totalTime);
- var maxSize = 0;
- /**
- * @param {Array.<number>} sizes
- * @param {function(number, number):void} callback
- */
- function aggregateAndCall(sizes, callback)
- {
- var size = 0;
- var currentX = 0;
- for (var i = 1; i < timestamps.length; ++i) {
- var x = Math.floor((timestamps[i] - startTime) * scaleFactor);
- if (x !== currentX) {
- if (size)
- callback(currentX, size);
- size = 0;
- currentX = x;
- }
- size += sizes[i];
- }
- callback(currentX, size);
- }
- /**
- * @param {number} x
- * @param {number} size
- */
- function maxSizeCallback(x, size)
- {
- maxSize = Math.max(maxSize, size);
- }
- aggregateAndCall(sizes, maxSizeCallback);
- var yScaleFactor = this._yScale.nextScale(maxSize ? height / (maxSize * 1.1) : 0.0);
- this._overviewCanvas.width = width * window.devicePixelRatio;
- this._overviewCanvas.height = height * window.devicePixelRatio;
- this._overviewCanvas.style.width = width + "px";
- this._overviewCanvas.style.height = height + "px";
- var context = this._overviewCanvas.getContext("2d");
- context.scale(window.devicePixelRatio, window.devicePixelRatio);
- context.beginPath();
- context.lineWidth = 2;
- context.strokeStyle = "rgba(192, 192, 192, 0.6)";
- var currentX = (endTime - startTime) * scaleFactor;
- context.moveTo(currentX, height - 1);
- context.lineTo(currentX, 0);
- context.stroke();
- context.closePath();
- var gridY;
- var gridValue;
- var gridLabelHeight = 14;
- if (yScaleFactor) {
- const maxGridValue = (height - gridLabelHeight) / yScaleFactor;
- // The round value calculation is a bit tricky, because
- // it has a form k*10^n*1024^m, where k=[1,5], n=[0..3], m is an integer,
- // e.g. a round value 10KB is 10240 bytes.
- gridValue = Math.pow(1024, Math.floor(Math.log(maxGridValue) / Math.log(1024)));
- gridValue *= Math.pow(10, Math.floor(Math.log(maxGridValue / gridValue) / Math.log(10)));
- if (gridValue * 5 <= maxGridValue)
- gridValue *= 5;
- gridY = Math.round(height - gridValue * yScaleFactor - 0.5) + 0.5;
- context.beginPath();
- context.lineWidth = 1;
- context.strokeStyle = "rgba(0, 0, 0, 0.2)";
- context.moveTo(0, gridY);
- context.lineTo(width, gridY);
- context.stroke();
- context.closePath();
- }
- /**
- * @param {number} x
- * @param {number} size
- */
- function drawBarCallback(x, size)
- {
- context.moveTo(x, height - 1);
- context.lineTo(x, Math.round(height - size * yScaleFactor - 1));
- }
- context.beginPath();
- context.lineWidth = 2;
- context.strokeStyle = "rgba(192, 192, 192, 0.6)";
- aggregateAndCall(topSizes, drawBarCallback);
- context.stroke();
- context.closePath();
- context.beginPath();
- context.lineWidth = 2;
- context.strokeStyle = "rgba(0, 0, 192, 0.8)";
- aggregateAndCall(sizes, drawBarCallback);
- context.stroke();
- context.closePath();
- if (gridValue) {
- var label = Number.bytesToString(gridValue);
- var labelPadding = 4;
- var labelX = 0;
- var labelY = gridY - 0.5;
- var labelWidth = 2 * labelPadding + context.measureText(label).width;
- context.beginPath();
- context.textBaseline = "bottom";
- context.font = "10px " + window.getComputedStyle(this.element, null).getPropertyValue("font-family");
- context.fillStyle = "rgba(255, 255, 255, 0.75)";
- context.fillRect(labelX, labelY - gridLabelHeight, labelWidth, gridLabelHeight);
- context.fillStyle = "rgb(64, 64, 64)";
- context.fillText(label, labelX + labelPadding, labelY);
- context.fill();
- context.closePath();
- }
- },
- onResize: function()
- {
- this._updateOverviewCanvas = true;
- this._scheduleUpdate();
- },
- _onWindowChanged: function()
- {
- if (!this._updateGridTimerId)
- this._updateGridTimerId = setTimeout(this._updateGrid.bind(this), 10);
- },
- _scheduleUpdate: function()
- {
- if (this._updateTimerId)
- return;
- this._updateTimerId = setTimeout(this.update.bind(this), 10);
- },
- _updateBoundaries: function()
- {
- this._windowLeft = this._overviewGrid.windowLeft();
- this._windowRight = this._overviewGrid.windowRight();
- this._windowWidth = this._windowRight - this._windowLeft;
- },
- update: function()
- {
- this._updateTimerId = null;
- if (!this.isShowing())
- return;
- this._updateBoundaries();
- this._overviewCalculator._updateBoundaries(this);
- this._overviewGrid.updateDividers(this._overviewCalculator);
- this._drawOverviewCanvas(this._overviewContainer.clientWidth, this._overviewContainer.clientHeight - 20);
- },
- _updateGrid: function()
- {
- this._updateGridTimerId = 0;
- this._updateBoundaries();
- var ids = this._profileSamples.ids;
- var timestamps = this._profileSamples.timestamps;
- var sizes = this._profileSamples.sizes;
- var startTime = timestamps[0];
- var totalTime = this._profileSamples.totalTime;
- var timeLeft = startTime + totalTime * this._windowLeft;
- var timeRight = startTime + totalTime * this._windowRight;
- var minId = 0;
- var maxId = ids[ids.length - 1] + 1;
- var size = 0;
- for (var i = 0; i < timestamps.length; ++i) {
- if (!timestamps[i])
- continue;
- if (timestamps[i] > timeRight)
- break;
- maxId = ids[i];
- if (timestamps[i] < timeLeft) {
- minId = ids[i];
- continue;
- }
- size += sizes[i];
- }
- this.dispatchEventToListeners(WebInspector.HeapTrackingOverviewGrid.IdsRangeChanged, {minId: minId, maxId: maxId, size: size});
- },
- __proto__: WebInspector.View.prototype
- }
- /**
- * @constructor
- */
- WebInspector.HeapTrackingOverviewGrid.SmoothScale = function()
- {
- this._lastUpdate = 0;
- this._currentScale = 0.0;
- }
- WebInspector.HeapTrackingOverviewGrid.SmoothScale.prototype = {
- /**
- * @param {number} target
- * @return {number}
- */
- nextScale: function(target) {
- target = target || this._currentScale;
- if (this._currentScale) {
- var now = Date.now();
- var timeDeltaMs = now - this._lastUpdate;
- this._lastUpdate = now;
- var maxChangePerSec = 20;
- var maxChangePerDelta = Math.pow(maxChangePerSec, timeDeltaMs / 1000);
- var scaleChange = target / this._currentScale;
- this._currentScale *= Number.constrain(scaleChange, 1 / maxChangePerDelta, maxChangePerDelta);
- } else
- this._currentScale = target;
- return this._currentScale;
- }
- }
- /**
- * @constructor
- * @implements {WebInspector.TimelineGrid.Calculator}
- */
- WebInspector.HeapTrackingOverviewGrid.OverviewCalculator = function()
- {
- }
- WebInspector.HeapTrackingOverviewGrid.OverviewCalculator.prototype = {
- /**
- * @param {WebInspector.HeapTrackingOverviewGrid} chart
- */
- _updateBoundaries: function(chart)
- {
- this._minimumBoundaries = 0;
- this._maximumBoundaries = chart._profileSamples.totalTime;
- this._xScaleFactor = chart._overviewContainer.clientWidth / this._maximumBoundaries;
- },
- /**
- * @param {number} time
- */
- computePosition: function(time)
- {
- return (time - this._minimumBoundaries) * this._xScaleFactor;
- },
- formatTime: function(value)
- {
- return Number.secondsToString((value + this._minimumBoundaries) / 1000);
- },
- maximumBoundary: function()
- {
- return this._maximumBoundaries;
- },
- minimumBoundary: function()
- {
- return this._minimumBoundaries;
- },
- zeroTime: function()
- {
- return this._minimumBoundaries;
- },
- boundarySpan: function()
- {
- return this._maximumBoundaries - this._minimumBoundaries;
- }
- }
|