| #!/usr/bin/env python3 |
| # Copyright (C) 2021 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """ |
| Generate a size report for target binaries. |
| |
| For example: |
| $ tools/ninja -C out/r traced_probes traced |
| $ tools/size-report.py -C out/r traced_probes traced |
| """ |
| |
| from __future__ import absolute_import |
| from __future__ import division |
| from __future__ import print_function |
| |
| import argparse |
| import os |
| import subprocess |
| import sys |
| import json |
| |
| ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| BLOATY_PATH = os.path.join(ROOT_DIR, 'buildtools', 'bloaty', 'bloaty') |
| GN_PATH = os.path.join(ROOT_DIR, 'tools', 'gn') |
| |
| def GetGnArgValueOrNone(arg): |
| if 'current' in arg: |
| return eval(arg['current']['value']) |
| if 'default' in arg: |
| return eval(arg['default']['value']) |
| return None |
| |
| |
| def GetTargetOsForBuildDir(build_dir): |
| cmd = [GN_PATH, 'args', '--list', '--json', build_dir] |
| args = json.loads(subprocess.check_output(cmd)) |
| target_os = None |
| host_os = None |
| for arg in args: |
| if arg['name'] == 'target_os': |
| print(arg) |
| target_os = GetGnArgValueOrNone(arg) |
| if arg['name'] == 'host_os': |
| print(arg) |
| host_os = GetGnArgValueOrNone(arg) |
| return target_os or host_os or None |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser( |
| formatter_class=argparse.RawDescriptionHelpFormatter, description=__doc__) |
| parser.add_argument( |
| '-C', '--build-dir', metavar='DIR', help='build directory', required=True) |
| parser.add_argument('-o', '--output', help='output path', default=None) |
| parser.add_argument( |
| 'binaries', metavar='BINARY', nargs='+', help='subjects of size report') |
| args = parser.parse_args() |
| |
| if not os.path.exists(BLOATY_PATH): |
| print( |
| 'Could not find bloaty at expected path "{}". Try re-running ./tools/install-build-deps' |
| .format(BLOATY_PATH)) |
| return 1 |
| |
| results = [] |
| |
| out_directory = args.build_dir |
| target_os = GetTargetOsForBuildDir(out_directory) |
| print('target_os', target_os) |
| for binary in args.binaries: |
| binary_path = os.path.join(out_directory, binary) |
| output = '{} - {}\n'.format(binary, binary_path) |
| if target_os == 'mac': |
| subprocess.check_output(['dsymutil', binary_path]) |
| symbols = '--debug-file={}.dSYM/Contents/Resources/DWARF/{}'.format( |
| binary_path, binary) |
| cmd = [symbols, '-d', 'compileunits', '-n', '100', binary_path] |
| else: |
| cmd = ['-d', 'compileunits', '-n', '100', binary_path] |
| output += subprocess.check_output([BLOATY_PATH] + cmd).decode('utf-8') |
| results.append(output) |
| |
| if args.output is None or args.output == '-': |
| out = sys.stdout |
| else: |
| out = open(args.output, 'w') |
| |
| for result in results: |
| out.write(result) |
| out.write('\n') |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |