1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 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. 29 */ 30 31/** 32 * @fileoverview Provides communication interface to remote v8 profiler. 33 */ 34 35/** 36 * @constructor 37 */ 38devtools.ProfilerAgent = function() 39{ 40 RemoteProfilerAgent.didGetActiveProfilerModules = this._didGetActiveProfilerModules.bind(this); 41 RemoteProfilerAgent.didGetLogLines = this._didGetLogLines.bind(this); 42 43 /** 44 * Active profiler modules flags. 45 * @type {number} 46 */ 47 this._activeProfilerModules = devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE; 48 49 /** 50 * Interval for polling profiler state. 51 * @type {number} 52 */ 53 this._getActiveProfilerModulesInterval = null; 54 55 /** 56 * Profiler log position. 57 * @type {number} 58 */ 59 this._logPosition = 0; 60 61 /** 62 * Last requested log position. 63 * @type {number} 64 */ 65 this._lastRequestedLogPosition = -1; 66 67 /** 68 * Whether log contents retrieval must be forced next time. 69 * @type {boolean} 70 */ 71 this._forceGetLogLines = false; 72 73 /** 74 * Profiler processor instance. 75 * @type {devtools.profiler.Processor} 76 */ 77 this._profilerProcessor = new devtools.profiler.Processor(); 78}; 79 80 81/** 82 * A copy of enum from include/v8.h 83 * @enum {number} 84 */ 85devtools.ProfilerAgent.ProfilerModules = { 86 PROFILER_MODULE_NONE: 0, 87 PROFILER_MODULE_CPU: 1, 88 PROFILER_MODULE_HEAP_STATS: 1 << 1, 89 PROFILER_MODULE_JS_CONSTRUCTORS: 1 << 2, 90 PROFILER_MODULE_HEAP_SNAPSHOT: 1 << 16 91}; 92 93 94/** 95 * Sets up callbacks that deal with profiles processing. 96 */ 97devtools.ProfilerAgent.prototype.setupProfilerProcessorCallbacks = function() 98{ 99 // A temporary icon indicating that the profile is being processed. 100 var processingIcon = new WebInspector.SidebarTreeElement( 101 "profile-sidebar-tree-item", 102 WebInspector.UIString("Processing..."), 103 '', null, false); 104 var profilesSidebar = WebInspector.panels.profiles.getProfileType(WebInspector.CPUProfileType.TypeId).treeElement; 105 106 this._profilerProcessor.setCallbacks( 107 function onProfileProcessingStarted() { 108 // Set visually empty string. Subtitle hiding is done via styles 109 // manipulation which doesn't play well with dynamic append / removal. 110 processingIcon.subtitle = " "; 111 profilesSidebar.appendChild(processingIcon); 112 }, 113 function onProfileProcessingStatus(ticksCount) { 114 processingIcon.subtitle = WebInspector.UIString("%d ticks processed", ticksCount); 115 }, 116 function onProfileProcessingFinished(profile) { 117 profilesSidebar.removeChild(processingIcon); 118 profile.typeId = WebInspector.CPUProfileType.TypeId; 119 InspectorBackend.addFullProfile(profile); 120 WebInspector.addProfileHeader(profile); 121 // If no profile is currently shown, show the new one. 122 var profilesPanel = WebInspector.panels.profiles; 123 if (!profilesPanel.visibleView) { 124 profilesPanel.showProfile(profile); 125 } 126 } 127 ); 128}; 129 130 131/** 132 * Initializes profiling state. 133 */ 134devtools.ProfilerAgent.prototype.initializeProfiling = function() 135{ 136 this.setupProfilerProcessorCallbacks(); 137 this._forceGetLogLines = true; 138 this._getActiveProfilerModulesInterval = setInterval(function() { RemoteProfilerAgent.getActiveProfilerModules(); }, 1000); 139}; 140 141 142/** 143 * Requests the next chunk of log lines. 144 * @param {boolean} immediately Do not postpone the request. 145 * @private 146 */ 147devtools.ProfilerAgent.prototype._getNextLogLines = function(immediately) 148{ 149 if (this._lastRequestedLogPosition == this._logPosition) 150 return; 151 var pos = this._lastRequestedLogPosition = this._logPosition; 152 if (immediately) 153 RemoteProfilerAgent.getLogLines(pos); 154 else 155 setTimeout(function() { RemoteProfilerAgent.getLogLines(pos); }, 500); 156}; 157 158 159/** 160 * Starts profiling. 161 * @param {number} modules List of modules to enable. 162 */ 163devtools.ProfilerAgent.prototype.startProfiling = function(modules) 164{ 165 var cmd = new devtools.DebugCommand("profile", { 166 "modules": modules, 167 "command": "resume"}); 168 devtools.DebuggerAgent.sendCommand_(cmd); 169 RemoteDebuggerAgent.processDebugCommands(); 170 if (modules & devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_HEAP_SNAPSHOT) { 171 // Active modules will not change, instead, a snapshot will be logged. 172 this._getNextLogLines(); 173 } 174}; 175 176 177/** 178 * Stops profiling. 179 */ 180devtools.ProfilerAgent.prototype.stopProfiling = function(modules) 181{ 182 var cmd = new devtools.DebugCommand("profile", { 183 "modules": modules, 184 "command": "pause"}); 185 devtools.DebuggerAgent.sendCommand_(cmd); 186 RemoteDebuggerAgent.processDebugCommands(); 187}; 188 189 190/** 191 * Handles current profiler status. 192 * @param {number} modules List of active (started) modules. 193 */ 194devtools.ProfilerAgent.prototype._didGetActiveProfilerModules = function(modules) 195{ 196 var profModules = devtools.ProfilerAgent.ProfilerModules; 197 var profModuleNone = profModules.PROFILER_MODULE_NONE; 198 if (this._forceGetLogLines || (modules !== profModuleNone && this._activeProfilerModules === profModuleNone)) { 199 this._forceGetLogLines = false; 200 // Start to query log data. 201 this._getNextLogLines(true); 202 } 203 this._activeProfilerModules = modules; 204 // Update buttons. 205 WebInspector.setRecordingProfile(modules & profModules.PROFILER_MODULE_CPU); 206}; 207 208 209/** 210 * Handles a portion of a profiler log retrieved by getLogLines call. 211 * @param {number} pos Current position in log. 212 * @param {string} log A portion of profiler log. 213 */ 214devtools.ProfilerAgent.prototype._didGetLogLines = function(pos, log) 215{ 216 this._logPosition = pos; 217 if (log.length > 0) 218 this._profilerProcessor.processLogChunk(log); 219 else { 220 // Allow re-reading from the last position. 221 this._lastRequestedLogPosition = this._logPosition - 1; 222 if (this._activeProfilerModules === devtools.ProfilerAgent.ProfilerModules.PROFILER_MODULE_NONE) 223 // No new data and profiling is stopped---suspend log reading. 224 return; 225 } 226 this._getNextLogLines(); 227}; 228