OLD | NEW |
1 # Copyright 2017 The Chromium Authors. All rights reserved. | 1 # Copyright 2017 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """An interactive console for looking analyzing .size files.""" | 5 """An interactive console for looking analyzing .size files.""" |
6 | 6 |
7 import argparse | 7 import argparse |
8 import atexit | 8 import atexit |
9 import code | 9 import code |
10 import contextlib | 10 import contextlib |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 with open(to_file, 'w') as file_obj: | 60 with open(to_file, 'w') as file_obj: |
61 describe.WriteLines(lines, file_obj.write) | 61 describe.WriteLines(lines, file_obj.write) |
62 else: | 62 else: |
63 describe.WriteLines(lines, sys.stdout.write) | 63 describe.WriteLines(lines, sys.stdout.write) |
64 | 64 |
65 | 65 |
66 class _Session(object): | 66 class _Session(object): |
67 _readline_initialized = False | 67 _readline_initialized = False |
68 | 68 |
69 def __init__(self, size_infos, size_paths, lazy_paths): | 69 def __init__(self, size_infos, size_paths, lazy_paths): |
| 70 self._printed_variables = [] |
70 self._variables = { | 71 self._variables = { |
71 'Print': self._PrintFunc, | 72 'Print': self._PrintFunc, |
72 'Diff': self._DiffFunc, | 73 'Diff': self._DiffFunc, |
73 'Disassemble': self._DisassembleFunc, | 74 'Disassemble': self._DisassembleFunc, |
74 'ExpandRegex': match_util.ExpandRegexIdentifierPlaceholder, | 75 'ExpandRegex': match_util.ExpandRegexIdentifierPlaceholder, |
75 'ShowExamples': self._ShowExamplesFunc, | 76 'ShowExamples': self._ShowExamplesFunc, |
76 'canned_queries': canned_queries.CannedQueries(size_infos), | 77 'canned_queries': canned_queries.CannedQueries(size_infos), |
| 78 'printed': self._printed_variables, |
77 } | 79 } |
78 self._lazy_paths = lazy_paths | 80 self._lazy_paths = lazy_paths |
79 self._size_infos = size_infos | 81 self._size_infos = size_infos |
80 self._size_paths = size_paths | 82 self._size_paths = size_paths |
81 self._disassemble_prefix_len = None | 83 self._disassemble_prefix_len = None |
82 | 84 |
83 if len(size_infos) == 1: | 85 if len(size_infos) == 1: |
84 self._variables['size_info'] = size_infos[0] | 86 self._variables['size_info'] = size_infos[0] |
85 else: | 87 else: |
86 for i, size_info in enumerate(size_infos): | 88 for i, size_info in enumerate(size_infos): |
(...skipping 15 matching lines...) Expand all Loading... |
102 if cluster: | 104 if cluster: |
103 ret.symbols = ret.symbols.Clustered() | 105 ret.symbols = ret.symbols.Clustered() |
104 if sort: | 106 if sort: |
105 ret.symbols = ret.symbols.Sorted() | 107 ret.symbols = ret.symbols.Sorted() |
106 return ret | 108 return ret |
107 | 109 |
108 def _PrintFunc(self, obj=None, verbose=False, recursive=False, use_pager=None, | 110 def _PrintFunc(self, obj=None, verbose=False, recursive=False, use_pager=None, |
109 to_file=None): | 111 to_file=None): |
110 """Prints out the given Symbol / SymbolGroup / SymbolDiff / SizeInfo. | 112 """Prints out the given Symbol / SymbolGroup / SymbolDiff / SizeInfo. |
111 | 113 |
| 114 For convenience, |obj| will be appended to the global "printed" list. |
| 115 |
112 Args: | 116 Args: |
113 obj: The object to be printed. Defaults to size_infos[-1]. | 117 obj: The object to be printed. Defaults to size_infos[-1]. |
114 verbose: Show more detailed output. | 118 verbose: Show more detailed output. |
115 recursive: Print children of nested SymbolGroups. | 119 recursive: Print children of nested SymbolGroups. |
116 use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol. | 120 use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol. |
117 default is to automatically pipe when output is long. | 121 default is to automatically pipe when output is long. |
118 to_file: Rather than print to stdio, write to the given file. | 122 to_file: Rather than print to stdio, write to the given file. |
119 """ | 123 """ |
| 124 if not self._printed_variables or self._printed_variables[-1] != obj: |
| 125 self._printed_variables.append(obj) |
120 obj = obj if obj is not None else self._size_infos[-1] | 126 obj = obj if obj is not None else self._size_infos[-1] |
121 lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive) | 127 lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive) |
122 _WriteToStream(lines, use_pager=use_pager, to_file=to_file) | 128 _WriteToStream(lines, use_pager=use_pager, to_file=to_file) |
123 | 129 |
124 def _ElfPathAndToolPrefixForSymbol(self, symbol, elf_path, tool_prefix): | 130 def _ElfPathAndToolPrefixForSymbol(self, symbol, elf_path, tool_prefix): |
125 size_info = None | 131 size_info = None |
126 size_path = None | 132 size_path = None |
127 for size_info, size_path in zip(self._size_infos, self._size_paths): | 133 for size_info, size_path in zip(self._size_infos, self._size_paths): |
128 if symbol in size_info.symbols: | 134 if symbol in size_info.symbols: |
129 break | 135 break |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 | 195 |
190 def _DisassembleFunc(self, symbol, elf_path=None, use_pager=None, | 196 def _DisassembleFunc(self, symbol, elf_path=None, use_pager=None, |
191 to_file=None): | 197 to_file=None): |
192 """Shows objdump disassembly for the given symbol. | 198 """Shows objdump disassembly for the given symbol. |
193 | 199 |
194 Args: | 200 Args: |
195 symbol: Must be a .text symbol and not a SymbolGroup. | 201 symbol: Must be a .text symbol and not a SymbolGroup. |
196 elf_path: Path to the executable containing the symbol. Required only | 202 elf_path: Path to the executable containing the symbol. Required only |
197 when auto-detection fails. | 203 when auto-detection fails. |
198 """ | 204 """ |
| 205 assert not symbol.IsGroup() |
199 assert symbol.address and symbol.section_name == '.text' | 206 assert symbol.address and symbol.section_name == '.text' |
200 | 207 |
201 tool_prefix = self._lazy_paths.tool_prefix | 208 tool_prefix = self._lazy_paths.tool_prefix |
202 if not elf_path: | 209 if not elf_path: |
203 elf_path, tool_prefix = self._ElfPathAndToolPrefixForSymbol( | 210 elf_path, tool_prefix = self._ElfPathAndToolPrefixForSymbol( |
204 symbol, elf_path, tool_prefix) | 211 symbol, elf_path, tool_prefix) |
205 | 212 |
206 args = [tool_prefix + 'objdump', '--disassemble', '--source', | 213 args = [tool_prefix + 'objdump', '--disassemble', '--source', |
207 '--line-numbers', '--demangle', | 214 '--line-numbers', '--demangle', |
208 '--start-address=0x%x' % symbol.address, | 215 '--start-address=0x%x' % symbol.address, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 'help(models)', | 247 'help(models)', |
241 '', | 248 '', |
242 '# Show all attributes of all symbols & per-section totals:', | 249 '# Show all attributes of all symbols & per-section totals:', |
243 'Print(size_info, verbose=True)', | 250 'Print(size_info, verbose=True)', |
244 '', | 251 '', |
245 '# Show two levels of .text, grouped by first two subdirectories', | 252 '# Show two levels of .text, grouped by first two subdirectories', |
246 'text_syms = size_info.symbols.WhereInSection("t")', | 253 'text_syms = size_info.symbols.WhereInSection("t")', |
247 'by_path = text_syms.GroupedByPath(depth=2)', | 254 'by_path = text_syms.GroupedByPath(depth=2)', |
248 'Print(by_path.WherePssBiggerThan(1024))', | 255 'Print(by_path.WherePssBiggerThan(1024))', |
249 '', | 256 '', |
250 '# Show all non-vtable generated symbols', | 257 '# Show all generated symbols, then show only non-vtable ones', |
251 'generated_syms = size_info.symbols.WhereGeneratedByToolchain()', | 258 'Print(size_info.symbols.WhereGeneratedByToolchain())', |
252 'Print(generated_syms.WhereNameMatches(r"vtable").Inverted().Sorted())', | 259 'Print(printed[-1].WhereNameMatches(r"vtable").Inverted().Sorted())', |
253 '', | 260 '', |
254 '# Show all symbols that have "print" in their name or path, except', | 261 '# Show all symbols that have "print" in their name or path, except', |
255 '# those within components/.', | 262 '# those within components/.', |
256 '# Note: Could have also used Inverted(), as above.', | 263 '# Note: Could have also used Inverted(), as above.', |
257 '# Note: Use "help(ExpandRegex)" for more about what {{_print_}} does.', | 264 '# Note: Use "help(ExpandRegex)" for more about what {{_print_}} does.', |
258 'print_syms = size_info.symbols.WhereMatches(r"{{_print_}}")', | 265 'print_syms = size_info.symbols.WhereMatches(r"{{_print_}}")', |
259 'Print(print_syms - print_syms.WherePathMatches(r"^components/"))', | 266 'Print(print_syms - print_syms.WherePathMatches(r"^components/"))', |
260 '', | 267 '', |
261 '# Diff two .size files and save result to a file:', | 268 '# Diff two .size files and save result to a file:', |
262 'Print(Diff(size_info1, size_info2), to_file="output.txt")', | 269 'Print(Diff(size_info1, size_info2), to_file="output.txt")', |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 output_directory=args.output_directory, | 355 output_directory=args.output_directory, |
349 any_path_within_output_directory=args.inputs[0]) | 356 any_path_within_output_directory=args.inputs[0]) |
350 session = _Session(size_infos, args.inputs, lazy_paths) | 357 session = _Session(size_infos, args.inputs, lazy_paths) |
351 | 358 |
352 if args.query: | 359 if args.query: |
353 logging.info('Running query from command-line.') | 360 logging.info('Running query from command-line.') |
354 session.Eval(args.query) | 361 session.Eval(args.query) |
355 else: | 362 else: |
356 logging.info('Entering interactive console.') | 363 logging.info('Entering interactive console.') |
357 session.GoInteractive() | 364 session.GoInteractive() |
OLD | NEW |