Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: scripts/slave/recipe_modules/isolate/resources/compare_build_artifacts.py

Issue 763363002: Deterministic build: Add a whitelist to the compare_build_artifact script (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Compare the artifacts from two builds.""" 6 """Compare the artifacts from two builds."""
7 7
8 import difflib 8 import difflib
9 import json 9 import json
10 import optparse 10 import optparse
11 import os 11 import os
12 import struct 12 import struct
13 import sys 13 import sys
14 import time 14 import time
15 15
16 16
17 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 17 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
18 18
19 19
20 # List of files that are known to be non deterministic. This is a temporary
21 # workaround to find regression on the deterministic builders.
22 # TODO(sebmarchand): Remove this once all the files are deterministic.
23 WHITELIST = {
24 'win': {
25 'base_unittests.exe',
26 'base_unittests.isolated',
27 'browser_tests.exe',
28 'browser_tests.isolated',
29 'chrome.dll',
30 'chrome.exe',
31 'chrome_child.dll',
32 'chrome_watcher.dll',
33 'clearkeycdm.dll',
34 'content_browsertests.exe',
35 'content_browsertests.isolated',
36 'content_unittests.exe',
37 'content_unittests.isolated',
38 'd8.exe',
39 'delegate_execute.exe',
40 'delegate_execute_unittests.exe',
41 'interactive_ui_tests.exe',
42 'interactive_ui_tests.isolated',
43 'metro_driver.dll',
44 'mock_nacl_gdb.exe',
45 'net_unittests.exe',
46 'net_unittests.isolated',
47 'npapi_test_plugin.dll',
48 'pdf.dll',
49 'peerconnection_server.exe',
50 'ppapi_nacl_tests_pnacl_newlib_x32.nexe',
51 'ppapi_nacl_tests_pnacl_newlib_x64.nexe',
52 'sync_integration_tests.exe',
53 'sync_integration_tests.isolated',
54 'test_registrar.exe',
55 'unit_tests.exe',
56 'unit_tests.isolated',
57 },
58 'linux': {
59 'browser_tests.isolated',
60 'nacl_helper_nonsfi',
61 'nacl_irt_x86_64.nexe',
62 'ppapi_nacl_tests_glibc_x64.nexe',
63 'ppapi_nacl_tests_newlib_x64.nexe',
64 'ppapi_nacl_tests_pnacl_newlib_x64.nexe',
65 'unit_tests.isolated',
66 },
67 'mac': { },
68 'android': { },
69 'ios': { },
70 }
71
20 def get_files_to_compare(build_dir, recursive=False): 72 def get_files_to_compare(build_dir, recursive=False):
21 """Get the list of files to compare.""" 73 """Get the list of files to compare."""
22 allowed = frozenset( 74 allowed = frozenset(
23 ('', '.apk', '.app', '.dll', '.dylib', '.exe', '.nexe', '.so')) 75 ('', '.apk', '.app', '.dll', '.dylib', '.exe', '.nexe', '.so'))
24 non_x_ok_exts = frozenset(('.apk', '.isolated')) 76 non_x_ok_exts = frozenset(('.apk', '.isolated'))
25 def check(f): 77 def check(f):
26 if not os.path.isfile(f): 78 if not os.path.isfile(f):
27 return False 79 return False
28 if os.path.basename(f).startswith('.'): 80 if os.path.basename(f).startswith('.'):
29 return False 81 return False
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
117 # else, falls through binary comparison, it must be binary equal too. 169 # else, falls through binary comparison, it must be binary equal too.
118 170
119 file_len = os.stat(first_filepath).st_size 171 file_len = os.stat(first_filepath).st_size
120 if file_len != os.stat(second_filepath).st_size: 172 if file_len != os.stat(second_filepath).st_size:
121 return 'different size: %d != %d' % ( 173 return 'different size: %d != %d' % (
122 file_len, os.stat(second_filepath).st_size) 174 file_len, os.stat(second_filepath).st_size)
123 175
124 return diff_binary(first_filepath, second_filepath, file_len) 176 return diff_binary(first_filepath, second_filepath, file_len)
125 177
126 178
127 def compare_build_artifacts(first_dir, second_dir, recursive=False): 179 def compare_build_artifacts(first_dir, second_dir, target_platform,
180 recursive=False):
128 """Compare the artifacts from two distinct builds.""" 181 """Compare the artifacts from two distinct builds."""
129 if not os.path.isdir(first_dir): 182 if not os.path.isdir(first_dir):
130 print >> sys.stderr, '%s isn\'t a valid directory.' % first_dir 183 print >> sys.stderr, '%s isn\'t a valid directory.' % first_dir
131 return 1 184 return 1
132 if not os.path.isdir(second_dir): 185 if not os.path.isdir(second_dir):
133 print >> sys.stderr, '%s isn\'t a valid directory.' % second_dir 186 print >> sys.stderr, '%s isn\'t a valid directory.' % second_dir
134 return 1 187 return 1
135 188
136 with open(os.path.join(BASE_DIR, 'deterministic_build_blacklist.json')) as f: 189 with open(os.path.join(BASE_DIR, 'deterministic_build_blacklist.json')) as f:
137 blacklist = frozenset(json.load(f)) 190 blacklist = frozenset(json.load(f))
138 191
139 res = 0 192 whitelist = WHITELIST[target_platform]
193
194 unexpected_failures = 0
195 expected_failures = 0
140 first_list = get_files_to_compare(first_dir, recursive) - blacklist 196 first_list = get_files_to_compare(first_dir, recursive) - blacklist
141 second_list = get_files_to_compare(second_dir, recursive) - blacklist 197 second_list = get_files_to_compare(second_dir, recursive) - blacklist
142 198
143 diff = first_list.symmetric_difference(second_list) 199 diff = first_list.symmetric_difference(second_list)
144 if diff: 200 if diff:
145 print >> sys.stderr, 'Different list of files in both directories' 201 print >> sys.stderr, 'Different list of files in both directories'
146 print >> sys.stderr, '\n'.join(' ' + i for i in sorted(diff)) 202 print >> sys.stderr, '\n'.join(' ' + i for i in sorted(diff))
147 res += len(diff) 203 unexpected_failures += len(diff)
148 204
149 epoch_hex = struct.pack('<I', int(time.time())).encode('hex') 205 epoch_hex = struct.pack('<I', int(time.time())).encode('hex')
150 print('Epoch: %s' % 206 print('Epoch: %s' %
151 ' '.join(epoch_hex[i:i+2] for i in xrange(0, len(epoch_hex), 2))) 207 ' '.join(epoch_hex[i:i+2] for i in xrange(0, len(epoch_hex), 2)))
152 max_filepath_len = max(len(n) for n in first_list & second_list) 208 max_filepath_len = max(len(n) for n in first_list & second_list)
153 for f in sorted(first_list & second_list): 209 for f in sorted(first_list & second_list):
154 first_file = os.path.join(first_dir, f) 210 first_file = os.path.join(first_dir, f)
155 second_file = os.path.join(second_dir, f) 211 second_file = os.path.join(second_dir, f)
156 result = compare_files(first_file, second_file) 212 result = compare_files(first_file, second_file)
157 if not result: 213 if not result:
158 result = 'equal' 214 result = 'equal'
159 else: 215 else:
160 result = 'DIFFERENT: %s' % result 216 expected = 'unexpected'
161 res += 1 217 if f in whitelist:
218 expected_failures += 1
219 expected = 'expected'
220 else:
221 unexpected_failures += 1
222 result = 'DIFFERENT (%s): %s' % (expected, result)
162 print('%-*s: %s' % (max_filepath_len, f, result)) 223 print('%-*s: %s' % (max_filepath_len, f, result))
163 224
164 print '%d files are equal, %d are different.' % ( 225 print '%d files are equal, %d are different.' % (
165 len(first_list & second_list) - res, res) 226 len(first_list & second_list) - expected_failures - unexpected_failures,
227 expected_failures + unexpected_failures)
166 228
167 return 0 if res == 0 else 1 229 return 0 if unexpected_failures == 0 else 1
168 230
169 231
170 def main(): 232 def main():
171 parser = optparse.OptionParser(usage='%prog [options]') 233 parser = optparse.OptionParser(usage='%prog [options]')
172 parser.add_option( 234 parser.add_option(
173 '-f', '--first-build-dir', help='The first build directory.') 235 '-f', '--first-build-dir', help='The first build directory.')
174 parser.add_option( 236 parser.add_option(
175 '-s', '--second-build-dir', help='The second build directory.') 237 '-s', '--second-build-dir', help='The second build directory.')
176 parser.add_option('-r', '--recursive', action='store_true', default=False, 238 parser.add_option('-r', '--recursive', action='store_true', default=False,
177 help='Indicates if the comparison should be recursive.') 239 help='Indicates if the comparison should be recursive.')
240 parser.add_option('-t', '--target-platform', help='The target platform.')
178 options, _ = parser.parse_args() 241 options, _ = parser.parse_args()
179 242
180 if not options.first_build_dir: 243 if not options.first_build_dir:
181 parser.error('--first-build-dir is required') 244 parser.error('--first-build-dir is required')
182 if not options.second_build_dir: 245 if not options.second_build_dir:
183 parser.error('--second-build-dir is required') 246 parser.error('--second-build-dir is required')
247 if not options.target_platform:
248 parser.error('--target-platform is required')
184 249
185 return compare_build_artifacts(os.path.abspath(options.first_build_dir), 250 return compare_build_artifacts(os.path.abspath(options.first_build_dir),
186 os.path.abspath(options.second_build_dir), 251 os.path.abspath(options.second_build_dir),
252 options.target_platform,
187 options.recursive) 253 options.recursive)
188 254
189 255
190 if __name__ == '__main__': 256 if __name__ == '__main__':
191 sys.exit(main()) 257 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698