| /* |
| * Copyright (C) 2008 Apple 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: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. 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. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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 |
| * @implements {WebInspector.Searchable} |
| * @extends {WebInspector.VBox} |
| * @param {!WebInspector.CPUProfileHeader} profileHeader |
| */ |
| WebInspector.CPUProfileView = function(profileHeader) |
| { |
| WebInspector.VBox.call(this); |
| this.element.classList.add("cpu-profile-view"); |
| |
| this._searchableView = new WebInspector.SearchableView(this); |
| this._searchableView.setPlaceholder(WebInspector.UIString("Find by cost (>50ms), name or file")); |
| this._searchableView.show(this.element); |
| |
| this._viewType = WebInspector.settings.createSetting("cpuProfilerView", WebInspector.CPUProfileView._TypeHeavy); |
| |
| var columns = []; |
| columns.push({id: "self", title: WebInspector.UIString("Self"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true}); |
| columns.push({id: "total", title: WebInspector.UIString("Total"), width: "120px", sortable: true}); |
| columns.push({id: "function", title: WebInspector.UIString("Function"), disclosure: true, sortable: true}); |
| |
| this.dataGrid = new WebInspector.DataGrid(columns); |
| this.dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortProfile, this); |
| |
| this.viewSelectComboBox = new WebInspector.ToolbarComboBox(this._changeView.bind(this)); |
| |
| var options = {}; |
| options[WebInspector.CPUProfileView._TypeFlame] = this.viewSelectComboBox.createOption(WebInspector.UIString("Chart"), "", WebInspector.CPUProfileView._TypeFlame); |
| options[WebInspector.CPUProfileView._TypeHeavy] = this.viewSelectComboBox.createOption(WebInspector.UIString("Heavy (Bottom Up)"), "", WebInspector.CPUProfileView._TypeHeavy); |
| options[WebInspector.CPUProfileView._TypeTree] = this.viewSelectComboBox.createOption(WebInspector.UIString("Tree (Top Down)"), "", WebInspector.CPUProfileView._TypeTree); |
| |
| var optionName = this._viewType.get() || WebInspector.CPUProfileView._TypeFlame; |
| var option = options[optionName] || options[WebInspector.CPUProfileView._TypeFlame]; |
| this.viewSelectComboBox.select(option); |
| |
| this.focusButton = new WebInspector.ToolbarButton(WebInspector.UIString("Focus selected function"), "visibility-toolbar-item"); |
| this.focusButton.setEnabled(false); |
| this.focusButton.addEventListener("click", this._focusClicked, this); |
| |
| this.excludeButton = new WebInspector.ToolbarButton(WebInspector.UIString("Exclude selected function"), "delete-toolbar-item"); |
| this.excludeButton.setEnabled(false); |
| this.excludeButton.addEventListener("click", this._excludeClicked, this); |
| |
| this.resetButton = new WebInspector.ToolbarButton(WebInspector.UIString("Restore all functions"), "refresh-toolbar-item"); |
| this.resetButton.setEnabled(false); |
| this.resetButton.addEventListener("click", this._resetClicked, this); |
| |
| this._profileHeader = profileHeader; |
| this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultFormatter(30)); |
| |
| this.profile = new WebInspector.CPUProfileDataModel(profileHeader._profile || profileHeader.protocolProfile()); |
| |
| this._changeView(); |
| if (this._flameChart) |
| this._flameChart.update(); |
| } |
| |
| WebInspector.CPUProfileView._TypeFlame = "Flame"; |
| WebInspector.CPUProfileView._TypeTree = "Tree"; |
| WebInspector.CPUProfileView._TypeHeavy = "Heavy"; |
| |
| /** |
| * @interface |
| */ |
| WebInspector.CPUProfileView.Searchable = function() |
| { |
| } |
| |
| WebInspector.CPUProfileView.Searchable.prototype = { |
| jumpToNextSearchResult: function() {}, |
| jumpToPreviousSearchResult: function() {}, |
| searchCanceled: function() {}, |
| /** |
| * @param {!WebInspector.SearchableView.SearchConfig} searchConfig |
| * @param {boolean} shouldJump |
| * @param {boolean=} jumpBackwards |
| * @return {number} |
| */ |
| performSearch: function(searchConfig, shouldJump, jumpBackwards) {}, |
| /** |
| * @return {number} |
| */ |
| currentSearchResultIndex: function() {} |
| } |
| |
| WebInspector.CPUProfileView.prototype = { |
| focus: function() |
| { |
| if (this._flameChart) |
| this._flameChart.focus(); |
| else |
| WebInspector.Widget.prototype.focus.call(this); |
| }, |
| |
| /** |
| * @return {?WebInspector.Target} |
| */ |
| target: function() |
| { |
| return this._profileHeader.target(); |
| }, |
| |
| /** |
| * @param {number} timeLeft |
| * @param {number} timeRight |
| */ |
| selectRange: function(timeLeft, timeRight) |
| { |
| if (!this._flameChart) |
| return; |
| this._flameChart.selectRange(timeLeft, timeRight); |
| }, |
| |
| /** |
| * @return {!Array.<!WebInspector.ToolbarItem>} |
| */ |
| toolbarItems: function() |
| { |
| return [this.viewSelectComboBox, this.focusButton, this.excludeButton, this.resetButton]; |
| }, |
| |
| /** |
| * @return {!WebInspector.ProfileDataGridTree} |
| */ |
| _getBottomUpProfileDataGridTree: function() |
| { |
| if (!this._bottomUpProfileDataGridTree) |
| this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, /** @type {!ProfilerAgent.CPUProfileNode} */ (this.profile.profileHead)); |
| return this._bottomUpProfileDataGridTree; |
| }, |
| |
| /** |
| * @return {!WebInspector.ProfileDataGridTree} |
| */ |
| _getTopDownProfileDataGridTree: function() |
| { |
| if (!this._topDownProfileDataGridTree) |
| this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, /** @type {!ProfilerAgent.CPUProfileNode} */ (this.profile.profileHead)); |
| return this._topDownProfileDataGridTree; |
| }, |
| |
| willHide: function() |
| { |
| this._currentSearchResultIndex = -1; |
| }, |
| |
| refresh: function() |
| { |
| var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.selectedNode.profileNode : null; |
| |
| this.dataGrid.rootNode().removeChildren(); |
| |
| var children = this.profileDataGridTree.children; |
| var count = children.length; |
| |
| for (var index = 0; index < count; ++index) |
| this.dataGrid.rootNode().appendChild(children[index]); |
| |
| if (selectedProfileNode) |
| selectedProfileNode.selected = true; |
| }, |
| |
| refreshVisibleData: function() |
| { |
| var child = this.dataGrid.rootNode().children[0]; |
| while (child) { |
| child.refresh(); |
| child = child.traverseNextNode(false, null, true); |
| } |
| }, |
| |
| /** |
| * @return {!WebInspector.SearchableView} |
| */ |
| searchableView: function() |
| { |
| return this._searchableView; |
| }, |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| supportsCaseSensitiveSearch: function() |
| { |
| return true; |
| }, |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| supportsRegexSearch: function() |
| { |
| return false; |
| }, |
| |
| /** |
| * @override |
| */ |
| searchCanceled: function() |
| { |
| this._searchableElement.searchCanceled(); |
| }, |
| |
| /** |
| * @override |
| * @param {!WebInspector.SearchableView.SearchConfig} searchConfig |
| * @param {boolean} shouldJump |
| * @param {boolean=} jumpBackwards |
| */ |
| performSearch: function(searchConfig, shouldJump, jumpBackwards) |
| { |
| var matchesCount = this._searchableElement.performSearch(searchConfig, shouldJump, jumpBackwards); |
| this._searchableView.updateSearchMatchesCount(matchesCount); |
| this._searchableView.updateCurrentMatchIndex(this._searchableElement.currentSearchResultIndex()); |
| }, |
| |
| /** |
| * @override |
| */ |
| jumpToNextSearchResult: function() |
| { |
| this._searchableElement.jumpToNextSearchResult(); |
| this._searchableView.updateCurrentMatchIndex(this._searchableElement.currentSearchResultIndex()); |
| }, |
| |
| /** |
| * @override |
| */ |
| jumpToPreviousSearchResult: function() |
| { |
| this._searchableElement.jumpToPreviousSearchResult(); |
| this._searchableView.updateCurrentMatchIndex(this._searchableElement.currentSearchResultIndex()); |
| }, |
| |
| _ensureFlameChartCreated: function() |
| { |
| if (this._flameChart) |
| return; |
| this._dataProvider = new WebInspector.CPUFlameChartDataProvider(this.profile, this._profileHeader.target()); |
| this._flameChart = new WebInspector.CPUProfileFlameChart(this._dataProvider); |
| this._flameChart.addEventListener(WebInspector.FlameChart.Events.EntrySelected, this._onEntrySelected.bind(this)); |
| }, |
| |
| /** |
| * @param {!WebInspector.Event} event |
| */ |
| _onEntrySelected: function(event) |
| { |
| var entryIndex = event.data; |
| var node = this._dataProvider._entryNodes[entryIndex]; |
| var debuggerModel = this._profileHeader._debuggerModel; |
| if (!node || !node.scriptId || !debuggerModel) |
| return; |
| var script = debuggerModel.scriptForId(node.scriptId); |
| if (!script) |
| return; |
| var location = /** @type {!WebInspector.DebuggerModel.Location} */ (debuggerModel.createRawLocation(script, node.lineNumber, node.columnNumber)); |
| WebInspector.Revealer.reveal(WebInspector.debuggerWorkspaceBinding.rawLocationToUILocation(location)); |
| }, |
| |
| _changeView: function() |
| { |
| if (!this.profile) |
| return; |
| |
| this._searchableView.closeSearch(); |
| |
| if (this._visibleView) |
| this._visibleView.detach(); |
| |
| this._viewType.set(this.viewSelectComboBox.selectedOption().value); |
| switch (this._viewType.get()) { |
| case WebInspector.CPUProfileView._TypeFlame: |
| this._ensureFlameChartCreated(); |
| this._visibleView = this._flameChart; |
| this._searchableElement = this._flameChart; |
| break; |
| case WebInspector.CPUProfileView._TypeTree: |
| this.profileDataGridTree = this._getTopDownProfileDataGridTree(); |
| this._sortProfile(); |
| this._visibleView = this.dataGrid; |
| this._searchableElement = this.profileDataGridTree; |
| break; |
| case WebInspector.CPUProfileView._TypeHeavy: |
| this.profileDataGridTree = this._getBottomUpProfileDataGridTree(); |
| this._sortProfile(); |
| this._visibleView = this.dataGrid; |
| this._searchableElement = this.profileDataGridTree; |
| break; |
| } |
| |
| var isFlame = this._viewType.get() === WebInspector.CPUProfileView._TypeFlame; |
| this.focusButton.setVisible(!isFlame); |
| this.excludeButton.setVisible(!isFlame); |
| this.resetButton.setVisible(!isFlame); |
| |
| this._visibleView.show(this._searchableView.element); |
| }, |
| |
| _focusClicked: function(event) |
| { |
| if (!this.dataGrid.selectedNode) |
| return; |
| |
| this.resetButton.setEnabled(true); |
| this.profileDataGridTree.focus(this.dataGrid.selectedNode); |
| this.refresh(); |
| this.refreshVisibleData(); |
| }, |
| |
| _excludeClicked: function(event) |
| { |
| var selectedNode = this.dataGrid.selectedNode; |
| |
| if (!selectedNode) |
| return; |
| |
| selectedNode.deselect(); |
| |
| this.resetButton.setEnabled(true); |
| this.profileDataGridTree.exclude(selectedNode); |
| this.refresh(); |
| this.refreshVisibleData(); |
| }, |
| |
| _resetClicked: function(event) |
| { |
| this.resetButton.setEnabled(false); |
| this.profileDataGridTree.restore(); |
| this._linkifier.reset(); |
| this.refresh(); |
| this.refreshVisibleData(); |
| }, |
| |
| _dataGridNodeSelected: function(node) |
| { |
| this.focusButton.setEnabled(true); |
| this.excludeButton.setEnabled(true); |
| }, |
| |
| _dataGridNodeDeselected: function(node) |
| { |
| this.focusButton.setEnabled(false); |
| this.excludeButton.setEnabled(false); |
| }, |
| |
| _sortProfile: function() |
| { |
| var sortAscending = this.dataGrid.isSortOrderAscending(); |
| var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier(); |
| var sortProperty = { |
| "self": "selfTime", |
| "total": "totalTime", |
| "function": "functionName" |
| }[sortColumnIdentifier]; |
| |
| this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending)); |
| |
| this.refresh(); |
| }, |
| |
| __proto__: WebInspector.VBox.prototype |
| } |
| |
| /** |
| * @constructor |
| * @extends {WebInspector.ProfileType} |
| */ |
| WebInspector.CPUProfileType = function() |
| { |
| WebInspector.ProfileType.call(this, WebInspector.CPUProfileType.TypeId, WebInspector.UIString("Collect JavaScript CPU Profile")); |
| this._recording = false; |
| |
| this._nextAnonymousConsoleProfileNumber = 1; |
| this._anonymousConsoleProfileIdToTitle = {}; |
| |
| WebInspector.CPUProfileType.instance = this; |
| WebInspector.targetManager.addModelListener(WebInspector.CPUProfilerModel, WebInspector.CPUProfilerModel.EventTypes.ConsoleProfileStarted, this._consoleProfileStarted, this); |
| WebInspector.targetManager.addModelListener(WebInspector.CPUProfilerModel, WebInspector.CPUProfilerModel.EventTypes.ConsoleProfileFinished, this._consoleProfileFinished, this); |
| } |
| |
| WebInspector.CPUProfileType.TypeId = "CPU"; |
| |
| WebInspector.CPUProfileType.prototype = { |
| /** |
| * @override |
| * @return {string} |
| */ |
| fileExtension: function() |
| { |
| return ".cpuprofile"; |
| }, |
| |
| get buttonTooltip() |
| { |
| return this._recording ? WebInspector.UIString("Stop CPU profiling") : WebInspector.UIString("Start CPU profiling"); |
| }, |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| buttonClicked: function() |
| { |
| if (this._recording) { |
| this.stopRecordingProfile(); |
| return false; |
| } else { |
| this.startRecordingProfile(); |
| return true; |
| } |
| }, |
| |
| get treeItemTitle() |
| { |
| return WebInspector.UIString("CPU PROFILES"); |
| }, |
| |
| get description() |
| { |
| return WebInspector.UIString("CPU profiles show where the execution time is spent in your page's JavaScript functions."); |
| }, |
| |
| /** |
| * @param {!WebInspector.Event} event |
| */ |
| _consoleProfileStarted: function(event) |
| { |
| var protocolId = /** @type {string} */ (event.data.protocolId); |
| var scriptLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (event.data.scriptLocation); |
| var resolvedTitle = /** @type {string|undefined} */ (event.data.title); |
| if (!resolvedTitle) { |
| resolvedTitle = WebInspector.UIString("Profile %s", this._nextAnonymousConsoleProfileNumber++); |
| this._anonymousConsoleProfileIdToTitle[protocolId] = resolvedTitle; |
| } |
| this._addMessageToConsole(WebInspector.ConsoleMessage.MessageType.Profile, scriptLocation, WebInspector.UIString("Profile '%s' started.", resolvedTitle)); |
| }, |
| |
| /** |
| * @param {!WebInspector.Event} event |
| */ |
| _consoleProfileFinished: function(event) |
| { |
| var protocolId = /** @type {string} */ (event.data.protocolId); |
| var scriptLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (event.data.scriptLocation); |
| var cpuProfile = /** @type {!ProfilerAgent.CPUProfile} */ (event.data.cpuProfile); |
| var resolvedTitle = /** @type {string|undefined} */ (event.data.title); |
| if (typeof resolvedTitle === "undefined") { |
| resolvedTitle = this._anonymousConsoleProfileIdToTitle[protocolId]; |
| delete this._anonymousConsoleProfileIdToTitle[protocolId]; |
| } |
| |
| var profile = new WebInspector.CPUProfileHeader(scriptLocation.target(), this, resolvedTitle); |
| profile.setProtocolProfile(cpuProfile); |
| this.addProfile(profile); |
| this._addMessageToConsole(WebInspector.ConsoleMessage.MessageType.ProfileEnd, scriptLocation, WebInspector.UIString("Profile '%s' finished.", resolvedTitle)); |
| }, |
| |
| /** |
| * @param {string} type |
| * @param {!WebInspector.DebuggerModel.Location} scriptLocation |
| * @param {string} messageText |
| */ |
| _addMessageToConsole: function(type, scriptLocation, messageText) |
| { |
| var script = scriptLocation.script(); |
| var target = scriptLocation.target(); |
| var message = new WebInspector.ConsoleMessage( |
| target, |
| WebInspector.ConsoleMessage.MessageSource.ConsoleAPI, |
| WebInspector.ConsoleMessage.MessageLevel.Debug, |
| messageText, |
| type, |
| undefined, |
| undefined, |
| undefined, |
| undefined, |
| undefined, |
| [{ |
| functionName: "", |
| scriptId: scriptLocation.scriptId, |
| url: script ? script.contentURL() : "", |
| lineNumber: scriptLocation.lineNumber, |
| columnNumber: scriptLocation.columnNumber || 0 |
| }]); |
| |
| target.consoleModel.addMessage(message); |
| }, |
| |
| startRecordingProfile: function() |
| { |
| var target = WebInspector.context.flavor(WebInspector.Target); |
| if (this._profileBeingRecorded || !target) |
| return; |
| var profile = new WebInspector.CPUProfileHeader(target, this); |
| this.setProfileBeingRecorded(profile); |
| this.addProfile(profile); |
| profile.updateStatus(WebInspector.UIString("Recording\u2026")); |
| this._recording = true; |
| target.cpuProfilerModel.startRecording(); |
| }, |
| |
| stopRecordingProfile: function() |
| { |
| this._recording = false; |
| if (!this._profileBeingRecorded || !this._profileBeingRecorded.target()) |
| return; |
| |
| /** |
| * @param {?ProfilerAgent.CPUProfile} profile |
| * @this {WebInspector.CPUProfileType} |
| */ |
| function didStopProfiling(profile) |
| { |
| if (!this._profileBeingRecorded) |
| return; |
| console.assert(profile); |
| this._profileBeingRecorded.setProtocolProfile(profile); |
| this._profileBeingRecorded.updateStatus(""); |
| var recordedProfile = this._profileBeingRecorded; |
| this.setProfileBeingRecorded(null); |
| this.dispatchEventToListeners(WebInspector.ProfileType.Events.ProfileComplete, recordedProfile); |
| } |
| this._profileBeingRecorded.target().cpuProfilerModel.stopRecording().then(didStopProfiling.bind(this)); |
| }, |
| |
| /** |
| * @override |
| * @param {string} title |
| * @return {!WebInspector.ProfileHeader} |
| */ |
| createProfileLoadedFromFile: function(title) |
| { |
| return new WebInspector.CPUProfileHeader(null, this, title); |
| }, |
| |
| /** |
| * @override |
| */ |
| profileBeingRecordedRemoved: function() |
| { |
| this.stopRecordingProfile(); |
| }, |
| |
| __proto__: WebInspector.ProfileType.prototype |
| } |
| |
| /** |
| * @constructor |
| * @extends {WebInspector.ProfileHeader} |
| * @implements {WebInspector.OutputStream} |
| * @implements {WebInspector.OutputStreamDelegate} |
| * @param {?WebInspector.Target} target |
| * @param {!WebInspector.CPUProfileType} type |
| * @param {string=} title |
| */ |
| WebInspector.CPUProfileHeader = function(target, type, title) |
| { |
| WebInspector.ProfileHeader.call(this, target, type, title || WebInspector.UIString("Profile %d", type.nextProfileUid())); |
| this._debuggerModel = WebInspector.DebuggerModel.fromTarget(target); |
| this._tempFile = null; |
| } |
| |
| WebInspector.CPUProfileHeader.prototype = { |
| /** |
| * @override |
| */ |
| onTransferStarted: function() |
| { |
| this._jsonifiedProfile = ""; |
| this.updateStatus(WebInspector.UIString("Loading\u2026 %s", Number.bytesToString(this._jsonifiedProfile.length)), true); |
| }, |
| |
| /** |
| * @override |
| * @param {!WebInspector.ChunkedReader} reader |
| */ |
| onChunkTransferred: function(reader) |
| { |
| this.updateStatus(WebInspector.UIString("Loading\u2026 %d%%", Number.bytesToString(this._jsonifiedProfile.length))); |
| }, |
| |
| /** |
| * @override |
| */ |
| onTransferFinished: function() |
| { |
| this.updateStatus(WebInspector.UIString("Parsing\u2026"), true); |
| this._profile = JSON.parse(this._jsonifiedProfile); |
| this._jsonifiedProfile = null; |
| this.updateStatus(WebInspector.UIString("Loaded"), false); |
| |
| if (this._profileType.profileBeingRecorded() === this) |
| this._profileType.setProfileBeingRecorded(null); |
| }, |
| |
| /** |
| * @override |
| * @param {!WebInspector.ChunkedReader} reader |
| * @param {!Event} e |
| */ |
| onError: function(reader, e) |
| { |
| var subtitle; |
| switch(e.target.error.code) { |
| case e.target.error.NOT_FOUND_ERR: |
| subtitle = WebInspector.UIString("'%s' not found.", reader.fileName()); |
| break; |
| case e.target.error.NOT_READABLE_ERR: |
| subtitle = WebInspector.UIString("'%s' is not readable", reader.fileName()); |
| break; |
| case e.target.error.ABORT_ERR: |
| return; |
| default: |
| subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code); |
| } |
| this.updateStatus(subtitle); |
| }, |
| |
| /** |
| * @override |
| * @param {string} text |
| */ |
| write: function(text) |
| { |
| this._jsonifiedProfile += text; |
| }, |
| |
| /** |
| * @override |
| */ |
| close: function() { }, |
| |
| /** |
| * @override |
| */ |
| dispose: function() |
| { |
| this.removeTempFile(); |
| }, |
| |
| /** |
| * @override |
| * @param {!WebInspector.ProfileType.DataDisplayDelegate} panel |
| * @return {!WebInspector.ProfileSidebarTreeElement} |
| */ |
| createSidebarTreeElement: function(panel) |
| { |
| return new WebInspector.ProfileSidebarTreeElement(panel, this, "profile-sidebar-tree-item"); |
| }, |
| |
| /** |
| * @override |
| * @return {!WebInspector.CPUProfileView} |
| */ |
| createView: function() |
| { |
| return new WebInspector.CPUProfileView(this); |
| }, |
| |
| /** |
| * @override |
| * @return {boolean} |
| */ |
| canSaveToFile: function() |
| { |
| return !this.fromFile() && this._protocolProfile; |
| }, |
| |
| saveToFile: function() |
| { |
| var fileOutputStream = new WebInspector.FileOutputStream(); |
| |
| /** |
| * @param {boolean} accepted |
| * @this {WebInspector.CPUProfileHeader} |
| */ |
| function onOpenForSave(accepted) |
| { |
| if (!accepted) |
| return; |
| function didRead(data) |
| { |
| if (data) |
| fileOutputStream.write(data, fileOutputStream.close.bind(fileOutputStream)); |
| else |
| fileOutputStream.close(); |
| } |
| if (this._failedToCreateTempFile) { |
| WebInspector.console.error("Failed to open temp file with heap snapshot"); |
| fileOutputStream.close(); |
| } else if (this._tempFile) { |
| this._tempFile.read(didRead); |
| } else { |
| this._onTempFileReady = onOpenForSave.bind(this, accepted); |
| } |
| } |
| this._fileName = this._fileName || "CPU-" + new Date().toISO8601Compact() + this._profileType.fileExtension(); |
| fileOutputStream.open(this._fileName, onOpenForSave.bind(this)); |
| }, |
| |
| /** |
| * @override |
| * @param {!File} file |
| */ |
| loadFromFile: function(file) |
| { |
| this.updateStatus(WebInspector.UIString("Loading\u2026"), true); |
| var fileReader = new WebInspector.ChunkedFileReader(file, 10000000, this); |
| fileReader.start(this); |
| }, |
| |
| |
| /** |
| * @return {?ProfilerAgent.CPUProfile} |
| */ |
| protocolProfile: function() |
| { |
| return this._protocolProfile; |
| }, |
| |
| /** |
| * @param {!ProfilerAgent.CPUProfile} cpuProfile |
| */ |
| setProtocolProfile: function(cpuProfile) |
| { |
| this._protocolProfile = cpuProfile; |
| this._saveProfileDataToTempFile(cpuProfile); |
| if (this.canSaveToFile()) |
| this.dispatchEventToListeners(WebInspector.ProfileHeader.Events.ProfileReceived); |
| }, |
| |
| /** |
| * @param {!ProfilerAgent.CPUProfile} data |
| */ |
| _saveProfileDataToTempFile: function(data) |
| { |
| var serializedData = JSON.stringify(data); |
| |
| /** |
| * @this {WebInspector.CPUProfileHeader} |
| */ |
| function didCreateTempFile(tempFile) |
| { |
| this._writeToTempFile(tempFile, serializedData); |
| } |
| WebInspector.TempFile.create("cpu-profiler", String(this.uid)) |
| .then(didCreateTempFile.bind(this)); |
| }, |
| |
| /** |
| * @param {?WebInspector.TempFile} tempFile |
| * @param {string} serializedData |
| */ |
| _writeToTempFile: function(tempFile, serializedData) |
| { |
| this._tempFile = tempFile; |
| if (!tempFile) { |
| this._failedToCreateTempFile = true; |
| this._notifyTempFileReady(); |
| return; |
| } |
| /** |
| * @param {number} fileSize |
| * @this {WebInspector.CPUProfileHeader} |
| */ |
| function didWriteToTempFile(fileSize) |
| { |
| if (!fileSize) |
| this._failedToCreateTempFile = true; |
| tempFile.finishWriting(); |
| this._notifyTempFileReady(); |
| } |
| tempFile.write([serializedData], didWriteToTempFile.bind(this)); |
| }, |
| |
| _notifyTempFileReady: function() |
| { |
| if (this._onTempFileReady) { |
| this._onTempFileReady(); |
| this._onTempFileReady = null; |
| } |
| }, |
| |
| __proto__: WebInspector.ProfileHeader.prototype |
| } |