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 19 matching lines...) Expand all Loading... |
30 * Creates a profile object for processing profiling-related events | 30 * Creates a profile object for processing profiling-related events |
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 this.c_entries_ = {}; | 39 this.c_entries_ = {}; |
| 40 this.ticks_ = []; |
40 }; | 41 }; |
41 | 42 |
42 | 43 |
43 /** | 44 /** |
44 * Returns whether a function with the specified name must be skipped. | 45 * Returns whether a function with the specified name must be skipped. |
45 * Should be overriden by subclasses. | 46 * Should be overriden by subclasses. |
46 * | 47 * |
47 * @param {string} name Function name. | 48 * @param {string} name Function name. |
48 */ | 49 */ |
49 Profile.prototype.skipThisFunction = function(name) { | 50 Profile.prototype.skipThisFunction = function(name) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 return this.codeMap_.findEntry(addr); | 229 return this.codeMap_.findEntry(addr); |
229 }; | 230 }; |
230 | 231 |
231 | 232 |
232 /** | 233 /** |
233 * Records a tick event. Stack must contain a sequence of | 234 * Records a tick event. Stack must contain a sequence of |
234 * addresses starting with the program counter value. | 235 * addresses starting with the program counter value. |
235 * | 236 * |
236 * @param {Array<number>} stack Stack sample. | 237 * @param {Array<number>} stack Stack sample. |
237 */ | 238 */ |
238 Profile.prototype.recordTick = function(stack) { | 239 Profile.prototype.recordTick = function(time_ns, vmState, stack) { |
239 var processedStack = this.resolveAndFilterFuncs_(stack); | 240 var processedStack = this.resolveAndFilterFuncs_(stack); |
240 this.bottomUpTree_.addPath(processedStack); | 241 this.bottomUpTree_.addPath(processedStack); |
241 processedStack.reverse(); | 242 processedStack.reverse(); |
242 this.topDownTree_.addPath(processedStack); | 243 this.topDownTree_.addPath(processedStack); |
243 }; | 244 }; |
244 | 245 |
245 | 246 |
246 /** | 247 /** |
247 * Translates addresses into function names and filters unneeded | 248 * Translates addresses into function names and filters unneeded |
248 * functions. | 249 * functions. |
(...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
825 labels, opt_f) { | 826 labels, opt_f) { |
826 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) { | 827 for (var pos = 0, curr = this; pos < labels.length && curr != null; pos++) { |
827 var child = curr.findChild(labels[pos]); | 828 var child = curr.findChild(labels[pos]); |
828 if (opt_f) { | 829 if (opt_f) { |
829 opt_f(child, pos); | 830 opt_f(child, pos); |
830 } | 831 } |
831 curr = child; | 832 curr = child; |
832 } | 833 } |
833 return curr; | 834 return curr; |
834 }; | 835 }; |
| 836 |
| 837 function JsonProfile() { |
| 838 this.codeMap_ = new CodeMap(); |
| 839 this.codeEntries_ = []; |
| 840 this.functionEntries_ = []; |
| 841 this.ticks_ = []; |
| 842 } |
| 843 |
| 844 JsonProfile.prototype.addLibrary = function( |
| 845 name, startAddr, endAddr) { |
| 846 var entry = new CodeMap.CodeEntry( |
| 847 endAddr - startAddr, name, 'SHARED_LIB'); |
| 848 this.codeMap_.addLibrary(startAddr, entry); |
| 849 |
| 850 entry.codeId = this.codeEntries_.length; |
| 851 this.codeEntries_.push({name : entry.name, type : entry.type}); |
| 852 return entry; |
| 853 }; |
| 854 |
| 855 JsonProfile.prototype.addStaticCode = function( |
| 856 name, startAddr, endAddr) { |
| 857 var entry = new CodeMap.CodeEntry( |
| 858 endAddr - startAddr, name, 'CPP'); |
| 859 this.codeMap_.addStaticCode(startAddr, entry); |
| 860 |
| 861 entry.codeId = this.codeEntries_.length; |
| 862 this.codeEntries_.push({name : entry.name, type : entry.type}); |
| 863 return entry; |
| 864 }; |
| 865 |
| 866 JsonProfile.prototype.addCode = function( |
| 867 kind, name, start, size) { |
| 868 var entry = new CodeMap.CodeEntry(size, name, 'CODE'); |
| 869 this.codeMap_.addCode(start, entry); |
| 870 |
| 871 entry.codeId = this.codeEntries_.length; |
| 872 this.codeEntries_.push({name : entry.name, type : entry.type, kind : kind}); |
| 873 |
| 874 return entry; |
| 875 }; |
| 876 |
| 877 JsonProfile.prototype.addFuncCode = function( |
| 878 kind, name, start, size, funcAddr, state) { |
| 879 // As code and functions are in the same address space, |
| 880 // it is safe to put them in a single code map. |
| 881 var func = this.codeMap_.findDynamicEntryByStartAddress(funcAddr); |
| 882 if (!func) { |
| 883 var func = new CodeMap.CodeEntry(0, name, 'SFI'); |
| 884 this.codeMap_.addCode(funcAddr, func); |
| 885 |
| 886 func.funcId = this.functionEntries_.length; |
| 887 this.functionEntries_.push({name : name, codes : []}); |
| 888 } else if (func.name !== name) { |
| 889 // Function object has been overwritten with a new one. |
| 890 func.name = name; |
| 891 |
| 892 func.funcId = this.functionEntries_.length; |
| 893 this.functionEntries_.push({name : name, codes : []}); |
| 894 } |
| 895 // TODO(jarin): Insert the code object into the SFI's code list. |
| 896 var entry = this.codeMap_.findDynamicEntryByStartAddress(start); |
| 897 if (entry) { |
| 898 // TODO(jarin) This does not look correct, we should really |
| 899 // update the code object (remove the old one and insert this one). |
| 900 if (entry.size === size && entry.func === func) { |
| 901 // Entry state has changed. |
| 902 entry.state = state; |
| 903 } |
| 904 } else { |
| 905 var entry = new CodeMap.CodeEntry(size, name, 'JS'); |
| 906 this.codeMap_.addCode(start, entry); |
| 907 |
| 908 entry.codeId = this.codeEntries_.length; |
| 909 |
| 910 this.functionEntries_[func.funcId].codes.push(entry.codeId); |
| 911 |
| 912 if (state === 0) { |
| 913 kind = "Builtin"; |
| 914 } else if (state === 1) { |
| 915 kind = "Unopt"; |
| 916 } else if (state === 2) { |
| 917 kind = "Opt"; |
| 918 } |
| 919 |
| 920 this.codeEntries_.push({ |
| 921 name : entry.name, |
| 922 type : entry.type, |
| 923 kind : kind, |
| 924 func : func.funcId |
| 925 }); |
| 926 } |
| 927 return entry; |
| 928 }; |
| 929 |
| 930 JsonProfile.prototype.moveCode = function(from, to) { |
| 931 try { |
| 932 this.codeMap_.moveCode(from, to); |
| 933 } catch (e) { |
| 934 printErr("Move: unknown source " + from); |
| 935 } |
| 936 }; |
| 937 |
| 938 JsonProfile.prototype.deleteCode = function(start) { |
| 939 try { |
| 940 this.codeMap_.deleteCode(start); |
| 941 } catch (e) { |
| 942 printErr("Delete: unknown address " + start); |
| 943 } |
| 944 }; |
| 945 |
| 946 JsonProfile.prototype.moveFunc = function(from, to) { |
| 947 if (this.codeMap_.findDynamicEntryByStartAddress(from)) { |
| 948 this.codeMap_.moveCode(from, to); |
| 949 } |
| 950 }; |
| 951 |
| 952 JsonProfile.prototype.findEntry = function(addr) { |
| 953 return this.codeMap_.findEntry(addr); |
| 954 }; |
| 955 |
| 956 JsonProfile.prototype.recordTick = function(time_ns, vmState, stack) { |
| 957 // TODO(jarin) Resolve the frame-less case (when top of stack is |
| 958 // known code). |
| 959 var processedStack = []; |
| 960 for (var i = 0; i < stack.length; i++) { |
| 961 var resolved = this.codeMap_.findAddress(stack[i]); |
| 962 if (resolved) { |
| 963 processedStack.push(resolved.entry.codeId, resolved.offset); |
| 964 } else { |
| 965 processedStack.push(-1, stack[i]); |
| 966 } |
| 967 } |
| 968 this.ticks_.push({ tm : time_ns, vm : vmState, s : processedStack }); |
| 969 }; |
| 970 |
| 971 JsonProfile.prototype.writeJson = function() { |
| 972 var toplevel = { |
| 973 code : this.codeEntries_, |
| 974 functions : this.functionEntries_, |
| 975 ticks : this.ticks_ |
| 976 }; |
| 977 write(JSON.stringify(toplevel)); |
| 978 }; |
OLD | NEW |