OLD | NEW |
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 |
(...skipping 20 matching lines...) Expand all Loading... |
31 * and calculating function execution times. | 31 * and calculating function execution times. |
32 * | 32 * |
33 * @constructor | 33 * @constructor |
34 */ | 34 */ |
35 function Profile() { | 35 function Profile() { |
36 this.codeMap_ = new CodeMap(); | 36 this.codeMap_ = new CodeMap(); |
37 this.topDownTree_ = new CallTree(); | 37 this.topDownTree_ = new CallTree(); |
38 this.bottomUpTree_ = new CallTree(); | 38 this.bottomUpTree_ = new CallTree(); |
39 }; | 39 }; |
40 | 40 |
41 /** | |
42 * Version of profiler log. | |
43 */ | |
44 Profile.VERSION = 2; | |
45 | |
46 | 41 |
47 /** | 42 /** |
48 * Returns whether a function with the specified name must be skipped. | 43 * Returns whether a function with the specified name must be skipped. |
49 * Should be overriden by subclasses. | 44 * Should be overriden by subclasses. |
50 * | 45 * |
51 * @param {string} name Function name. | 46 * @param {string} name Function name. |
52 */ | 47 */ |
53 Profile.prototype.skipThisFunction = function(name) { | 48 Profile.prototype.skipThisFunction = function(name) { |
54 return false; | 49 return false; |
55 }; | 50 }; |
56 | 51 |
57 | 52 |
58 /** | 53 /** |
59 * Enum for profiler operations that involve looking up existing | 54 * Enum for profiler operations that involve looking up existing |
60 * code entries. | 55 * code entries. |
61 * | 56 * |
62 * @enum {number} | 57 * @enum {number} |
63 */ | 58 */ |
64 Profile.Operation = { | 59 Profile.Operation = { |
65 MOVE: 0, | 60 MOVE: 0, |
66 DELETE: 1, | 61 DELETE: 1, |
67 TICK: 2 | 62 TICK: 2 |
68 }; | 63 }; |
69 | 64 |
70 | 65 |
71 /** | 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 /** |
72 * Called whenever the specified operation has failed finding a function | 79 * Called whenever the specified operation has failed finding a function |
73 * containing the specified address. Should be overriden by subclasses. | 80 * containing the specified address. Should be overriden by subclasses. |
74 * See the Profile.Operation enum for the list of | 81 * See the Profile.Operation enum for the list of |
75 * possible operations. | 82 * possible operations. |
76 * | 83 * |
77 * @param {number} operation Operation. | 84 * @param {number} operation Operation. |
78 * @param {number} addr Address of the unknown code. | 85 * @param {number} addr Address of the unknown code. |
79 * @param {number} opt_stackPos If an unknown address is encountered | 86 * @param {number} opt_stackPos If an unknown address is encountered |
80 * during stack strace processing, specifies a position of the frame | 87 * during stack strace processing, specifies a position of the frame |
81 * containing the address. | 88 * containing the address. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 */ | 134 */ |
128 Profile.prototype.addCode = function( | 135 Profile.prototype.addCode = function( |
129 type, name, start, size) { | 136 type, name, start, size) { |
130 var entry = new Profile.DynamicCodeEntry(size, type, name); | 137 var entry = new Profile.DynamicCodeEntry(size, type, name); |
131 this.codeMap_.addCode(start, entry); | 138 this.codeMap_.addCode(start, entry); |
132 return entry; | 139 return entry; |
133 }; | 140 }; |
134 | 141 |
135 | 142 |
136 /** | 143 /** |
137 * Creates an alias entry for a code entry. | 144 * Registers dynamic (JIT-compiled) code entry. |
138 * | 145 * |
139 * @param {number} aliasAddr Alias address. | 146 * @param {string} type Code entry type. |
140 * @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. |
141 */ | 152 */ |
142 Profile.prototype.addCodeAlias = function( | 153 Profile.prototype.addFuncCode = function( |
143 aliasAddr, addr) { | 154 type, name, start, size, funcAddr, state) { |
144 var entry = this.codeMap_.findDynamicEntryByStartAddress(addr); | 155 // As code and functions are in the same address space, |
145 if (entry) { | 156 // it is safe to put them in a single code map. |
146 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; |
147 } | 164 } |
| 165 var entry = new Profile.DynamicFuncCodeEntry(size, type, func, state); |
| 166 this.codeMap_.addCode(start, entry); |
| 167 return entry; |
148 }; | 168 }; |
149 | 169 |
150 | 170 |
151 /** | 171 /** |
152 * Reports about moving of a dynamic code entry. | 172 * Reports about moving of a dynamic code entry. |
153 * | 173 * |
154 * @param {number} from Current code entry address. | 174 * @param {number} from Current code entry address. |
155 * @param {number} to New code entry address. | 175 * @param {number} to New code entry address. |
156 */ | 176 */ |
157 Profile.prototype.moveCode = function(from, to) { | 177 Profile.prototype.moveCode = function(from, to) { |
(...skipping 18 matching lines...) Expand all Loading... |
176 } | 196 } |
177 }; | 197 }; |
178 | 198 |
179 | 199 |
180 /** | 200 /** |
181 * Reports about moving of a dynamic code entry. | 201 * Reports about moving of a dynamic code entry. |
182 * | 202 * |
183 * @param {number} from Current code entry address. | 203 * @param {number} from Current code entry address. |
184 * @param {number} to New code entry address. | 204 * @param {number} to New code entry address. |
185 */ | 205 */ |
186 Profile.prototype.safeMoveDynamicCode = function(from, to) { | 206 Profile.prototype.moveFunc = function(from, to) { |
187 if (this.codeMap_.findDynamicEntryByStartAddress(from)) { | 207 if (this.codeMap_.findDynamicEntryByStartAddress(from)) { |
188 this.codeMap_.moveCode(from, to); | 208 this.codeMap_.moveCode(from, to); |
189 } | 209 } |
190 }; | 210 }; |
191 | 211 |
192 | 212 |
193 /** | 213 /** |
194 * Reports about deletion of a dynamic code entry. | |
195 * | |
196 * @param {number} start Starting address. | |
197 */ | |
198 Profile.prototype.safeDeleteDynamicCode = function(start) { | |
199 if (this.codeMap_.findDynamicEntryByStartAddress(start)) { | |
200 this.codeMap_.deleteCode(start); | |
201 } | |
202 }; | |
203 | |
204 | |
205 /** | |
206 * Retrieves a code entry by an address. | 214 * Retrieves a code entry by an address. |
207 * | 215 * |
208 * @param {number} addr Entry address. | 216 * @param {number} addr Entry address. |
209 */ | 217 */ |
210 Profile.prototype.findEntry = function(addr) { | 218 Profile.prototype.findEntry = function(addr) { |
211 return this.codeMap_.findEntry(addr); | 219 return this.codeMap_.findEntry(addr); |
212 }; | 220 }; |
213 | 221 |
214 | 222 |
215 /** | 223 /** |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 Profile.DynamicCodeEntry = function(size, type, name) { | 384 Profile.DynamicCodeEntry = function(size, type, name) { |
377 CodeMap.CodeEntry.call(this, size, name); | 385 CodeMap.CodeEntry.call(this, size, name); |
378 this.type = type; | 386 this.type = type; |
379 }; | 387 }; |
380 | 388 |
381 | 389 |
382 /** | 390 /** |
383 * Returns node name. | 391 * Returns node name. |
384 */ | 392 */ |
385 Profile.DynamicCodeEntry.prototype.getName = function() { | 393 Profile.DynamicCodeEntry.prototype.getName = function() { |
386 var name = this.name; | 394 return this.type + ': ' + this.name; |
387 if (name.length == 0) { | |
388 name = '<anonymous>'; | |
389 } else if (name.charAt(0) == ' ') { | |
390 // An anonymous function with location: " aaa.js:10". | |
391 name = '<anonymous>' + name; | |
392 } | |
393 return this.type + ': ' + name; | |
394 }; | 395 }; |
395 | 396 |
396 | 397 |
397 /** | 398 /** |
398 * Returns raw node name (without type decoration). | 399 * Returns raw node name (without type decoration). |
399 */ | 400 */ |
400 Profile.DynamicCodeEntry.prototype.getRawName = function() { | 401 Profile.DynamicCodeEntry.prototype.getRawName = function() { |
401 return this.name; | 402 return this.name; |
402 }; | 403 }; |
403 | 404 |
404 | 405 |
405 Profile.DynamicCodeEntry.prototype.isJSFunction = function() { | 406 Profile.DynamicCodeEntry.prototype.isJSFunction = function() { |
406 return this.type == "Function" || | 407 return false; |
407 this.type == "LazyCompile" || | |
408 this.type == "Script"; | |
409 }; | 408 }; |
410 | 409 |
411 | 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() { |
| 466 var name = this.name; |
| 467 if (name.length == 0) { |
| 468 name = '<anonymous>'; |
| 469 } else if (name.charAt(0) == ' ') { |
| 470 // An anonymous function with location: " aaa.js:10". |
| 471 name = '<anonymous>' + name; |
| 472 } |
| 473 return name; |
| 474 }; |
| 475 |
| 476 |
412 /** | 477 /** |
413 * Constructs a call graph. | 478 * Constructs a call graph. |
414 * | 479 * |
415 * @constructor | 480 * @constructor |
416 */ | 481 */ |
417 function CallTree() { | 482 function CallTree() { |
418 this.root_ = new CallTree.Node( | 483 this.root_ = new CallTree.Node( |
419 CallTree.ROOT_NODE_LABEL); | 484 CallTree.ROOT_NODE_LABEL); |
420 }; | 485 }; |
421 | 486 |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 labels, opt_f) { | 742 labels, opt_f) { |
678 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++) { |
679 var child = curr.findChild(labels[pos]); | 744 var child = curr.findChild(labels[pos]); |
680 if (opt_f) { | 745 if (opt_f) { |
681 opt_f(child, pos); | 746 opt_f(child, pos); |
682 } | 747 } |
683 curr = child; | 748 curr = child; |
684 } | 749 } |
685 return curr; | 750 return curr; |
686 }; | 751 }; |
OLD | NEW |