Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(249)

Side by Side Diff: tools/binary_size/libsupersize/console.py

Issue 2864063002: Supersize: Chrome-specific breakdowns, console tweaks (Closed)
Patch Set: review tweaks Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
11 import itertools 11 import itertools
12 import logging 12 import logging
13 import os 13 import os
14 import readline 14 import readline
15 import subprocess 15 import subprocess
16 import sys 16 import sys
17 17
18 import archive 18 import archive
19 import canned_queries
19 import describe 20 import describe
20 import diff 21 import diff
21 import file_format 22 import file_format
22 import match_util 23 import match_util
23 import models 24 import models
24 import paths 25 import paths
25 26
26 27
27 # Number of lines before using less for Print(). 28 # Number of lines before using less for Print().
28 _THRESHOLD_FOR_PAGER = 30 29 _THRESHOLD_FOR_PAGER = 50
29 30
30 31
31 @contextlib.contextmanager 32 @contextlib.contextmanager
32 def _LessPipe(): 33 def _LessPipe():
33 """Output to `less`. Yields a file object to write to.""" 34 """Output to `less`. Yields a file object to write to."""
34 try: 35 try:
35 proc = subprocess.Popen(['less'], stdin=subprocess.PIPE, stdout=sys.stdout) 36 proc = subprocess.Popen(['less'], stdin=subprocess.PIPE, stdout=sys.stdout)
36 yield proc.stdin 37 yield proc.stdin
37 proc.stdin.close() 38 proc.stdin.close()
38 proc.wait() 39 proc.wait()
(...skipping 22 matching lines...) Expand all
61 else: 62 else:
62 describe.WriteLines(lines, sys.stdout.write) 63 describe.WriteLines(lines, sys.stdout.write)
63 64
64 65
65 class _Session(object): 66 class _Session(object):
66 _readline_initialized = False 67 _readline_initialized = False
67 68
68 def __init__(self, size_infos, lazy_paths): 69 def __init__(self, size_infos, lazy_paths):
69 self._variables = { 70 self._variables = {
70 'Print': self._PrintFunc, 71 'Print': self._PrintFunc,
71 'Diff': diff.Diff, 72 'Diff': self._DiffFunc,
72 'Disassemble': self._DisassembleFunc, 73 'Disassemble': self._DisassembleFunc,
73 'ExpandRegex': match_util.ExpandRegexIdentifierPlaceholder, 74 'ExpandRegex': match_util.ExpandRegexIdentifierPlaceholder,
74 'ShowExamples': self._ShowExamplesFunc, 75 'ShowExamples': self._ShowExamplesFunc,
76 'canned_queries': canned_queries.CannedQueries(size_infos),
75 } 77 }
76 self._lazy_paths = lazy_paths 78 self._lazy_paths = lazy_paths
77 self._size_infos = size_infos 79 self._size_infos = size_infos
78 80
79 if len(size_infos) == 1: 81 if len(size_infos) == 1:
80 self._variables['size_info'] = size_infos[0] 82 self._variables['size_info'] = size_infos[0]
81 else: 83 else:
82 for i, size_info in enumerate(size_infos): 84 for i, size_info in enumerate(size_infos):
83 self._variables['size_info%d' % (i + 1)] = size_info 85 self._variables['size_info%d' % (i + 1)] = size_info
84 86
85 def _PrintFunc(self, obj, verbose=False, recursive=False, use_pager=None, 87 def _DiffFunc(self, before=None, after=None, cluster=True):
88 """Diffs two SizeInfo objects. Returns a SizeInfoDiff.
89
90 Args:
91 before: Defaults to first size_infos[0].
92 after: Defaults to second size_infos[1].
93 cluster: When True, calls SymbolGroup.Cluster() after diffing. This
94 generally reduces noise.
95 """
96 before = before if before is not None else self._size_infos[0]
97 after = after if after is not None else self._size_infos[1]
98 return diff.Diff(before, after, cluster=cluster)
99
100 def _PrintFunc(self, obj=None, verbose=False, recursive=False, use_pager=None,
86 to_file=None): 101 to_file=None):
87 """Prints out the given Symbol / SymbolGroup / SymbolDiff / SizeInfo. 102 """Prints out the given Symbol / SymbolGroup / SymbolDiff / SizeInfo.
88 103
89 Args: 104 Args:
90 obj: The object to be printed. 105 obj: The object to be printed. Defaults to size_infos[-1].
91 verbose: Show more detailed output. 106 verbose: Show more detailed output.
92 recursive: Print children of nested SymbolGroups. 107 recursive: Print children of nested SymbolGroups.
93 use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol. 108 use_pager: Pipe output through `less`. Ignored when |obj| is a Symbol.
94 default is to automatically pipe when output is long. 109 default is to automatically pipe when output is long.
95 to_file: Rather than print to stdio, write to the given file. 110 to_file: Rather than print to stdio, write to the given file.
96 """ 111 """
112 obj = obj if obj is not None else self._size_infos[-1]
97 lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive) 113 lines = describe.GenerateLines(obj, verbose=verbose, recursive=recursive)
98 _WriteToStream(lines, use_pager=use_pager, to_file=to_file) 114 _WriteToStream(lines, use_pager=use_pager, to_file=to_file)
99 115
100 def _ElfPathForSymbol(self, symbol): 116 def _ElfPathForSymbol(self, symbol):
101 size_info = None 117 size_info = None
102 for size_info in self._size_infos: 118 for size_info in self._size_infos:
103 if symbol in size_info.symbols: 119 if symbol in size_info.symbols:
104 break 120 break
105 else: 121 else:
106 assert False, 'Symbol does not belong to a size_info.' 122 assert False, 'Symbol does not belong to a size_info.'
(...skipping 26 matching lines...) Expand all
133 '--start-address=0x%x' % symbol.address, 149 '--start-address=0x%x' % symbol.address,
134 '--stop-address=0x%x' % symbol.end_address, elf_path] 150 '--stop-address=0x%x' % symbol.end_address, elf_path]
135 proc = subprocess.Popen(args, stdout=subprocess.PIPE) 151 proc = subprocess.Popen(args, stdout=subprocess.PIPE)
136 lines = itertools.chain(('Showing disassembly for %r' % symbol, 152 lines = itertools.chain(('Showing disassembly for %r' % symbol,
137 'Command: %s' % ' '.join(args)), 153 'Command: %s' % ' '.join(args)),
138 (l.rstrip() for l in proc.stdout)) 154 (l.rstrip() for l in proc.stdout))
139 _WriteToStream(lines, use_pager=use_pager, to_file=to_file) 155 _WriteToStream(lines, use_pager=use_pager, to_file=to_file)
140 proc.kill() 156 proc.kill()
141 157
142 def _ShowExamplesFunc(self): 158 def _ShowExamplesFunc(self):
159 print self._CreateBanner()
143 print '\n'.join([ 160 print '\n'.join([
144 '# Show pydoc for main types:', 161 '# Show pydoc for main types:',
145 'import models', 162 'import models',
146 'help(models)', 163 'help(models)',
147 '', 164 '',
148 '# Show all attributes of all symbols & per-section totals:', 165 '# Show all attributes of all symbols & per-section totals:',
149 'Print(size_info, verbose=True)', 166 'Print(size_info, verbose=True)',
150 '', 167 '',
151 '# Show two levels of .text, grouped by first two subdirectories', 168 '# Show two levels of .text, grouped by first two subdirectories',
152 'text_syms = size_info.symbols.WhereInSection("t")', 169 'text_syms = size_info.symbols.WhereInSection("t")',
153 'by_path = text_syms.GroupBySourcePath(depth=2)', 170 'by_path = text_syms.GroupByPath(depth=2)',
154 'Print(by_path.WhereBiggerThan(1024))', 171 'Print(by_path.WhereBiggerThan(1024))',
155 '', 172 '',
156 '# Show all non-vtable generated symbols', 173 '# Show all non-vtable generated symbols',
157 'generated_syms = size_info.symbols.WhereGeneratedByToolchain()', 174 'generated_syms = size_info.symbols.WhereGeneratedByToolchain()',
158 'Print(generated_syms.WhereNameMatches(r"vtable").Inverted().Sorted())', 175 'Print(generated_syms.WhereNameMatches(r"vtable").Inverted().Sorted())',
159 '', 176 '',
160 '# Show all symbols that have "print" in their name or path, except', 177 '# Show all symbols that have "print" in their name or path, except',
161 '# those within components/.', 178 '# those within components/.',
162 '# Note: Could have also used Inverted(), as above.', 179 '# Note: Could have also used Inverted(), as above.',
163 '# Note: Use "help(ExpandRegex)" for more about what {{_print_}} does.', 180 '# Note: Use "help(ExpandRegex)" for more about what {{_print_}} does.',
164 'print_syms = size_info.symbols.WhereMatches(r"{{_print_}}")', 181 'print_syms = size_info.symbols.WhereMatches(r"{{_print_}}")',
165 'Print(print_syms - print_syms.WherePathMatches(r"^components/"))', 182 'Print(print_syms - print_syms.WherePathMatches(r"^components/"))',
166 '', 183 '',
167 '# Diff two .size files and save result to a file:', 184 '# Diff two .size files and save result to a file:',
168 'Print(Diff(size_info1, size_info2), to_file="output.txt")', 185 'Print(Diff(size_info1, size_info2), to_file="output.txt")',
169 '', 186 '',
187 '# View per-component breakdowns, then drill into the last entry.',
188 'c = canned_queries.CategorizeByChromeComponent()',
189 'Print(c)',
190 'Print(c[-1].GroupByPath(depth=2).Sorted())',
191 '',
192 '# For even more inspiration, look at canned_queries.py',
193 '# (and feel free to add your own!).',
170 ]) 194 ])
171 195
172 def _CreateBanner(self): 196 def _CreateBanner(self):
173 symbol_info_keys = sorted(m for m in dir(models.SizeInfo) if m[0] != '_') 197 symbol_info_keys = sorted(m for m in dir(models.SizeInfo) if m[0] != '_')
174 symbol_keys = sorted(m for m in dir(models.Symbol) if m[0] != '_') 198 symbol_keys = sorted(m for m in dir(models.Symbol) if m[0] != '_')
175 symbol_group_keys = [m for m in dir(models.SymbolGroup) if m[0] != '_'] 199 symbol_group_keys = [m for m in dir(models.SymbolGroup) if m[0] != '_']
176 symbol_diff_keys = sorted(m for m in dir(models.SymbolDiff) 200 symbol_diff_keys = sorted(m for m in dir(models.SymbolDiff)
177 if m[0] != '_' and m not in symbol_group_keys) 201 if m[0] != '_' and m not in symbol_group_keys)
178 symbol_group_keys = sorted(m for m in symbol_group_keys 202 symbol_group_keys = sorted(m for m in symbol_group_keys
179 if m not in symbol_keys) 203 if m not in symbol_keys)
204 canned_queries_keys = sorted(m for m in dir(canned_queries.CannedQueries)
205 if m[0] != '_')
180 functions = sorted(k for k in self._variables if k[0].isupper()) 206 functions = sorted(k for k in self._variables if k[0].isupper())
181 variables = sorted(k for k in self._variables if k[0].islower()) 207 variables = sorted(k for k in self._variables if k[0].islower())
182 return '\n'.join([ 208 return '\n'.join([
183 '*' * 80, 209 '*' * 80,
184 'Entering interactive Python shell. Quick reference:', 210 'Entering interactive Python shell. Quick reference:',
185 '', 211 '',
186 'SizeInfo: %s' % ', '.join(symbol_info_keys), 212 'SizeInfo: %s' % ', '.join(symbol_info_keys),
187 'Symbol: %s' % ', '.join(symbol_keys), 213 'Symbol: %s' % ', '.join(symbol_keys),
214 '',
188 'SymbolGroup (extends Symbol): %s' % ', '.join(symbol_group_keys), 215 'SymbolGroup (extends Symbol): %s' % ', '.join(symbol_group_keys),
216 '',
189 'SymbolDiff (extends SymbolGroup): %s' % ', '.join(symbol_diff_keys), 217 'SymbolDiff (extends SymbolGroup): %s' % ', '.join(symbol_diff_keys),
190 '', 218 '',
219 'canned_queries: %s' % ', '.join(canned_queries_keys),
220 '',
191 'Functions: %s' % ', '.join('%s()' % f for f in functions), 221 'Functions: %s' % ', '.join('%s()' % f for f in functions),
192 'Variables: %s' % ', '.join(variables), 222 'Variables: %s' % ', '.join(variables),
193 '*' * 80, 223 '*' * 80,
194 ]) 224 ])
195 225
196 @classmethod 226 @classmethod
197 def _InitReadline(cls): 227 def _InitReadline(cls):
198 if cls._readline_initialized: 228 if cls._readline_initialized:
199 return 229 return
200 cls._readline_initialized = True 230 cls._readline_initialized = True
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 output_directory=args.output_directory, 271 output_directory=args.output_directory,
242 any_path_within_output_directory=args.inputs[0]) 272 any_path_within_output_directory=args.inputs[0])
243 session = _Session(size_infos, lazy_paths) 273 session = _Session(size_infos, lazy_paths)
244 274
245 if args.query: 275 if args.query:
246 logging.info('Running query from command-line.') 276 logging.info('Running query from command-line.')
247 session.Eval(args.query) 277 session.Eval(args.query)
248 else: 278 else:
249 logging.info('Entering interactive console.') 279 logging.info('Entering interactive console.')
250 session.GoInteractive() 280 session.GoInteractive()
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/canned_queries.py ('k') | tools/binary_size/libsupersize/describe.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698