Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(977)

Side by Side Diff: tools/profile.js

Issue 6614010: [Isolates] Merge 6700:7030 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/oprofile/start ('k') | tools/profile_view.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 28
29 // Initlialize namespaces
30 var devtools = devtools || {};
31 devtools.profiler = devtools.profiler || {};
32
33
34 /** 29 /**
35 * Creates a profile object for processing profiling-related events 30 * Creates a profile object for processing profiling-related events
36 * and calculating function execution times. 31 * and calculating function execution times.
37 * 32 *
38 * @constructor 33 * @constructor
39 */ 34 */
40 devtools.profiler.Profile = function() { 35 function Profile() {
41 this.codeMap_ = new devtools.profiler.CodeMap(); 36 this.codeMap_ = new CodeMap();
42 this.topDownTree_ = new devtools.profiler.CallTree(); 37 this.topDownTree_ = new CallTree();
43 this.bottomUpTree_ = new devtools.profiler.CallTree(); 38 this.bottomUpTree_ = new CallTree();
44 }; 39 };
45 40
46 /**
47 * Version of profiler log.
48 */
49 devtools.profiler.Profile.VERSION = 2;
50
51 41
52 /** 42 /**
53 * Returns whether a function with the specified name must be skipped. 43 * Returns whether a function with the specified name must be skipped.
54 * Should be overriden by subclasses. 44 * Should be overriden by subclasses.
55 * 45 *
56 * @param {string} name Function name. 46 * @param {string} name Function name.
57 */ 47 */
58 devtools.profiler.Profile.prototype.skipThisFunction = function(name) { 48 Profile.prototype.skipThisFunction = function(name) {
59 return false; 49 return false;
60 }; 50 };
61 51
62 52
63 /** 53 /**
64 * Enum for profiler operations that involve looking up existing 54 * Enum for profiler operations that involve looking up existing
65 * code entries. 55 * code entries.
66 * 56 *
67 * @enum {number} 57 * @enum {number}
68 */ 58 */
69 devtools.profiler.Profile.Operation = { 59 Profile.Operation = {
70 MOVE: 0, 60 MOVE: 0,
71 DELETE: 1, 61 DELETE: 1,
72 TICK: 2 62 TICK: 2
73 }; 63 };
74 64
75 65
76 /** 66 /**
67 * Enum for code state regarding its dynamic optimization.
68 *
69 * @enum {number}
70 */
71 Profile.CodeState = {
72 COMPILED: 0,
73 OPTIMIZABLE: 1,
74 OPTIMIZED: 2
75 };
76
77
78 /**
77 * Called whenever the specified operation has failed finding a function 79 * Called whenever the specified operation has failed finding a function
78 * containing the specified address. Should be overriden by subclasses. 80 * containing the specified address. Should be overriden by subclasses.
79 * See the devtools.profiler.Profile.Operation enum for the list of 81 * See the Profile.Operation enum for the list of
80 * possible operations. 82 * possible operations.
81 * 83 *
82 * @param {number} operation Operation. 84 * @param {number} operation Operation.
83 * @param {number} addr Address of the unknown code. 85 * @param {number} addr Address of the unknown code.
84 * @param {number} opt_stackPos If an unknown address is encountered 86 * @param {number} opt_stackPos If an unknown address is encountered
85 * during stack strace processing, specifies a position of the frame 87 * during stack strace processing, specifies a position of the frame
86 * containing the address. 88 * containing the address.
87 */ 89 */
88 devtools.profiler.Profile.prototype.handleUnknownCode = function( 90 Profile.prototype.handleUnknownCode = function(
89 operation, addr, opt_stackPos) { 91 operation, addr, opt_stackPos) {
90 }; 92 };
91 93
92 94
93 /** 95 /**
94 * Registers a library. 96 * Registers a library.
95 * 97 *
96 * @param {string} name Code entry name. 98 * @param {string} name Code entry name.
97 * @param {number} startAddr Starting address. 99 * @param {number} startAddr Starting address.
98 * @param {number} endAddr Ending address. 100 * @param {number} endAddr Ending address.
99 */ 101 */
100 devtools.profiler.Profile.prototype.addLibrary = function( 102 Profile.prototype.addLibrary = function(
101 name, startAddr, endAddr) { 103 name, startAddr, endAddr) {
102 var entry = new devtools.profiler.CodeMap.CodeEntry( 104 var entry = new CodeMap.CodeEntry(
103 endAddr - startAddr, name); 105 endAddr - startAddr, name);
104 this.codeMap_.addLibrary(startAddr, entry); 106 this.codeMap_.addLibrary(startAddr, entry);
105 return entry; 107 return entry;
106 }; 108 };
107 109
108 110
109 /** 111 /**
110 * Registers statically compiled code entry. 112 * Registers statically compiled code entry.
111 * 113 *
112 * @param {string} name Code entry name. 114 * @param {string} name Code entry name.
113 * @param {number} startAddr Starting address. 115 * @param {number} startAddr Starting address.
114 * @param {number} endAddr Ending address. 116 * @param {number} endAddr Ending address.
115 */ 117 */
116 devtools.profiler.Profile.prototype.addStaticCode = function( 118 Profile.prototype.addStaticCode = function(
117 name, startAddr, endAddr) { 119 name, startAddr, endAddr) {
118 var entry = new devtools.profiler.CodeMap.CodeEntry( 120 var entry = new CodeMap.CodeEntry(
119 endAddr - startAddr, name); 121 endAddr - startAddr, name);
120 this.codeMap_.addStaticCode(startAddr, entry); 122 this.codeMap_.addStaticCode(startAddr, entry);
121 return entry; 123 return entry;
122 }; 124 };
123 125
124 126
125 /** 127 /**
126 * Registers dynamic (JIT-compiled) code entry. 128 * Registers dynamic (JIT-compiled) code entry.
127 * 129 *
128 * @param {string} type Code entry type. 130 * @param {string} type Code entry type.
129 * @param {string} name Code entry name. 131 * @param {string} name Code entry name.
130 * @param {number} start Starting address. 132 * @param {number} start Starting address.
131 * @param {number} size Code entry size. 133 * @param {number} size Code entry size.
132 */ 134 */
133 devtools.profiler.Profile.prototype.addCode = function( 135 Profile.prototype.addCode = function(
134 type, name, start, size) { 136 type, name, start, size) {
135 var entry = new devtools.profiler.Profile.DynamicCodeEntry(size, type, name); 137 var entry = new Profile.DynamicCodeEntry(size, type, name);
136 this.codeMap_.addCode(start, entry); 138 this.codeMap_.addCode(start, entry);
137 return entry; 139 return entry;
138 }; 140 };
139 141
140 142
141 /** 143 /**
142 * Creates an alias entry for a code entry. 144 * Registers dynamic (JIT-compiled) code entry.
143 * 145 *
144 * @param {number} aliasAddr Alias address. 146 * @param {string} type Code entry type.
145 * @param {number} addr Code entry address. 147 * @param {string} name Code entry name.
148 * @param {number} start Starting address.
149 * @param {number} size Code entry size.
150 * @param {number} funcAddr Shared function object address.
151 * @param {Profile.CodeState} state Optimization state.
146 */ 152 */
147 devtools.profiler.Profile.prototype.addCodeAlias = function( 153 Profile.prototype.addFuncCode = function(
148 aliasAddr, addr) { 154 type, name, start, size, funcAddr, state) {
149 var entry = this.codeMap_.findDynamicEntryByStartAddress(addr); 155 // As code and functions are in the same address space,
150 if (entry) { 156 // it is safe to put them in a single code map.
151 this.codeMap_.addCode(aliasAddr, entry); 157 var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr);
158 if (!func) {
159 func = new Profile.FunctionEntry(name);
160 this.codeMap_.addCode(funcAddr, func);
161 } else if (func.name !== name) {
162 // Function object has been overwritten with a new one.
163 func.name = name;
152 } 164 }
165 var entry = new Profile.DynamicFuncCodeEntry(size, type, func, state);
166 this.codeMap_.addCode(start, entry);
167 return entry;
153 }; 168 };
154 169
155 170
156 /** 171 /**
157 * Reports about moving of a dynamic code entry. 172 * Reports about moving of a dynamic code entry.
158 * 173 *
159 * @param {number} from Current code entry address. 174 * @param {number} from Current code entry address.
160 * @param {number} to New code entry address. 175 * @param {number} to New code entry address.
161 */ 176 */
162 devtools.profiler.Profile.prototype.moveCode = function(from, to) { 177 Profile.prototype.moveCode = function(from, to) {
163 try { 178 try {
164 this.codeMap_.moveCode(from, to); 179 this.codeMap_.moveCode(from, to);
165 } catch (e) { 180 } catch (e) {
166 this.handleUnknownCode(devtools.profiler.Profile.Operation.MOVE, from); 181 this.handleUnknownCode(Profile.Operation.MOVE, from);
167 } 182 }
168 }; 183 };
169 184
170 185
171 /** 186 /**
172 * Reports about deletion of a dynamic code entry. 187 * Reports about deletion of a dynamic code entry.
173 * 188 *
174 * @param {number} start Starting address. 189 * @param {number} start Starting address.
175 */ 190 */
176 devtools.profiler.Profile.prototype.deleteCode = function(start) { 191 Profile.prototype.deleteCode = function(start) {
177 try { 192 try {
178 this.codeMap_.deleteCode(start); 193 this.codeMap_.deleteCode(start);
179 } catch (e) { 194 } catch (e) {
180 this.handleUnknownCode(devtools.profiler.Profile.Operation.DELETE, start); 195 this.handleUnknownCode(Profile.Operation.DELETE, start);
181 } 196 }
182 }; 197 };
183 198
184 199
185 /** 200 /**
186 * Reports about moving of a dynamic code entry. 201 * Reports about moving of a dynamic code entry.
187 * 202 *
188 * @param {number} from Current code entry address. 203 * @param {number} from Current code entry address.
189 * @param {number} to New code entry address. 204 * @param {number} to New code entry address.
190 */ 205 */
191 devtools.profiler.Profile.prototype.safeMoveDynamicCode = function(from, to) { 206 Profile.prototype.moveFunc = function(from, to) {
192 if (this.codeMap_.findDynamicEntryByStartAddress(from)) { 207 if (this.codeMap_.findDynamicEntryByStartAddress(from)) {
193 this.codeMap_.moveCode(from, to); 208 this.codeMap_.moveCode(from, to);
194 } 209 }
195 }; 210 };
196 211
197 212
198 /** 213 /**
199 * Reports about deletion of a dynamic code entry.
200 *
201 * @param {number} start Starting address.
202 */
203 devtools.profiler.Profile.prototype.safeDeleteDynamicCode = function(start) {
204 if (this.codeMap_.findDynamicEntryByStartAddress(start)) {
205 this.codeMap_.deleteCode(start);
206 }
207 };
208
209
210 /**
211 * Retrieves a code entry by an address. 214 * Retrieves a code entry by an address.
212 * 215 *
213 * @param {number} addr Entry address. 216 * @param {number} addr Entry address.
214 */ 217 */
215 devtools.profiler.Profile.prototype.findEntry = function(addr) { 218 Profile.prototype.findEntry = function(addr) {
216 return this.codeMap_.findEntry(addr); 219 return this.codeMap_.findEntry(addr);
217 }; 220 };
218 221
219 222
220 /** 223 /**
221 * Records a tick event. Stack must contain a sequence of 224 * Records a tick event. Stack must contain a sequence of
222 * addresses starting with the program counter value. 225 * addresses starting with the program counter value.
223 * 226 *
224 * @param {Array<number>} stack Stack sample. 227 * @param {Array<number>} stack Stack sample.
225 */ 228 */
226 devtools.profiler.Profile.prototype.recordTick = function(stack) { 229 Profile.prototype.recordTick = function(stack) {
227 var processedStack = this.resolveAndFilterFuncs_(stack); 230 var processedStack = this.resolveAndFilterFuncs_(stack);
228 this.bottomUpTree_.addPath(processedStack); 231 this.bottomUpTree_.addPath(processedStack);
229 processedStack.reverse(); 232 processedStack.reverse();
230 this.topDownTree_.addPath(processedStack); 233 this.topDownTree_.addPath(processedStack);
231 }; 234 };
232 235
233 236
234 /** 237 /**
235 * Translates addresses into function names and filters unneeded 238 * Translates addresses into function names and filters unneeded
236 * functions. 239 * functions.
237 * 240 *
238 * @param {Array<number>} stack Stack sample. 241 * @param {Array<number>} stack Stack sample.
239 */ 242 */
240 devtools.profiler.Profile.prototype.resolveAndFilterFuncs_ = function(stack) { 243 Profile.prototype.resolveAndFilterFuncs_ = function(stack) {
241 var result = []; 244 var result = [];
242 for (var i = 0; i < stack.length; ++i) { 245 for (var i = 0; i < stack.length; ++i) {
243 var entry = this.codeMap_.findEntry(stack[i]); 246 var entry = this.codeMap_.findEntry(stack[i]);
244 if (entry) { 247 if (entry) {
245 var name = entry.getName(); 248 var name = entry.getName();
246 if (!this.skipThisFunction(name)) { 249 if (!this.skipThisFunction(name)) {
247 result.push(name); 250 result.push(name);
248 } 251 }
249 } else { 252 } else {
250 this.handleUnknownCode( 253 this.handleUnknownCode(
251 devtools.profiler.Profile.Operation.TICK, stack[i], i); 254 Profile.Operation.TICK, stack[i], i);
252 } 255 }
253 } 256 }
254 return result; 257 return result;
255 }; 258 };
256 259
257 260
258 /** 261 /**
259 * Performs a BF traversal of the top down call graph. 262 * Performs a BF traversal of the top down call graph.
260 * 263 *
261 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 264 * @param {function(CallTree.Node)} f Visitor function.
262 */ 265 */
263 devtools.profiler.Profile.prototype.traverseTopDownTree = function(f) { 266 Profile.prototype.traverseTopDownTree = function(f) {
264 this.topDownTree_.traverse(f); 267 this.topDownTree_.traverse(f);
265 }; 268 };
266 269
267 270
268 /** 271 /**
269 * Performs a BF traversal of the bottom up call graph. 272 * Performs a BF traversal of the bottom up call graph.
270 * 273 *
271 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 274 * @param {function(CallTree.Node)} f Visitor function.
272 */ 275 */
273 devtools.profiler.Profile.prototype.traverseBottomUpTree = function(f) { 276 Profile.prototype.traverseBottomUpTree = function(f) {
274 this.bottomUpTree_.traverse(f); 277 this.bottomUpTree_.traverse(f);
275 }; 278 };
276 279
277 280
278 /** 281 /**
279 * Calculates a top down profile for a node with the specified label. 282 * Calculates a top down profile for a node with the specified label.
280 * If no name specified, returns the whole top down calls tree. 283 * If no name specified, returns the whole top down calls tree.
281 * 284 *
282 * @param {string} opt_label Node label. 285 * @param {string} opt_label Node label.
283 */ 286 */
284 devtools.profiler.Profile.prototype.getTopDownProfile = function(opt_label) { 287 Profile.prototype.getTopDownProfile = function(opt_label) {
285 return this.getTreeProfile_(this.topDownTree_, opt_label); 288 return this.getTreeProfile_(this.topDownTree_, opt_label);
286 }; 289 };
287 290
288 291
289 /** 292 /**
290 * Calculates a bottom up profile for a node with the specified label. 293 * Calculates a bottom up profile for a node with the specified label.
291 * If no name specified, returns the whole bottom up calls tree. 294 * If no name specified, returns the whole bottom up calls tree.
292 * 295 *
293 * @param {string} opt_label Node label. 296 * @param {string} opt_label Node label.
294 */ 297 */
295 devtools.profiler.Profile.prototype.getBottomUpProfile = function(opt_label) { 298 Profile.prototype.getBottomUpProfile = function(opt_label) {
296 return this.getTreeProfile_(this.bottomUpTree_, opt_label); 299 return this.getTreeProfile_(this.bottomUpTree_, opt_label);
297 }; 300 };
298 301
299 302
300 /** 303 /**
301 * Helper function for calculating a tree profile. 304 * Helper function for calculating a tree profile.
302 * 305 *
303 * @param {devtools.profiler.Profile.CallTree} tree Call tree. 306 * @param {Profile.CallTree} tree Call tree.
304 * @param {string} opt_label Node label. 307 * @param {string} opt_label Node label.
305 */ 308 */
306 devtools.profiler.Profile.prototype.getTreeProfile_ = function(tree, opt_label) { 309 Profile.prototype.getTreeProfile_ = function(tree, opt_label) {
307 if (!opt_label) { 310 if (!opt_label) {
308 tree.computeTotalWeights(); 311 tree.computeTotalWeights();
309 return tree; 312 return tree;
310 } else { 313 } else {
311 var subTree = tree.cloneSubtree(opt_label); 314 var subTree = tree.cloneSubtree(opt_label);
312 subTree.computeTotalWeights(); 315 subTree.computeTotalWeights();
313 return subTree; 316 return subTree;
314 } 317 }
315 }; 318 };
316 319
317 320
318 /** 321 /**
319 * Calculates a flat profile of callees starting from a node with 322 * Calculates a flat profile of callees starting from a node with
320 * the specified label. If no name specified, starts from the root. 323 * the specified label. If no name specified, starts from the root.
321 * 324 *
322 * @param {string} opt_label Starting node label. 325 * @param {string} opt_label Starting node label.
323 */ 326 */
324 devtools.profiler.Profile.prototype.getFlatProfile = function(opt_label) { 327 Profile.prototype.getFlatProfile = function(opt_label) {
325 var counters = new devtools.profiler.CallTree(); 328 var counters = new CallTree();
326 var rootLabel = opt_label || devtools.profiler.CallTree.ROOT_NODE_LABEL; 329 var rootLabel = opt_label || CallTree.ROOT_NODE_LABEL;
327 var precs = {}; 330 var precs = {};
328 precs[rootLabel] = 0; 331 precs[rootLabel] = 0;
329 var root = counters.findOrAddChild(rootLabel); 332 var root = counters.findOrAddChild(rootLabel);
330 333
331 this.topDownTree_.computeTotalWeights(); 334 this.topDownTree_.computeTotalWeights();
332 this.topDownTree_.traverseInDepth( 335 this.topDownTree_.traverseInDepth(
333 function onEnter(node) { 336 function onEnter(node) {
334 if (!(node.label in precs)) { 337 if (!(node.label in precs)) {
335 precs[node.label] = 0; 338 precs[node.label] = 0;
336 } 339 }
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 374
372 375
373 /** 376 /**
374 * Creates a dynamic code entry. 377 * Creates a dynamic code entry.
375 * 378 *
376 * @param {number} size Code size. 379 * @param {number} size Code size.
377 * @param {string} type Code type. 380 * @param {string} type Code type.
378 * @param {string} name Function name. 381 * @param {string} name Function name.
379 * @constructor 382 * @constructor
380 */ 383 */
381 devtools.profiler.Profile.DynamicCodeEntry = function(size, type, name) { 384 Profile.DynamicCodeEntry = function(size, type, name) {
382 devtools.profiler.CodeMap.CodeEntry.call(this, size, name); 385 CodeMap.CodeEntry.call(this, size, name);
383 this.type = type; 386 this.type = type;
384 }; 387 };
385 388
386 389
387 /** 390 /**
388 * Returns node name. 391 * Returns node name.
389 */ 392 */
390 devtools.profiler.Profile.DynamicCodeEntry.prototype.getName = function() { 393 Profile.DynamicCodeEntry.prototype.getName = function() {
394 return this.type + ': ' + this.name;
395 };
396
397
398 /**
399 * Returns raw node name (without type decoration).
400 */
401 Profile.DynamicCodeEntry.prototype.getRawName = function() {
402 return this.name;
403 };
404
405
406 Profile.DynamicCodeEntry.prototype.isJSFunction = function() {
407 return false;
408 };
409
410
411 /**
412 * Creates a dynamic code entry.
413 *
414 * @param {number} size Code size.
415 * @param {string} type Code type.
416 * @param {Profile.FunctionEntry} func Shared function entry.
417 * @param {Profile.CodeState} state Code optimization state.
418 * @constructor
419 */
420 Profile.DynamicFuncCodeEntry = function(size, type, func, state) {
421 CodeMap.CodeEntry.call(this, size);
422 this.type = type;
423 this.func = func;
424 this.state = state;
425 };
426
427 Profile.DynamicFuncCodeEntry.STATE_PREFIX = ["", "~", "*"];
428
429 /**
430 * Returns node name.
431 */
432 Profile.DynamicFuncCodeEntry.prototype.getName = function() {
433 var name = this.func.getName();
434 return this.type + ': ' + Profile.DynamicFuncCodeEntry.STATE_PREFIX[this.state ] + name;
435 };
436
437
438 /**
439 * Returns raw node name (without type decoration).
440 */
441 Profile.DynamicFuncCodeEntry.prototype.getRawName = function() {
442 return this.func.getName();
443 };
444
445
446 Profile.DynamicFuncCodeEntry.prototype.isJSFunction = function() {
447 return true;
448 };
449
450
451 /**
452 * Creates a shared function object entry.
453 *
454 * @param {string} name Function name.
455 * @constructor
456 */
457 Profile.FunctionEntry = function(name) {
458 CodeMap.CodeEntry.call(this, 0, name);
459 };
460
461
462 /**
463 * Returns node name.
464 */
465 Profile.FunctionEntry.prototype.getName = function() {
391 var name = this.name; 466 var name = this.name;
392 if (name.length == 0) { 467 if (name.length == 0) {
393 name = '<anonymous>'; 468 name = '<anonymous>';
394 } else if (name.charAt(0) == ' ') { 469 } else if (name.charAt(0) == ' ') {
395 // An anonymous function with location: " aaa.js:10". 470 // An anonymous function with location: " aaa.js:10".
396 name = '<anonymous>' + name; 471 name = '<anonymous>' + name;
397 } 472 }
398 return this.type + ': ' + name; 473 return name;
399 };
400
401
402 /**
403 * Returns raw node name (without type decoration).
404 */
405 devtools.profiler.Profile.DynamicCodeEntry.prototype.getRawName = function() {
406 return this.name;
407 };
408
409
410 devtools.profiler.Profile.DynamicCodeEntry.prototype.isJSFunction = function() {
411 return this.type == "Function" ||
412 this.type == "LazyCompile" ||
413 this.type == "Script";
414 }; 474 };
415 475
416 476
417 /** 477 /**
418 * Constructs a call graph. 478 * Constructs a call graph.
419 * 479 *
420 * @constructor 480 * @constructor
421 */ 481 */
422 devtools.profiler.CallTree = function() { 482 function CallTree() {
423 this.root_ = new devtools.profiler.CallTree.Node( 483 this.root_ = new CallTree.Node(
424 devtools.profiler.CallTree.ROOT_NODE_LABEL); 484 CallTree.ROOT_NODE_LABEL);
425 }; 485 };
426 486
427 487
428 /** 488 /**
429 * The label of the root node. 489 * The label of the root node.
430 */ 490 */
431 devtools.profiler.CallTree.ROOT_NODE_LABEL = ''; 491 CallTree.ROOT_NODE_LABEL = '';
432 492
433 493
434 /** 494 /**
435 * @private 495 * @private
436 */ 496 */
437 devtools.profiler.CallTree.prototype.totalsComputed_ = false; 497 CallTree.prototype.totalsComputed_ = false;
438 498
439 499
440 /** 500 /**
441 * Returns the tree root. 501 * Returns the tree root.
442 */ 502 */
443 devtools.profiler.CallTree.prototype.getRoot = function() { 503 CallTree.prototype.getRoot = function() {
444 return this.root_; 504 return this.root_;
445 }; 505 };
446 506
447 507
448 /** 508 /**
449 * Adds the specified call path, constructing nodes as necessary. 509 * Adds the specified call path, constructing nodes as necessary.
450 * 510 *
451 * @param {Array<string>} path Call path. 511 * @param {Array<string>} path Call path.
452 */ 512 */
453 devtools.profiler.CallTree.prototype.addPath = function(path) { 513 CallTree.prototype.addPath = function(path) {
454 if (path.length == 0) { 514 if (path.length == 0) {
455 return; 515 return;
456 } 516 }
457 var curr = this.root_; 517 var curr = this.root_;
458 for (var i = 0; i < path.length; ++i) { 518 for (var i = 0; i < path.length; ++i) {
459 curr = curr.findOrAddChild(path[i]); 519 curr = curr.findOrAddChild(path[i]);
460 } 520 }
461 curr.selfWeight++; 521 curr.selfWeight++;
462 this.totalsComputed_ = false; 522 this.totalsComputed_ = false;
463 }; 523 };
464 524
465 525
466 /** 526 /**
467 * Finds an immediate child of the specified parent with the specified 527 * Finds an immediate child of the specified parent with the specified
468 * label, creates a child node if necessary. If a parent node isn't 528 * label, creates a child node if necessary. If a parent node isn't
469 * specified, uses tree root. 529 * specified, uses tree root.
470 * 530 *
471 * @param {string} label Child node label. 531 * @param {string} label Child node label.
472 */ 532 */
473 devtools.profiler.CallTree.prototype.findOrAddChild = function(label) { 533 CallTree.prototype.findOrAddChild = function(label) {
474 return this.root_.findOrAddChild(label); 534 return this.root_.findOrAddChild(label);
475 }; 535 };
476 536
477 537
478 /** 538 /**
479 * Creates a subtree by cloning and merging all subtrees rooted at nodes 539 * Creates a subtree by cloning and merging all subtrees rooted at nodes
480 * with a given label. E.g. cloning the following call tree on label 'A' 540 * with a given label. E.g. cloning the following call tree on label 'A'
481 * will give the following result: 541 * will give the following result:
482 * 542 *
483 * <A>--<B> <B> 543 * <A>--<B> <B>
484 * / / 544 * / /
485 * <root> == clone on 'A' ==> <root>--<A> 545 * <root> == clone on 'A' ==> <root>--<A>
486 * \ \ 546 * \ \
487 * <C>--<A>--<D> <D> 547 * <C>--<A>--<D> <D>
488 * 548 *
489 * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the 549 * And <A>'s selfWeight will be the sum of selfWeights of <A>'s from the
490 * source call tree. 550 * source call tree.
491 * 551 *
492 * @param {string} label The label of the new root node. 552 * @param {string} label The label of the new root node.
493 */ 553 */
494 devtools.profiler.CallTree.prototype.cloneSubtree = function(label) { 554 CallTree.prototype.cloneSubtree = function(label) {
495 var subTree = new devtools.profiler.CallTree(); 555 var subTree = new CallTree();
496 this.traverse(function(node, parent) { 556 this.traverse(function(node, parent) {
497 if (!parent && node.label != label) { 557 if (!parent && node.label != label) {
498 return null; 558 return null;
499 } 559 }
500 var child = (parent ? parent : subTree).findOrAddChild(node.label); 560 var child = (parent ? parent : subTree).findOrAddChild(node.label);
501 child.selfWeight += node.selfWeight; 561 child.selfWeight += node.selfWeight;
502 return child; 562 return child;
503 }); 563 });
504 return subTree; 564 return subTree;
505 }; 565 };
506 566
507 567
508 /** 568 /**
509 * Computes total weights in the call graph. 569 * Computes total weights in the call graph.
510 */ 570 */
511 devtools.profiler.CallTree.prototype.computeTotalWeights = function() { 571 CallTree.prototype.computeTotalWeights = function() {
512 if (this.totalsComputed_) { 572 if (this.totalsComputed_) {
513 return; 573 return;
514 } 574 }
515 this.root_.computeTotalWeight(); 575 this.root_.computeTotalWeight();
516 this.totalsComputed_ = true; 576 this.totalsComputed_ = true;
517 }; 577 };
518 578
519 579
520 /** 580 /**
521 * Traverses the call graph in preorder. This function can be used for 581 * Traverses the call graph in preorder. This function can be used for
522 * building optionally modified tree clones. This is the boilerplate code 582 * building optionally modified tree clones. This is the boilerplate code
523 * for this scenario: 583 * for this scenario:
524 * 584 *
525 * callTree.traverse(function(node, parentClone) { 585 * callTree.traverse(function(node, parentClone) {
526 * var nodeClone = cloneNode(node); 586 * var nodeClone = cloneNode(node);
527 * if (parentClone) 587 * if (parentClone)
528 * parentClone.addChild(nodeClone); 588 * parentClone.addChild(nodeClone);
529 * return nodeClone; 589 * return nodeClone;
530 * }); 590 * });
531 * 591 *
532 * @param {function(devtools.profiler.CallTree.Node, *)} f Visitor function. 592 * @param {function(CallTree.Node, *)} f Visitor function.
533 * The second parameter is the result of calling 'f' on the parent node. 593 * The second parameter is the result of calling 'f' on the parent node.
534 */ 594 */
535 devtools.profiler.CallTree.prototype.traverse = function(f) { 595 CallTree.prototype.traverse = function(f) {
536 var pairsToProcess = new ConsArray(); 596 var pairsToProcess = new ConsArray();
537 pairsToProcess.concat([{node: this.root_, param: null}]); 597 pairsToProcess.concat([{node: this.root_, param: null}]);
538 while (!pairsToProcess.atEnd()) { 598 while (!pairsToProcess.atEnd()) {
539 var pair = pairsToProcess.next(); 599 var pair = pairsToProcess.next();
540 var node = pair.node; 600 var node = pair.node;
541 var newParam = f(node, pair.param); 601 var newParam = f(node, pair.param);
542 var morePairsToProcess = []; 602 var morePairsToProcess = [];
543 node.forEachChild(function (child) { 603 node.forEachChild(function (child) {
544 morePairsToProcess.push({node: child, param: newParam}); }); 604 morePairsToProcess.push({node: child, param: newParam}); });
545 pairsToProcess.concat(morePairsToProcess); 605 pairsToProcess.concat(morePairsToProcess);
546 } 606 }
547 }; 607 };
548 608
549 609
550 /** 610 /**
551 * Performs an indepth call graph traversal. 611 * Performs an indepth call graph traversal.
552 * 612 *
553 * @param {function(devtools.profiler.CallTree.Node)} enter A function called 613 * @param {function(CallTree.Node)} enter A function called
554 * prior to visiting node's children. 614 * prior to visiting node's children.
555 * @param {function(devtools.profiler.CallTree.Node)} exit A function called 615 * @param {function(CallTree.Node)} exit A function called
556 * after visiting node's children. 616 * after visiting node's children.
557 */ 617 */
558 devtools.profiler.CallTree.prototype.traverseInDepth = function(enter, exit) { 618 CallTree.prototype.traverseInDepth = function(enter, exit) {
559 function traverse(node) { 619 function traverse(node) {
560 enter(node); 620 enter(node);
561 node.forEachChild(traverse); 621 node.forEachChild(traverse);
562 exit(node); 622 exit(node);
563 } 623 }
564 traverse(this.root_); 624 traverse(this.root_);
565 }; 625 };
566 626
567 627
568 /** 628 /**
569 * Constructs a call graph node. 629 * Constructs a call graph node.
570 * 630 *
571 * @param {string} label Node label. 631 * @param {string} label Node label.
572 * @param {devtools.profiler.CallTree.Node} opt_parent Node parent. 632 * @param {CallTree.Node} opt_parent Node parent.
573 */ 633 */
574 devtools.profiler.CallTree.Node = function(label, opt_parent) { 634 CallTree.Node = function(label, opt_parent) {
575 this.label = label; 635 this.label = label;
576 this.parent = opt_parent; 636 this.parent = opt_parent;
577 this.children = {}; 637 this.children = {};
578 }; 638 };
579 639
580 640
581 /** 641 /**
582 * Node self weight (how many times this node was the last node in 642 * Node self weight (how many times this node was the last node in
583 * a call path). 643 * a call path).
584 * @type {number} 644 * @type {number}
585 */ 645 */
586 devtools.profiler.CallTree.Node.prototype.selfWeight = 0; 646 CallTree.Node.prototype.selfWeight = 0;
587 647
588 648
589 /** 649 /**
590 * Node total weight (includes weights of all children). 650 * Node total weight (includes weights of all children).
591 * @type {number} 651 * @type {number}
592 */ 652 */
593 devtools.profiler.CallTree.Node.prototype.totalWeight = 0; 653 CallTree.Node.prototype.totalWeight = 0;
594 654
595 655
596 /** 656 /**
597 * Adds a child node. 657 * Adds a child node.
598 * 658 *
599 * @param {string} label Child node label. 659 * @param {string} label Child node label.
600 */ 660 */
601 devtools.profiler.CallTree.Node.prototype.addChild = function(label) { 661 CallTree.Node.prototype.addChild = function(label) {
602 var child = new devtools.profiler.CallTree.Node(label, this); 662 var child = new CallTree.Node(label, this);
603 this.children[label] = child; 663 this.children[label] = child;
604 return child; 664 return child;
605 }; 665 };
606 666
607 667
608 /** 668 /**
609 * Computes node's total weight. 669 * Computes node's total weight.
610 */ 670 */
611 devtools.profiler.CallTree.Node.prototype.computeTotalWeight = 671 CallTree.Node.prototype.computeTotalWeight =
612 function() { 672 function() {
613 var totalWeight = this.selfWeight; 673 var totalWeight = this.selfWeight;
614 this.forEachChild(function(child) { 674 this.forEachChild(function(child) {
615 totalWeight += child.computeTotalWeight(); }); 675 totalWeight += child.computeTotalWeight(); });
616 return this.totalWeight = totalWeight; 676 return this.totalWeight = totalWeight;
617 }; 677 };
618 678
619 679
620 /** 680 /**
621 * Returns all node's children as an array. 681 * Returns all node's children as an array.
622 */ 682 */
623 devtools.profiler.CallTree.Node.prototype.exportChildren = function() { 683 CallTree.Node.prototype.exportChildren = function() {
624 var result = []; 684 var result = [];
625 this.forEachChild(function (node) { result.push(node); }); 685 this.forEachChild(function (node) { result.push(node); });
626 return result; 686 return result;
627 }; 687 };
628 688
629 689
630 /** 690 /**
631 * Finds an immediate child with the specified label. 691 * Finds an immediate child with the specified label.
632 * 692 *
633 * @param {string} label Child node label. 693 * @param {string} label Child node label.
634 */ 694 */
635 devtools.profiler.CallTree.Node.prototype.findChild = function(label) { 695 CallTree.Node.prototype.findChild = function(label) {
636 return this.children[label] || null; 696 return this.children[label] || null;
637 }; 697 };
638 698
639 699
640 /** 700 /**
641 * Finds an immediate child with the specified label, creates a child 701 * Finds an immediate child with the specified label, creates a child
642 * node if necessary. 702 * node if necessary.
643 * 703 *
644 * @param {string} label Child node label. 704 * @param {string} label Child node label.
645 */ 705 */
646 devtools.profiler.CallTree.Node.prototype.findOrAddChild = function(label) { 706 CallTree.Node.prototype.findOrAddChild = function(label) {
647 return this.findChild(label) || this.addChild(label); 707 return this.findChild(label) || this.addChild(label);
648 }; 708 };
649 709
650 710
651 /** 711 /**
652 * Calls the specified function for every child. 712 * Calls the specified function for every child.
653 * 713 *
654 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 714 * @param {function(CallTree.Node)} f Visitor function.
655 */ 715 */
656 devtools.profiler.CallTree.Node.prototype.forEachChild = function(f) { 716 CallTree.Node.prototype.forEachChild = function(f) {
657 for (var c in this.children) { 717 for (var c in this.children) {
658 f(this.children[c]); 718 f(this.children[c]);
659 } 719 }
660 }; 720 };
661 721
662 722
663 /** 723 /**
664 * Walks up from the current node up to the call tree root. 724 * Walks up from the current node up to the call tree root.
665 * 725 *
666 * @param {function(devtools.profiler.CallTree.Node)} f Visitor function. 726 * @param {function(CallTree.Node)} f Visitor function.
667 */ 727 */
668 devtools.profiler.CallTree.Node.prototype.walkUpToRoot = function(f) { 728 CallTree.Node.prototype.walkUpToRoot = function(f) {
669 for (var curr = this; curr != null; curr = curr.parent) { 729 for (var curr = this; curr != null; curr = curr.parent) {
670 f(curr); 730 f(curr);
671 } 731 }
672 }; 732 };
673 733
674 734
675 /** 735 /**
676 * Tries to find a node with the specified path. 736 * Tries to find a node with the specified path.
677 * 737 *
678 * @param {Array<string>} labels The path. 738 * @param {Array<string>} labels The path.
679 * @param {function(devtools.profiler.CallTree.Node)} opt_f Visitor function. 739 * @param {function(CallTree.Node)} opt_f Visitor function.
680 */ 740 */
681 devtools.profiler.CallTree.Node.prototype.descendToChild = function( 741 CallTree.Node.prototype.descendToChild = function(
682 labels, opt_f) { 742 labels, opt_f) {
683 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) { 743 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) {
684 var child = curr.findChild(labels[pos]); 744 var child = curr.findChild(labels[pos]);
685 if (opt_f) { 745 if (opt_f) {
686 opt_f(child, pos); 746 opt_f(child, pos);
687 } 747 }
688 curr = child; 748 curr = child;
689 } 749 }
690 return curr; 750 return curr;
691 }; 751 };
OLDNEW
« no previous file with comments | « tools/oprofile/start ('k') | tools/profile_view.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698