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 |