| 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 |