tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

binary_size_differ.py (5667B)


      1 #!/usr/bin/env vpython3
      2 #
      3 # Copyright 2021 The Chromium Authors
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 '''Implements Chrome-Fuchsia package binary size differ.'''
      7 
      8 import argparse
      9 import json
     10 import os
     11 import sys
     12 import traceback
     13 
     14 from binary_sizes import ReadPackageSizesJson
     15 from binary_sizes import PACKAGES_SIZES_FILE
     16 
     17 # Eng is not responsible for changes that cause "reasonable growth" if the
     18 # uncompressed binary size does not grow.
     19 # First-warning will fail the test if the uncompressed and compressed size
     20 # grow, while always-fail will fail the test regardless of uncompressed growth
     21 # (solely based on compressed growth).
     22 _FIRST_WARNING_DELTA_BYTES = 12 * 1024  # 12 KiB
     23 _ALWAYS_FAIL_DELTA_BYTES = 100 * 1024  # 100 KiB
     24 _TRYBOT_DOC = 'https://chromium.googlesource.com/chromium/src/+/main/docs/speed/binary_size/fuchsia_binary_size_trybot.md'
     25 
     26 SIZE_FAILURE = 1
     27 ROLLER_SIZE_WARNING = 2
     28 SUCCESS = 0
     29 
     30 
     31 def ComputePackageDiffs(before_sizes_file, after_sizes_file, author=None):
     32  '''Computes difference between after and before diff, for each package.'''
     33  before_sizes = ReadPackageSizesJson(before_sizes_file)
     34  after_sizes = ReadPackageSizesJson(after_sizes_file)
     35 
     36  assert before_sizes.keys() == after_sizes.keys(), (
     37      'Package files cannot'
     38      ' be compared with different packages: '
     39      '{} vs {}'.format(before_sizes.keys(), after_sizes.keys()))
     40 
     41  growth = {'compressed': {}, 'uncompressed': {}}
     42  status_code = SUCCESS
     43  summary = ''
     44  for package_name in before_sizes:
     45    growth['compressed'][package_name] = (after_sizes[package_name].compressed -
     46                                          before_sizes[package_name].compressed)
     47    growth['uncompressed'][package_name] = (
     48        after_sizes[package_name].uncompressed -
     49        before_sizes[package_name].uncompressed)
     50    # Developers are only responsible if uncompressed increases.
     51    if ((growth['compressed'][package_name] >= _FIRST_WARNING_DELTA_BYTES
     52         and growth['uncompressed'][package_name] > 0)
     53        # However, if compressed growth is unusually large, fail always.
     54        or growth['compressed'][package_name] >= _ALWAYS_FAIL_DELTA_BYTES):
     55      if not summary:
     56        summary = ('Size check failed! The following package(s) are affected:'
     57                   '<br>')
     58      status_code = SIZE_FAILURE
     59      summary += (('- {} (compressed) grew by {} bytes (uncompressed growth:'
     60                   ' {} bytes).<br>').format(
     61                       package_name, growth['compressed'][package_name],
     62                       growth['uncompressed'][package_name]))
     63      summary += ('Note that this bot compares growth against trunk, and is '
     64                  'not aware of CL chaining.<br>')
     65 
     66  # Allow rollers to pass even with size increases. See crbug.com/1355914.
     67  if author and '-autoroll' in author and status_code == SIZE_FAILURE:
     68    summary = summary.replace('Size check failed! ', '')
     69    summary = (
     70        'The following growth by an autoroller will be ignored:<br><br>' +
     71        summary)
     72    status_code = ROLLER_SIZE_WARNING
     73  growth['status_code'] = status_code
     74  summary += ('<br>See the following document for more information about'
     75              ' this trybot:<br>{}'.format(_TRYBOT_DOC))
     76  growth['summary'] = summary
     77 
     78  # TODO(crbug.com/40801868): Investigate using these fields.
     79  growth['archive_filenames'] = []
     80  growth['links'] = []
     81  return growth
     82 
     83 
     84 def main():
     85  parser = argparse.ArgumentParser()
     86  parser.add_argument(
     87      '--before-dir',
     88      type=os.path.realpath,
     89      required=True,
     90      help='Location of the build without the patch',
     91  )
     92  parser.add_argument(
     93      '--after-dir',
     94      type=os.path.realpath,
     95      required=True,
     96      help='Location of the build with the patch',
     97  )
     98  parser.add_argument('--author', help='Author of change')
     99  parser.add_argument(
    100      '--results-path',
    101      type=os.path.realpath,
    102      required=True,
    103      help='Output path for the trybot result .json file',
    104  )
    105  parser.add_argument('--verbose',
    106                      '-v',
    107                      action='store_true',
    108                      help='Enable verbose output')
    109  args = parser.parse_args()
    110 
    111  if args.verbose:
    112    print('Fuchsia binary sizes')
    113    print('Working directory', os.getcwd())
    114    print('Args:')
    115    for var in vars(args):
    116      print('  {}: {}'.format(var, getattr(args, var) or ''))
    117 
    118  if not os.path.isdir(args.before_dir) or not os.path.isdir(args.after_dir):
    119    raise Exception(
    120        'Could not find build output directory "{}" or "{}".'.format(
    121            args.before_dir, args.after_dir))
    122 
    123  test_name = 'sizes'
    124  before_sizes_file = os.path.join(args.before_dir, test_name,
    125                                   PACKAGES_SIZES_FILE)
    126  after_sizes_file = os.path.join(args.after_dir, test_name,
    127                                  PACKAGES_SIZES_FILE)
    128  if not os.path.isfile(before_sizes_file):
    129    raise Exception(
    130        'Could not find before sizes file: "{}"'.format(before_sizes_file))
    131 
    132  if not os.path.isfile(after_sizes_file):
    133    raise Exception(
    134        'Could not find after sizes file: "{}"'.format(after_sizes_file))
    135 
    136  test_completed = False
    137  try:
    138    growth = ComputePackageDiffs(before_sizes_file,
    139                                 after_sizes_file,
    140                                 author=args.author)
    141    test_completed = True
    142    with open(args.results_path, 'wt') as results_file:
    143      json.dump(growth, results_file)
    144  except:
    145    _, value, trace = sys.exc_info()
    146    traceback.print_tb(trace)
    147    print(str(value))
    148  finally:
    149    return 0 if test_completed else 1
    150 
    151 
    152 if __name__ == '__main__':
    153  sys.exit(main())