forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
binary_size_differ.py
executable file
·153 lines (134 loc) · 5.53 KB
/
binary_size_differ.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/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/40801868): 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())