| Index: tools/binary_size/console.py
|
| diff --git a/tools/binary_size/console.py b/tools/binary_size/console.py
|
| deleted file mode 100755
|
| index a2353a0c387afa31e3fccf3cd4ad7f81601932e3..0000000000000000000000000000000000000000
|
| --- a/tools/binary_size/console.py
|
| +++ /dev/null
|
| @@ -1,189 +0,0 @@
|
| -#!/usr/bin/env python
|
| -# Copyright 2017 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Tool for analyzing binary size of executables using nm or linker map files.
|
| -
|
| -Map files can be created by passing "-Map Foo.map" to the linker. If a map file
|
| -is unavailable, this tool can also be pointed at an unstripped executable, but
|
| -the information does not seem to be as accurate in this case.
|
| -
|
| -Inspired by SymbolSort for Windows:
|
| - https://github.com/adrianstone55/SymbolSort
|
| -"""
|
| -
|
| -import argparse
|
| -import atexit
|
| -import code
|
| -import contextlib
|
| -import itertools
|
| -import logging
|
| -import os
|
| -import readline
|
| -import subprocess
|
| -import sys
|
| -
|
| -import describe
|
| -import file_format
|
| -import helpers
|
| -import map2size
|
| -import models
|
| -
|
| -
|
| -# Number of lines before using less for Print().
|
| -_THRESHOLD_FOR_PAGER = 30
|
| -
|
| -
|
| -@contextlib.contextmanager
|
| -def _LessPipe():
|
| - """Output to `less`. Yields a file object to write to."""
|
| - try:
|
| - proc = subprocess.Popen(['less'], stdin=subprocess.PIPE, stdout=sys.stdout)
|
| - yield proc.stdin
|
| - proc.stdin.close()
|
| -
|
| - proc.wait()
|
| - except IOError:
|
| - pass # Happens when less is quit before all data is written.
|
| - except KeyboardInterrupt:
|
| - pass # Assume used to break out of less.
|
| -
|
| -
|
| -class _Session(object):
|
| - _readline_initialized = False
|
| -
|
| - def __init__(self, extra_vars):
|
| - self._variables = {
|
| - 'Print': self._PrintFunc,
|
| - 'Write': self._WriteFunc,
|
| - 'Diff': models.Diff,
|
| - }
|
| - self._variables.update(extra_vars)
|
| -
|
| - def _PrintFunc(self, obj, verbose=False, use_pager=None):
|
| - """Prints out the given Symbol / SymbolGroup / SymbolDiff / SizeInfo.
|
| -
|
| - Args:
|
| - obj: The object to be printed.
|
| - use_pager: Whether to pipe output through `less`. Ignored when |obj| is a
|
| - Symbol.
|
| - """
|
| - lines = describe.GenerateLines(obj, verbose=verbose)
|
| - if use_pager is None and sys.stdout.isatty():
|
| - # Does not take into account line-wrapping... Oh well.
|
| - first_lines = list(itertools.islice(lines, _THRESHOLD_FOR_PAGER))
|
| - if len(first_lines) == _THRESHOLD_FOR_PAGER:
|
| - use_pager = True
|
| - lines = itertools.chain(first_lines, lines)
|
| -
|
| - if use_pager:
|
| - with _LessPipe() as stdin:
|
| - describe.WriteLines(lines, stdin.write)
|
| - else:
|
| - describe.WriteLines(lines, sys.stdout.write)
|
| -
|
| -
|
| - def _WriteFunc(self, obj, path, verbose=False):
|
| - """Same as Print(), but writes to a file.
|
| -
|
| - Example: Write(Diff(size_info2, size_info1), 'output.txt')
|
| - """
|
| - parent_dir = os.path.dirname(path)
|
| - if parent_dir and not os.path.exists(parent_dir):
|
| - os.makedirs(parent_dir)
|
| - with file_format.OpenMaybeGz(path, 'w') as file_obj:
|
| - lines = describe.GenerateLines(obj, verbose=verbose)
|
| - describe.WriteLines(lines, file_obj.write)
|
| -
|
| -
|
| - def _CreateBanner(self):
|
| - symbol_info_keys = sorted(m for m in dir(models.SizeInfo) if m[0] != '_')
|
| - symbol_group_keys = sorted(m for m in dir(models.SymbolGroup)
|
| - if m[0] != '_')
|
| - symbol_diff_keys = sorted(m for m in dir(models.SymbolDiff)
|
| - if m[0] != '_' and m not in symbol_group_keys)
|
| - functions = sorted(k for k in self._variables if k[0].isupper())
|
| - variables = sorted(k for k in self._variables if k[0].islower())
|
| - return '\n'.join([
|
| - '*' * 80,
|
| - 'Entering interactive Python shell. Here is some inspiration:',
|
| - '',
|
| - '# Show pydoc for main types:',
|
| - 'import models',
|
| - 'help(models)',
|
| - '',
|
| - '# Show two levels of .text, grouped by first two subdirectories',
|
| - 'text_syms = size_info1.symbols.WhereInSection("t")',
|
| - 'by_path = text_syms.GroupByPath(depth=2)',
|
| - 'Print(by_path.WhereBiggerThan(1024))',
|
| - '',
|
| - '# Show all non-vtable generated symbols',
|
| - 'generated_syms = size_info1.symbols.WhereIsGenerated()',
|
| - 'Print(generated_syms.WhereNameMatches("vtable").Inverted())',
|
| - '',
|
| - '*' * 80,
|
| - 'Here is some quick reference:',
|
| - '',
|
| - 'SizeInfo: %s' % ', '.join(symbol_info_keys),
|
| - 'SymbolGroup: %s' % ', '.join(symbol_group_keys),
|
| - 'SymbolDiff (extends SymbolGroup): %s' % ', '.join(symbol_diff_keys),
|
| - '',
|
| - 'Functions: %s' % ', '.join('%s()' % f for f in functions),
|
| - 'Variables: %s' % ', '.join(variables),
|
| - '',
|
| - ])
|
| -
|
| - @classmethod
|
| - def _InitReadline(cls):
|
| - if cls._readline_initialized:
|
| - return
|
| - cls._readline_initialized = True
|
| - # Without initializing readline, arrow keys don't even work!
|
| - readline.parse_and_bind('tab: complete')
|
| - history_file = os.path.join(os.path.expanduser('~'),
|
| - '.binary_size_query_history')
|
| - if os.path.exists(history_file):
|
| - readline.read_history_file(history_file)
|
| - atexit.register(lambda: readline.write_history_file(history_file))
|
| -
|
| - def Eval(self, query):
|
| - eval_result = eval(query, self._variables)
|
| - if eval_result:
|
| - self._PrintFunc(eval_result)
|
| -
|
| - def GoInteractive(self):
|
| - _Session._InitReadline()
|
| - code.InteractiveConsole(self._variables).interact(self._CreateBanner())
|
| -
|
| -
|
| -def main(argv):
|
| - parser = argparse.ArgumentParser()
|
| - parser.add_argument('inputs', nargs='*',
|
| - help='Input .size/.map files to load. They will be '
|
| - 'mapped to variables as: size_info1, size_info2,'
|
| - ' etc.')
|
| - parser.add_argument('--query',
|
| - help='Print the result of the given snippet. Example: '
|
| - 'size_info1.symbols.WhereInSection("d").'
|
| - 'WhereBiggerThan(100)')
|
| - map2size.AddOptions(parser)
|
| - args = helpers.AddCommonOptionsAndParseArgs(parser, argv)
|
| -
|
| - info_variables = {}
|
| - for i, path in enumerate(args.inputs):
|
| - size_info = map2size.AnalyzeWithArgs(args, path)
|
| - info_variables['size_info%d' % (i + 1)] = size_info
|
| -
|
| - session = _Session(info_variables)
|
| -
|
| - if args.query:
|
| - logging.info('Running query from command-line.')
|
| - session.Eval(args.query)
|
| - else:
|
| - logging.info('Entering interactive console.')
|
| - session.GoInteractive()
|
| -
|
| -
|
| -if __name__ == '__main__':
|
| - sys.exit(main(sys.argv))
|
|
|