OLD | NEW |
---|---|
1 #! /usr/bin/python2 | 1 #! /usr/bin/python2 |
2 # | 2 # |
3 # Copyright 2016 the V8 project authors. All rights reserved. | 3 # Copyright 2016 the V8 project authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 # | 6 # |
7 | 7 |
8 import argparse | 8 import argparse |
9 import collections | 9 import collections |
10 import re | 10 import re |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
45 # See the hottest bytecodes on Octane benchmark, by number of samples. | 45 # See the hottest bytecodes on Octane benchmark, by number of samples. |
46 # | 46 # |
47 $ tools/run-perf.sh out/x64.release/d8 \\ | 47 $ tools/run-perf.sh out/x64.release/d8 \\ |
48 --ignition --noturbo --nocrankshaft octane/run.js | 48 --ignition --noturbo --nocrankshaft octane/run.js |
49 $ tools/ignition/linux_perf_report.py | 49 $ tools/ignition/linux_perf_report.py |
50 """ | 50 """ |
51 | 51 |
52 | 52 |
53 COMPILER_SYMBOLS_RE = re.compile( | 53 COMPILER_SYMBOLS_RE = re.compile( |
54 r"v8::internal::(?:\(anonymous namespace\)::)?Compile|v8::internal::Parser") | 54 r"v8::internal::(?:\(anonymous namespace\)::)?Compile|v8::internal::Parser") |
55 JIT_CODE_SYMBOLS_RE = re.compile( | |
56 r"(LazyCompile|Compile|Eval|Script):(\*|~)") | |
55 | 57 |
56 | 58 |
57 def strip_function_parameters(symbol): | 59 def strip_function_parameters(symbol): |
58 if symbol[-1] != ')': return symbol | 60 if symbol[-1] != ')': return symbol |
59 pos = 1 | 61 pos = 1 |
60 parenthesis_count = 0 | 62 parenthesis_count = 0 |
61 for c in reversed(symbol): | 63 for c in reversed(symbol): |
62 if c == ')': | 64 if c == ')': |
63 parenthesis_count += 1 | 65 parenthesis_count += 1 |
64 elif c == '(': | 66 elif c == '(': |
65 parenthesis_count -= 1 | 67 parenthesis_count -= 1 |
66 if parenthesis_count == 0: | 68 if parenthesis_count == 0: |
67 break | 69 break |
68 else: | 70 else: |
69 pos += 1 | 71 pos += 1 |
70 return symbol[:-pos] | 72 return symbol[:-pos] |
71 | 73 |
72 | 74 |
73 def collapsed_callchains_generator(perf_stream, show_all=False, | 75 def collapsed_callchains_generator(perf_stream, hide_other=False, |
76 hide_compiler=False, hide_jit=False, | |
74 show_full_signatures=False): | 77 show_full_signatures=False): |
75 current_chain = [] | 78 current_chain = [] |
76 skip_until_end_of_chain = False | 79 skip_until_end_of_chain = False |
77 compiler_symbol_in_chain = False | 80 compiler_symbol_in_chain = False |
78 | 81 |
79 for line in perf_stream: | 82 for line in perf_stream: |
80 # Lines starting with a "#" are comments, skip them. | 83 # Lines starting with a "#" are comments, skip them. |
81 if line[0] == "#": | 84 if line[0] == "#": |
82 continue | 85 continue |
83 | 86 |
84 line = line.strip() | 87 line = line.strip() |
85 | 88 |
86 # Empty line signals the end of the callchain. | 89 # Empty line signals the end of the callchain. |
87 if not line: | 90 if not line: |
88 if not skip_until_end_of_chain and current_chain and show_all: | 91 if (not skip_until_end_of_chain and current_chain |
92 and not hide_other): | |
89 current_chain.append("[other]") | 93 current_chain.append("[other]") |
90 yield current_chain | 94 yield current_chain |
91 # Reset parser status. | 95 # Reset parser status. |
92 current_chain = [] | 96 current_chain = [] |
93 skip_until_end_of_chain = False | 97 skip_until_end_of_chain = False |
94 compiler_symbol_in_chain = False | 98 compiler_symbol_in_chain = False |
95 continue | 99 continue |
96 | 100 |
97 if skip_until_end_of_chain: | 101 if skip_until_end_of_chain: |
98 continue | 102 continue |
99 | 103 |
100 # Trim the leading address and the trailing +offset, if present. | 104 # Trim the leading address and the trailing +offset, if present. |
101 symbol = line.split(" ", 1)[1].split("+", 1)[0] | 105 symbol = line.split(" ", 1)[1].split("+", 1)[0] |
102 if not show_full_signatures: | 106 if not show_full_signatures: |
103 symbol = strip_function_parameters(symbol) | 107 symbol = strip_function_parameters(symbol) |
108 | |
109 # Avoid chains of [unknown] | |
110 if symbol == "[unknown]" and current_chain[-1] == "[unknown]": | |
mythria
2016/11/08 09:47:07
It is possible that symbol is unknown and the curr
| |
111 continue | |
112 | |
104 current_chain.append(symbol) | 113 current_chain.append(symbol) |
105 | 114 |
106 if symbol.startswith("BytecodeHandler:"): | 115 if symbol.startswith("BytecodeHandler:"): |
116 current_chain.append("[interpreter]") | |
107 yield current_chain | 117 yield current_chain |
108 skip_until_end_of_chain = True | 118 skip_until_end_of_chain = True |
119 elif JIT_CODE_SYMBOLS_RE.match(symbol): | |
120 if not hide_jit: | |
121 current_chain.append("[jit]") | |
122 yield current_chain | |
123 skip_until_end_of_chain = True | |
109 elif symbol == "Stub:CEntryStub" and compiler_symbol_in_chain: | 124 elif symbol == "Stub:CEntryStub" and compiler_symbol_in_chain: |
110 if show_all: | 125 if not hide_compiler: |
111 current_chain[-1] = "[compiler]" | 126 current_chain.append("[compiler]") |
112 yield current_chain | 127 yield current_chain |
113 skip_until_end_of_chain = True | 128 skip_until_end_of_chain = True |
114 elif COMPILER_SYMBOLS_RE.match(symbol): | 129 elif COMPILER_SYMBOLS_RE.match(symbol): |
115 compiler_symbol_in_chain = True | 130 compiler_symbol_in_chain = True |
116 elif symbol == "Builtin:InterpreterEntryTrampoline": | 131 elif symbol == "Builtin:InterpreterEntryTrampoline": |
117 if len(current_chain) == 1: | 132 if len(current_chain) == 1: |
118 yield ["[entry trampoline]"] | 133 yield ["[entry trampoline]"] |
119 else: | 134 else: |
120 # If we see an InterpreterEntryTrampoline which is not at the top of the | 135 # If we see an InterpreterEntryTrampoline which is not at the top of the |
121 # chain and doesn't have a BytecodeHandler above it, then we have | 136 # chain and doesn't have a BytecodeHandler above it, then we have |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 default="perf.data", | 189 default="perf.data", |
175 metavar="<perf filename>" | 190 metavar="<perf filename>" |
176 ) | 191 ) |
177 command_line_parser.add_argument( | 192 command_line_parser.add_argument( |
178 "--flamegraph", "-f", | 193 "--flamegraph", "-f", |
179 help="output an input file for flamegraph.pl, not a report", | 194 help="output an input file for flamegraph.pl, not a report", |
180 action="store_true", | 195 action="store_true", |
181 dest="output_flamegraph" | 196 dest="output_flamegraph" |
182 ) | 197 ) |
183 command_line_parser.add_argument( | 198 command_line_parser.add_argument( |
184 "--show-all", "-a", | 199 "--hide-other", |
185 help="show samples outside Ignition bytecode handlers", | 200 help="Hide other samples", |
186 action="store_true" | 201 action="store_true" |
187 ) | 202 ) |
188 command_line_parser.add_argument( | 203 command_line_parser.add_argument( |
204 "--hide-compiler", | |
205 help="Hide samples during compilation", | |
206 action="store_true" | |
207 ) | |
208 command_line_parser.add_argument( | |
209 "--hide-jit", | |
210 help="Hide samples from JIT code execution", | |
211 action="store_true" | |
212 ) | |
213 command_line_parser.add_argument( | |
189 "--show-full-signatures", "-s", | 214 "--show-full-signatures", "-s", |
190 help="show full signatures instead of function names", | 215 help="show full signatures instead of function names", |
191 action="store_true" | 216 action="store_true" |
192 ) | 217 ) |
193 command_line_parser.add_argument( | 218 command_line_parser.add_argument( |
194 "--output", "-o", | 219 "--output", "-o", |
195 help="output file name (stdout if omitted)", | 220 help="output file name (stdout if omitted)", |
196 type=argparse.FileType('wt'), | 221 type=argparse.FileType('wt'), |
197 default=sys.stdout, | 222 default=sys.stdout, |
198 metavar="<output filename>", | 223 metavar="<output filename>", |
199 dest="output_stream" | 224 dest="output_stream" |
200 ) | 225 ) |
201 | 226 |
202 return command_line_parser.parse_args() | 227 return command_line_parser.parse_args() |
203 | 228 |
204 | 229 |
205 def main(): | 230 def main(): |
206 program_options = parse_command_line() | 231 program_options = parse_command_line() |
207 | 232 |
208 perf = subprocess.Popen(["perf", "script", "--fields", "ip,sym", | 233 perf = subprocess.Popen(["perf", "script", "--fields", "ip,sym", |
209 "-i", program_options.perf_filename], | 234 "-i", program_options.perf_filename], |
210 stdout=subprocess.PIPE) | 235 stdout=subprocess.PIPE) |
211 | 236 |
212 callchains = collapsed_callchains_generator( | 237 callchains = collapsed_callchains_generator( |
213 perf.stdout, program_options.show_all, | 238 perf.stdout, program_options.hide_other, program_options.hide_compiler, |
214 program_options.show_full_signatures) | 239 program_options.hide_jit, program_options.show_full_signatures) |
215 | 240 |
216 if program_options.output_flamegraph: | 241 if program_options.output_flamegraph: |
217 write_flamegraph_input_file(program_options.output_stream, callchains) | 242 write_flamegraph_input_file(program_options.output_stream, callchains) |
218 else: | 243 else: |
219 write_handlers_report(program_options.output_stream, callchains) | 244 write_handlers_report(program_options.output_stream, callchains) |
220 | 245 |
221 | 246 |
222 if __name__ == "__main__": | 247 if __name__ == "__main__": |
223 main() | 248 main() |
OLD | NEW |