| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview Profiler processor is used to process log file produced | 6 * @fileoverview Profiler processor is used to process log file produced |
| 7 * by V8 and produce an internal profile representation which is used | 7 * by V8 and produce an internal profile representation which is used |
| 8 * for building profile views in 'Profiles' tab. | 8 * for building profile views in 'Profiles' tab. |
| 9 */ | 9 */ |
| 10 goog.provide('devtools.profiler.Processor'); | 10 goog.provide('devtools.profiler.Processor'); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 /** | 29 /** |
| 30 * @override | 30 * @override |
| 31 */ | 31 */ |
| 32 devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { | 32 devtools.profiler.JsProfile.prototype.skipThisFunction = function(name) { |
| 33 return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name); | 33 return !devtools.profiler.JsProfile.JS_FUNC_RE.test(name); |
| 34 }; | 34 }; |
| 35 | 35 |
| 36 | 36 |
| 37 /** | 37 /** |
| 38 * Profiler processor. Consumes profiler log and builds profile views. | 38 * Profiler processor. Consumes profiler log and builds profile views. |
| 39 * |
| 40 * @param {function(devtools.profiler.ProfileView)} newProfileCallback Callback |
| 41 * that receives a new processed profile. |
| 39 * @constructor | 42 * @constructor |
| 40 */ | 43 */ |
| 41 devtools.profiler.Processor = function() { | 44 devtools.profiler.Processor = function(newProfileCallback) { |
| 42 /** | 45 /** |
| 43 * Current profile. | 46 * |
| 47 */ |
| 48 this.newProfileCallback_ = newProfileCallback; |
| 49 |
| 50 /** |
| 51 * Profiles array. |
| 52 * @type {Array<devtools.profiler.JsProfile>} |
| 53 */ |
| 54 this.profiles_ = []; |
| 55 |
| 56 /** |
| 57 * The current profile. |
| 44 * @type {devtools.profiler.JsProfile} | 58 * @type {devtools.profiler.JsProfile} |
| 45 */ | 59 */ |
| 46 this.profile_ = new devtools.profiler.JsProfile(); | 60 this.currentProfile_ = null; |
| 47 | 61 |
| 48 /** | 62 /** |
| 49 * Builder of profile views. | 63 * Builder of profile views. |
| 50 * @type {devtools.profiler.ViewBuilder} | 64 * @type {devtools.profiler.ViewBuilder} |
| 51 */ | 65 */ |
| 52 this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); | 66 this.viewBuilder_ = new devtools.profiler.ViewBuilder(1); |
| 53 | 67 |
| 54 /** | 68 /** |
| 55 * Next profile id. | 69 * Next profile id. |
| 56 * @type {number} | 70 * @type {number} |
| 57 */ | 71 */ |
| 58 this.profileId_ = 1; | 72 this.profileId_ = 1; |
| 59 }; | 73 }; |
| 60 | 74 |
| 61 | 75 |
| 62 /** | 76 /** |
| 63 * A dispatch table for V8 profiler event log records. | 77 * A dispatch table for V8 profiler event log records. |
| 64 * @private | 78 * @private |
| 65 */ | 79 */ |
| 66 devtools.profiler.Processor.RecordsDispatch_ = { | 80 devtools.profiler.Processor.RecordsDispatch_ = { |
| 67 'code-creation': { parsers: [null, parseInt, parseInt, null], | 81 'code-creation': { parsers: [null, parseInt, parseInt, null], |
| 68 processor: 'processCodeCreation_' }, | 82 processor: 'processCodeCreation_', needsProfile: true }, |
| 69 'code-move': { parsers: [parseInt, parseInt], | 83 'code-move': { parsers: [parseInt, parseInt], |
| 70 processor: 'processCodeMove_' }, | 84 processor: 'processCodeMove_', needsProfile: true }, |
| 71 'code-delete': { parsers: [parseInt], processor: 'processCodeDelete_' }, | 85 'code-delete': { parsers: [parseInt], |
| 86 processor: 'processCodeDelete_', needsProfile: true }, |
| 72 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], | 87 'tick': { parsers: [parseInt, parseInt, parseInt, 'var-args'], |
| 73 processor: 'processTick_' }, | 88 processor: 'processTick_', needsProfile: true }, |
| 89 'profiler': { parsers: [null], processor: 'processProfiler_', |
| 90 needsProfile: false }, |
| 74 // Not used in DevTools Profiler. | 91 // Not used in DevTools Profiler. |
| 75 'profiler': null, | |
| 76 'shared-library': null, | 92 'shared-library': null, |
| 77 // Obsolete row types. | 93 // Obsolete row types. |
| 78 'code-allocate': null, | 94 'code-allocate': null, |
| 79 'begin-code-region': null, | 95 'begin-code-region': null, |
| 80 'end-code-region': null | 96 'end-code-region': null |
| 81 }; | 97 }; |
| 82 | 98 |
| 83 | 99 |
| 84 /** | 100 /** |
| 85 * Processes a portion of V8 profiler event log. | 101 * Processes a portion of V8 profiler event log. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 * @private | 138 * @private |
| 123 */ | 139 */ |
| 124 devtools.profiler.Processor.prototype.dispatchLogRow_ = function(fields) { | 140 devtools.profiler.Processor.prototype.dispatchLogRow_ = function(fields) { |
| 125 // Obtain the dispatch. | 141 // Obtain the dispatch. |
| 126 var command = fields[0]; | 142 var command = fields[0]; |
| 127 if (!(command in devtools.profiler.Processor.RecordsDispatch_)) { | 143 if (!(command in devtools.profiler.Processor.RecordsDispatch_)) { |
| 128 throw new Error('unknown command: ' + command); | 144 throw new Error('unknown command: ' + command); |
| 129 } | 145 } |
| 130 var dispatch = devtools.profiler.Processor.RecordsDispatch_[command]; | 146 var dispatch = devtools.profiler.Processor.RecordsDispatch_[command]; |
| 131 | 147 |
| 132 if (dispatch === null) { | 148 if (dispatch === null || |
| 149 (dispatch.needsProfile && this.currentProfile_ == null)) { |
| 133 return; | 150 return; |
| 134 } | 151 } |
| 135 | 152 |
| 136 // Parse fields. | 153 // Parse fields. |
| 137 var parsedFields = []; | 154 var parsedFields = []; |
| 138 for (var i = 0; i < dispatch.parsers.length; ++i) { | 155 for (var i = 0; i < dispatch.parsers.length; ++i) { |
| 139 var parser = dispatch.parsers[i]; | 156 var parser = dispatch.parsers[i]; |
| 140 if (parser === null) { | 157 if (parser === null) { |
| 141 parsedFields.push(fields[1 + i]); | 158 parsedFields.push(fields[1 + i]); |
| 142 } else if (typeof parser == 'function') { | 159 } else if (typeof parser == 'function') { |
| 143 parsedFields.push(parser(fields[1 + i])); | 160 parsedFields.push(parser(fields[1 + i])); |
| 144 } else { | 161 } else { |
| 145 // var-args | 162 // var-args |
| 146 parsedFields.push(fields.slice(1 + i)); | 163 parsedFields.push(fields.slice(1 + i)); |
| 147 break; | 164 break; |
| 148 } | 165 } |
| 149 } | 166 } |
| 150 | 167 |
| 151 // Run the processor. | 168 // Run the processor. |
| 152 this[dispatch.processor].apply(this, parsedFields); | 169 this[dispatch.processor].apply(this, parsedFields); |
| 153 }; | 170 }; |
| 154 | 171 |
| 155 | 172 |
| 173 devtools.profiler.Processor.prototype.processProfiler_ = function(state) { |
| 174 switch (state) { |
| 175 case "resume": |
| 176 this.currentProfile_ = new devtools.profiler.JsProfile(); |
| 177 this.profiles_.push(this.currentProfile_); |
| 178 break; |
| 179 case "pause": |
| 180 if (this.currentProfile_ != null) { |
| 181 this.newProfileCallback_(this.createProfileForView()); |
| 182 this.currentProfile_ = null; |
| 183 } |
| 184 break; |
| 185 // These events are valid but are not used. |
| 186 case "begin": break; |
| 187 case "end": break; |
| 188 default: |
| 189 throw new Error("unknown profiler state: " + state); |
| 190 } |
| 191 }; |
| 192 |
| 193 |
| 156 devtools.profiler.Processor.prototype.processCodeCreation_ = function( | 194 devtools.profiler.Processor.prototype.processCodeCreation_ = function( |
| 157 type, start, size, name) { | 195 type, start, size, name) { |
| 158 this.profile_.addCode(type, name, start, size); | 196 this.currentProfile_.addCode(type, name, start, size); |
| 159 }; | 197 }; |
| 160 | 198 |
| 161 | 199 |
| 162 devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { | 200 devtools.profiler.Processor.prototype.processCodeMove_ = function(from, to) { |
| 163 this.profile_.moveCode(from, to); | 201 this.currentProfile_.moveCode(from, to); |
| 164 }; | 202 }; |
| 165 | 203 |
| 166 | 204 |
| 167 devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { | 205 devtools.profiler.Processor.prototype.processCodeDelete_ = function(start) { |
| 168 this.profile_.deleteCode(start); | 206 this.currentProfile_.deleteCode(start); |
| 169 }; | 207 }; |
| 170 | 208 |
| 171 | 209 |
| 172 devtools.profiler.Processor.prototype.processTick_ = function( | 210 devtools.profiler.Processor.prototype.processTick_ = function( |
| 173 pc, sp, vmState, stack) { | 211 pc, sp, vmState, stack) { |
| 174 var fullStack = [pc]; | 212 var fullStack = [pc]; |
| 175 for (var i = 0, n = stack.length; i < n; ++i) { | 213 for (var i = 0, n = stack.length; i < n; ++i) { |
| 176 var frame = stack[i]; | 214 var frame = stack[i]; |
| 177 // Leave only numbers starting with 0x. Filter possible 'overflow' string. | 215 // Leave only numbers starting with 0x. Filter possible 'overflow' string. |
| 178 if (frame.charAt(0) == '0') { | 216 if (frame.charAt(0) == '0') { |
| 179 fullStack.push(parseInt(frame, 16)); | 217 fullStack.push(parseInt(frame, 16)); |
| 180 } | 218 } |
| 181 } | 219 } |
| 182 this.profile_.recordTick(fullStack); | 220 this.currentProfile_.recordTick(fullStack); |
| 183 }; | 221 }; |
| 184 | 222 |
| 185 | 223 |
| 186 /** | 224 /** |
| 187 * Creates a profile for further displaying in ProfileView. | 225 * Creates a profile for further displaying in ProfileView. |
| 188 */ | 226 */ |
| 189 devtools.profiler.Processor.prototype.createProfileForView = function() { | 227 devtools.profiler.Processor.prototype.createProfileForView = function() { |
| 190 var profile = new devtools.profiler.ProfileView(); | 228 var profile = new devtools.profiler.ProfileView(); |
| 191 profile.uid = this.profileId_++; | 229 profile.uid = this.profileId_++; |
| 192 profile.title = UserInitiatedProfileName + '.' + profile.uid; | 230 profile.title = UserInitiatedProfileName + '.' + profile.uid; |
| 193 // A trick to cope with ProfileView.bottomUpProfileDataGridTree and | 231 // A trick to cope with ProfileView.bottomUpProfileDataGridTree and |
| 194 // ProfileView.topDownProfileDataGridTree behavior. | 232 // ProfileView.topDownProfileDataGridTree behavior. |
| 195 profile.head = profile; | 233 profile.head = profile; |
| 196 profile.heavyProfile = this.viewBuilder_.buildView( | 234 profile.heavyProfile = this.viewBuilder_.buildView( |
| 197 this.profile_.getBottomUpProfile(), true); | 235 this.currentProfile_.getBottomUpProfile(), true); |
| 198 profile.treeProfile = this.viewBuilder_.buildView( | 236 profile.treeProfile = this.viewBuilder_.buildView( |
| 199 this.profile_.getTopDownProfile()); | 237 this.currentProfile_.getTopDownProfile()); |
| 200 return profile; | 238 return profile; |
| 201 }; | 239 }; |
| OLD | NEW |