154 lines
5.5 KiB
Python
Executable File
154 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env vpython3
|
|
#
|
|
# Copyright 2021 The Chromium Authors
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
'''Implements Chrome-Fuchsia package binary size differ.'''
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
import traceback
|
|
|
|
from binary_sizes import ReadPackageSizesJson
|
|
from binary_sizes import PACKAGES_SIZES_FILE
|
|
|
|
# Eng is not responsible for changes that cause "reasonable growth" if the
|
|
# uncompressed binary size does not grow.
|
|
# First-warning will fail the test if the uncompressed and compressed size
|
|
# grow, while always-fail will fail the test regardless of uncompressed growth
|
|
# (solely based on compressed growth).
|
|
_FIRST_WARNING_DELTA_BYTES = 12 * 1024 # 12 KiB
|
|
_ALWAYS_FAIL_DELTA_BYTES = 100 * 1024 # 100 KiB
|
|
_TRYBOT_DOC = 'https://chromium.googlesource.com/chromium/src/+/main/docs/speed/binary_size/fuchsia_binary_size_trybot.md'
|
|
|
|
SIZE_FAILURE = 1
|
|
ROLLER_SIZE_WARNING = 2
|
|
SUCCESS = 0
|
|
|
|
|
|
def ComputePackageDiffs(before_sizes_file, after_sizes_file, author=None):
|
|
'''Computes difference between after and before diff, for each package.'''
|
|
before_sizes = ReadPackageSizesJson(before_sizes_file)
|
|
after_sizes = ReadPackageSizesJson(after_sizes_file)
|
|
|
|
assert before_sizes.keys() == after_sizes.keys(), (
|
|
'Package files cannot'
|
|
' be compared with different packages: '
|
|
'{} vs {}'.format(before_sizes.keys(), after_sizes.keys()))
|
|
|
|
growth = {'compressed': {}, 'uncompressed': {}}
|
|
status_code = SUCCESS
|
|
summary = ''
|
|
for package_name in before_sizes:
|
|
growth['compressed'][package_name] = (after_sizes[package_name].compressed -
|
|
before_sizes[package_name].compressed)
|
|
growth['uncompressed'][package_name] = (
|
|
after_sizes[package_name].uncompressed -
|
|
before_sizes[package_name].uncompressed)
|
|
# Developers are only responsible if uncompressed increases.
|
|
if ((growth['compressed'][package_name] >= _FIRST_WARNING_DELTA_BYTES
|
|
and growth['uncompressed'][package_name] > 0)
|
|
# However, if compressed growth is unusually large, fail always.
|
|
or growth['compressed'][package_name] >= _ALWAYS_FAIL_DELTA_BYTES):
|
|
if not summary:
|
|
summary = ('Size check failed! The following package(s) are affected:'
|
|
'<br>')
|
|
status_code = SIZE_FAILURE
|
|
summary += (('- {} (compressed) grew by {} bytes (uncompressed growth:'
|
|
' {} bytes).<br>').format(
|
|
package_name, growth['compressed'][package_name],
|
|
growth['uncompressed'][package_name]))
|
|
summary += ('Note that this bot compares growth against trunk, and is '
|
|
'not aware of CL chaining.<br>')
|
|
|
|
# Allow rollers to pass even with size increases. See crbug.com/1355914.
|
|
if author and '-autoroll' in author and status_code == SIZE_FAILURE:
|
|
summary = summary.replace('Size check failed! ', '')
|
|
summary = (
|
|
'The following growth by an autoroller will be ignored:<br><br>' +
|
|
summary)
|
|
status_code = ROLLER_SIZE_WARNING
|
|
growth['status_code'] = status_code
|
|
summary += ('<br>See the following document for more information about'
|
|
' this trybot:<br>{}'.format(_TRYBOT_DOC))
|
|
growth['summary'] = summary
|
|
|
|
# TODO(crbug.com/1266085): Investigate using these fields.
|
|
growth['archive_filenames'] = []
|
|
growth['links'] = []
|
|
return growth
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
'--before-dir',
|
|
type=os.path.realpath,
|
|
required=True,
|
|
help='Location of the build without the patch',
|
|
)
|
|
parser.add_argument(
|
|
'--after-dir',
|
|
type=os.path.realpath,
|
|
required=True,
|
|
help='Location of the build with the patch',
|
|
)
|
|
parser.add_argument('--author', help='Author of change')
|
|
parser.add_argument(
|
|
'--results-path',
|
|
type=os.path.realpath,
|
|
required=True,
|
|
help='Output path for the trybot result .json file',
|
|
)
|
|
parser.add_argument('--verbose',
|
|
'-v',
|
|
action='store_true',
|
|
help='Enable verbose output')
|
|
args = parser.parse_args()
|
|
|
|
if args.verbose:
|
|
print('Fuchsia binary sizes')
|
|
print('Working directory', os.getcwd())
|
|
print('Args:')
|
|
for var in vars(args):
|
|
print(' {}: {}'.format(var, getattr(args, var) or ''))
|
|
|
|
if not os.path.isdir(args.before_dir) or not os.path.isdir(args.after_dir):
|
|
raise Exception(
|
|
'Could not find build output directory "{}" or "{}".'.format(
|
|
args.before_dir, args.after_dir))
|
|
|
|
test_name = 'sizes'
|
|
before_sizes_file = os.path.join(args.before_dir, test_name,
|
|
PACKAGES_SIZES_FILE)
|
|
after_sizes_file = os.path.join(args.after_dir, test_name,
|
|
PACKAGES_SIZES_FILE)
|
|
if not os.path.isfile(before_sizes_file):
|
|
raise Exception(
|
|
'Could not find before sizes file: "{}"'.format(before_sizes_file))
|
|
|
|
if not os.path.isfile(after_sizes_file):
|
|
raise Exception(
|
|
'Could not find after sizes file: "{}"'.format(after_sizes_file))
|
|
|
|
test_completed = False
|
|
try:
|
|
growth = ComputePackageDiffs(before_sizes_file,
|
|
after_sizes_file,
|
|
author=args.author)
|
|
test_completed = True
|
|
with open(args.results_path, 'wt') as results_file:
|
|
json.dump(growth, results_file)
|
|
except:
|
|
_, value, trace = sys.exc_info()
|
|
traceback.print_tb(trace)
|
|
print(str(value))
|
|
finally:
|
|
return 0 if test_completed else 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|