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

Side by Side Diff: trunk/tools/rebaseline.py

Issue 23120002: Remove base-* directories from gm expected/actual paths; just use platform names (Closed) Base URL: http://skia.googlecode.com/svn/
Patch Set: Created 7 years, 4 months 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 | Annotate | Revision Log
OLDNEW
1 #!/usr/bin/python 1 #!/usr/bin/python
2 2
3 ''' 3 '''
4 Copyright 2012 Google Inc. 4 Copyright 2012 Google Inc.
5 5
6 Use of this source code is governed by a BSD-style license that can be 6 Use of this source code is governed by a BSD-style license that can be
7 found in the LICENSE file. 7 found in the LICENSE file.
8 ''' 8 '''
9 9
10 ''' 10 '''
(...skipping 18 matching lines...) Expand all
29 # 29 #
30 # This assumes that the 'gm' directory has been checked out as a sibling of 30 # This assumes that the 'gm' directory has been checked out as a sibling of
31 # the 'tools' directory containing this script, which will be the case if 31 # the 'tools' directory containing this script, which will be the case if
32 # 'trunk' was checked out as a single unit. 32 # 'trunk' was checked out as a single unit.
33 GM_DIRECTORY = os.path.realpath( 33 GM_DIRECTORY = os.path.realpath(
34 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm')) 34 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm'))
35 if GM_DIRECTORY not in sys.path: 35 if GM_DIRECTORY not in sys.path:
36 sys.path.append(GM_DIRECTORY) 36 sys.path.append(GM_DIRECTORY)
37 import gm_json 37 import gm_json
38 38
39 # Mapping of expectations/gm subdir (under 39 # Full list of builder names (under
40 # https://skia.googlecode.com/svn/trunk/expectations/gm/ ) 40 # https://skia.googlecode.com/svn/trunk/expectations/gm/ ,
41 # to builder name (see list at http://108.170.217.252:10117/builders ) 41 # which should match the list at http://108.170.217.252:10117/builders )
42 SUBDIR_MAPPING = { 42 #
43 'base-shuttle-win7-intel-float': 43 # TODO(epoger): Generate this list automatically.
rmistry 2013/08/14 12:28:05 This should be very easy to do (you could add it t
borenet 2013/08/14 12:57:48 +1. We need to get rid of the handwritten list AS
epoger 2013/08/16 20:16:25 Wow, that's pretty cool. Thanks! Done. (You'll
44 BUILDERS_LIST = [
45 'Test-Android-GalaxyNexus-SGX540-Arm7-Debug',
epoger 2013/08/13 19:59:37 Patchset 1 updates rebaseline.py to use builder na
46 'Test-Android-GalaxyNexus-SGX540-Arm7-Release',
47 'Test-Android-Nexus10-MaliT604-Arm7-Debug',
48 'Test-Android-Nexus10-MaliT604-Arm7-Release',
49 'Test-Android-Nexus4-Adreno320-Arm7-Debug',
50 'Test-Android-Nexus4-Adreno320-Arm7-Release',
51 'Test-Android-Nexus7-Tegra3-Arm7-Debug',
52 'Test-Android-Nexus7-Tegra3-Arm7-Release',
53 'Test-Android-NexusS-SGX540-Arm7-Debug',
54 'Test-Android-NexusS-SGX540-Arm7-Release',
55 'Test-Android-RazrI-SGX540-x86-Debug',
56 'Test-Android-RazrI-SGX540-x86-Release',
57 'Test-Android-Xoom-Tegra2-Arm7-Debug',
58 'Test-Android-Xoom-Tegra2-Arm7-Release',
59 'Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug',
60 'Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release',
61 'Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug',
62 'Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release',
63 'Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug',
64 'Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release',
65 'Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug',
66 'Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release',
67 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug',
68 'Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release',
69 'Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug',
70 'Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release',
71 'Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug',
72 'Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release',
73 'Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug',
74 'Test-Ubuntu12-ShuttleA-ATI5770-x86-Release',
75 'Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug',
76 'Test-Win7-ShuttleA-HD2000-x86_64-Debug',
77 'Test-Win7-ShuttleA-HD2000-x86_64-Release',
78 'Test-Win7-ShuttleA-HD2000-x86-Debug',
79 'Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE',
80 'Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite',
44 'Test-Win7-ShuttleA-HD2000-x86-Release', 81 'Test-Win7-ShuttleA-HD2000-x86-Release',
45 'base-shuttle-win7-intel-angle':
46 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE', 82 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE',
47 'base-shuttle-win7-intel-directwrite':
48 'Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite', 83 'Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite',
49 'base-shuttle_ubuntu12_ati5770': 84 ]
50 'Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release',
51 'base-macmini':
52 'Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release',
53 'base-macmini-lion-float':
54 'Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release',
55 'base-android-galaxy-nexus':
56 'Test-Android-GalaxyNexus-SGX540-Arm7-Debug',
57 'base-android-nexus-7':
58 'Test-Android-Nexus7-Tegra3-Arm7-Release',
59 'base-android-nexus-s':
60 'Test-Android-NexusS-SGX540-Arm7-Release',
61 'base-android-xoom':
62 'Test-Android-Xoom-Tegra2-Arm7-Release',
63 'base-android-nexus-10':
64 'Test-Android-Nexus10-MaliT604-Arm7-Release',
65 'base-android-nexus-4':
66 'Test-Android-Nexus4-Adreno320-Arm7-Release',
67 }
68 85
69 86
70 class _InternalException(Exception): 87 class _InternalException(Exception):
71 pass 88 pass
72 89
73 # Object that handles exceptions, either raising them immediately or collecting 90 # Object that handles exceptions, either raising them immediately or collecting
74 # them to display later on. 91 # them to display later on.
75 class ExceptionHandler(object): 92 class ExceptionHandler(object):
76 93
77 # params: 94 # params:
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS] 223 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
207 if not sections: 224 if not sections:
208 sections = actual_results.keys() 225 sections = actual_results.keys()
209 for section in sections: 226 for section in sections:
210 section_results = actual_results[section] 227 section_results = actual_results[section]
211 if section_results: 228 if section_results:
212 results_to_return.update(section_results) 229 results_to_return.update(section_results)
213 return results_to_return 230 return results_to_return
214 231
215 # Rebaseline all tests/types we specified in the constructor, 232 # Rebaseline all tests/types we specified in the constructor,
216 # within this expectations/gm subdir. 233 # within this builder's subdirectory in expectations/gm .
217 # 234 #
218 # params: 235 # params:
219 # subdir : e.g. 'base-shuttle-win7-intel-float'
220 # builder : e.g. 'Test-Win7-ShuttleA-HD2000-x86-Release' 236 # builder : e.g. 'Test-Win7-ShuttleA-HD2000-x86-Release'
221 def RebaselineSubdir(self, subdir, builder): 237 def RebaselineSubdir(self, builder):
222 # Read in the actual result summary, and extract all the tests whose 238 # Read in the actual result summary, and extract all the tests whose
223 # results we need to update. 239 # results we need to update.
224 actuals_url = '/'.join([self._actuals_base_url, 240 actuals_url = '/'.join([self._actuals_base_url,
225 subdir, builder, subdir, 241 builder, self._actuals_filename])
226 self._actuals_filename])
227 # In most cases, we won't need to re-record results that are already 242 # In most cases, we won't need to re-record results that are already
228 # succeeding, but including the SUCCEEDED results will allow us to 243 # succeeding, but including the SUCCEEDED results will allow us to
229 # re-record expectations if they somehow get out of sync. 244 # re-record expectations if they somehow get out of sync.
230 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED, 245 sections = [gm_json.JSONKEY_ACTUALRESULTS_FAILED,
231 gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED] 246 gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED]
232 if self._add_new: 247 if self._add_new:
233 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON) 248 sections.append(gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON)
234 results_to_update = self._GetActualResults(json_url=actuals_url, 249 results_to_update = self._GetActualResults(json_url=actuals_url,
235 sections=sections) 250 sections=sections)
236 251
237 # Read in current expectations. 252 # Read in current expectations.
238 expectations_input_filepath = os.path.join( 253 expectations_input_filepath = os.path.join(
239 self._expectations_root, subdir, self._expectations_input_filename) 254 self._expectations_root, builder, self._expectations_input_filename)
240 expectations_dict = gm_json.LoadFromFile(expectations_input_filepath) 255 expectations_dict = gm_json.LoadFromFile(expectations_input_filepath)
241 expected_results = expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS] 256 expected_results = expectations_dict[gm_json.JSONKEY_EXPECTEDRESULTS]
242 257
243 # Update the expectations in memory, skipping any tests/configs that 258 # Update the expectations in memory, skipping any tests/configs that
244 # the caller asked to exclude. 259 # the caller asked to exclude.
245 skipped_images = [] 260 skipped_images = []
246 if results_to_update: 261 if results_to_update:
247 for (image_name, image_results) in results_to_update.iteritems(): 262 for (image_name, image_results) in results_to_update.iteritems():
248 (test, config) = self._image_filename_re.match(image_name).groups() 263 (test, config) = self._image_filename_re.match(image_name).groups()
249 if self._tests: 264 if self._tests:
250 if test not in self._tests: 265 if test not in self._tests:
251 skipped_images.append(image_name) 266 skipped_images.append(image_name)
252 continue 267 continue
253 if self._configs: 268 if self._configs:
254 if config not in self._configs: 269 if config not in self._configs:
255 skipped_images.append(image_name) 270 skipped_images.append(image_name)
256 continue 271 continue
257 if not expected_results.get(image_name): 272 if not expected_results.get(image_name):
258 expected_results[image_name] = {} 273 expected_results[image_name] = {}
259 expected_results[image_name][gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGE STS] = \ 274 expected_results[image_name][gm_json.JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGE STS] = \
260 [image_results] 275 [image_results]
261 276
262 # Write out updated expectations. 277 # Write out updated expectations.
263 expectations_output_filepath = os.path.join( 278 expectations_output_filepath = os.path.join(
264 self._expectations_root, subdir, self._expectations_output_filename) 279 self._expectations_root, builder, self._expectations_output_filename)
265 gm_json.WriteToFile(expectations_dict, expectations_output_filepath) 280 gm_json.WriteToFile(expectations_dict, expectations_output_filepath)
266 281
267 # Mark the JSON file as plaintext, so text-style diffs can be applied. 282 # Mark the JSON file as plaintext, so text-style diffs can be applied.
268 # Fixes https://code.google.com/p/skia/issues/detail?id=1442 283 # Fixes https://code.google.com/p/skia/issues/detail?id=1442
269 if self._using_svn: 284 if self._using_svn:
270 self._Call(['svn', 'propset', '--quiet', 'svn:mime-type', 285 self._Call(['svn', 'propset', '--quiet', 'svn:mime-type',
271 'text/x-json', expectations_output_filepath]) 286 'text/x-json', expectations_output_filepath])
272 287
273 # main... 288 # main...
274 289
275 parser = argparse.ArgumentParser() 290 parser = argparse.ArgumentParser()
276 parser.add_argument('--actuals-base-url', 291 parser.add_argument('--actuals-base-url',
277 help='base URL from which to read files containing JSON ' + 292 help='base URL from which to read files containing JSON ' +
278 'summaries of actual GM results; defaults to %(default)s', 293 'summaries of actual GM results; defaults to %(default)s',
279 default='http://skia-autogen.googlecode.com/svn/gm-actual') 294 default='http://skia-autogen.googlecode.com/svn/gm-actual')
280 parser.add_argument('--actuals-filename', 295 parser.add_argument('--actuals-filename',
281 help='filename (within platform-specific subdirectories ' + 296 help='filename (within builder-specific subdirectories ' +
282 'of ACTUALS_BASE_URL) to read a summary of results from; ' + 297 'of ACTUALS_BASE_URL) to read a summary of results from; ' +
283 'defaults to %(default)s', 298 'defaults to %(default)s',
284 default='actual-results.json') 299 default='actual-results.json')
285 # TODO(epoger): Add test that exercises --add-new argument. 300 # TODO(epoger): Add test that exercises --add-new argument.
286 parser.add_argument('--add-new', action='store_true', 301 parser.add_argument('--add-new', action='store_true',
287 help='in addition to the standard behavior of ' + 302 help='in addition to the standard behavior of ' +
288 'updating expectations for failing tests, add ' + 303 'updating expectations for failing tests, add ' +
289 'expectations for tests which don\'t have expectations ' + 304 'expectations for tests which don\'t have expectations ' +
290 'yet.') 305 'yet.')
306 parser.add_argument('--builders', metavar='BUILDER', nargs='+',
307 help='which platforms to rebaseline; ' +
308 'if unspecified, rebaseline all platforms, same as ' +
309 '"--builders %s"' % ' '.join(sorted(BUILDERS_LIST)))
291 # TODO(epoger): Add test that exercises --configs argument. 310 # TODO(epoger): Add test that exercises --configs argument.
292 parser.add_argument('--configs', metavar='CONFIG', nargs='+', 311 parser.add_argument('--configs', metavar='CONFIG', nargs='+',
293 help='which configurations to rebaseline, e.g. ' + 312 help='which configurations to rebaseline, e.g. ' +
294 '"--configs 565 8888", as a filter over the full set of ' + 313 '"--configs 565 8888", as a filter over the full set of ' +
295 'results in ACTUALS_FILENAME; if unspecified, rebaseline ' + 314 'results in ACTUALS_FILENAME; if unspecified, rebaseline ' +
296 '*all* configs that are available.') 315 '*all* configs that are available.')
297 parser.add_argument('--expectations-filename', 316 parser.add_argument('--expectations-filename',
298 help='filename (under EXPECTATIONS_ROOT) to read ' + 317 help='filename (under EXPECTATIONS_ROOT) to read ' +
299 'current expectations from, and to write new ' + 318 'current expectations from, and to write new ' +
300 'expectations into (unless a separate ' + 319 'expectations into (unless a separate ' +
301 'EXPECTATIONS_FILENAME_OUTPUT has been specified); ' + 320 'EXPECTATIONS_FILENAME_OUTPUT has been specified); ' +
302 'defaults to %(default)s', 321 'defaults to %(default)s',
303 default='expected-results.json') 322 default='expected-results.json')
304 parser.add_argument('--expectations-filename-output', 323 parser.add_argument('--expectations-filename-output',
305 help='filename (under EXPECTATIONS_ROOT) to write ' + 324 help='filename (under EXPECTATIONS_ROOT) to write ' +
306 'updated expectations into; by default, overwrites the ' + 325 'updated expectations into; by default, overwrites the ' +
307 'input file (EXPECTATIONS_FILENAME)', 326 'input file (EXPECTATIONS_FILENAME)',
308 default='') 327 default='')
309 parser.add_argument('--expectations-root', 328 parser.add_argument('--expectations-root',
310 help='root of expectations directory to update-- should ' + 329 help='root of expectations directory to update-- should ' +
311 'contain one or more base-* subdirectories. Defaults to ' + 330 'contain one or more builder subdirectories. Defaults to ' +
312 '%(default)s', 331 '%(default)s',
313 default=os.path.join('expectations', 'gm')) 332 default=os.path.join('expectations', 'gm'))
314 parser.add_argument('--keep-going-on-failure', action='store_true', 333 parser.add_argument('--keep-going-on-failure', action='store_true',
315 help='instead of halting at the first error encountered, ' + 334 help='instead of halting at the first error encountered, ' +
316 'keep going and rebaseline as many tests as possible, ' + 335 'keep going and rebaseline as many tests as possible, ' +
317 'and then report the full set of errors at the end') 336 'and then report the full set of errors at the end')
318 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+',
319 help='which platform subdirectories to rebaseline; ' +
320 'if unspecified, rebaseline all subdirs, same as ' +
321 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys())))
322 # TODO(epoger): Add test that exercises --tests argument. 337 # TODO(epoger): Add test that exercises --tests argument.
323 parser.add_argument('--tests', metavar='TEST', nargs='+', 338 parser.add_argument('--tests', metavar='TEST', nargs='+',
324 help='which tests to rebaseline, e.g. ' + 339 help='which tests to rebaseline, e.g. ' +
325 '"--tests aaclip bigmatrix", as a filter over the full ' + 340 '"--tests aaclip bigmatrix", as a filter over the full ' +
326 'set of results in ACTUALS_FILENAME; if unspecified, ' + 341 'set of results in ACTUALS_FILENAME; if unspecified, ' +
327 'rebaseline *all* tests that are available.') 342 'rebaseline *all* tests that are available.')
328 args = parser.parse_args() 343 args = parser.parse_args()
329 exception_handler = ExceptionHandler( 344 exception_handler = ExceptionHandler(
330 keep_going_on_failure=args.keep_going_on_failure) 345 keep_going_on_failure=args.keep_going_on_failure)
331 if args.subdirs: 346 if args.builders:
332 subdirs = args.subdirs 347 builders = args.builders
333 missing_json_is_fatal = True 348 missing_json_is_fatal = True
334 else: 349 else:
335 subdirs = sorted(SUBDIR_MAPPING.keys()) 350 builders = sorted(BUILDERS_LIST)
336 missing_json_is_fatal = False 351 missing_json_is_fatal = False
337 for subdir in subdirs: 352 for builder in builders:
338 if not subdir in SUBDIR_MAPPING.keys(): 353 if not builder in BUILDERS_LIST:
339 raise Exception(('unrecognized platform subdir "%s"; ' + 354 raise Exception(('unrecognized builder "%s"; ' +
340 'should be one of %s') % ( 355 'should be one of %s') % (
341 subdir, SUBDIR_MAPPING.keys())) 356 builder, BUILDERS_LIST))
342 builder = SUBDIR_MAPPING[subdir]
343 357
344 # We instantiate different Rebaseliner objects depending 358 expectations_json_file = os.path.join(args.expectations_root, builder,
345 # on whether we are rebaselining an expected-results.json file, or
346 # individual image files. Different expectations/gm subdirectories may move
347 # from individual image files to JSON-format expectations at different
348 # times, so we need to make this determination per subdirectory.
349 #
350 # See https://goto.google.com/ChecksumTransitionDetail
351 expectations_json_file = os.path.join(args.expectations_root, subdir,
352 args.expectations_filename) 359 args.expectations_filename)
353 if os.path.isfile(expectations_json_file): 360 if os.path.isfile(expectations_json_file):
354 rebaseliner = JsonRebaseliner( 361 rebaseliner = JsonRebaseliner(
355 expectations_root=args.expectations_root, 362 expectations_root=args.expectations_root,
356 expectations_input_filename=args.expectations_filename, 363 expectations_input_filename=args.expectations_filename,
357 expectations_output_filename=(args.expectations_filename_output or 364 expectations_output_filename=(args.expectations_filename_output or
358 args.expectations_filename), 365 args.expectations_filename),
359 tests=args.tests, configs=args.configs, 366 tests=args.tests, configs=args.configs,
360 actuals_base_url=args.actuals_base_url, 367 actuals_base_url=args.actuals_base_url,
361 actuals_filename=args.actuals_filename, 368 actuals_filename=args.actuals_filename,
362 exception_handler=exception_handler, 369 exception_handler=exception_handler,
363 add_new=args.add_new) 370 add_new=args.add_new)
364 try: 371 try:
365 rebaseliner.RebaselineSubdir(subdir=subdir, builder=builder) 372 rebaseliner.RebaselineSubdir(builder=builder)
366 except BaseException as e: 373 except BaseException as e:
367 exception_handler.RaiseExceptionOrContinue(e) 374 exception_handler.RaiseExceptionOrContinue(e)
368 else: 375 else:
369 exception_handler.RaiseExceptionOrContinue(_InternalException( 376 exception_handler.RaiseExceptionOrContinue(_InternalException(
370 'expectations_json_file %s not found' % expectations_json_file)) 377 'expectations_json_file %s not found' % expectations_json_file))
371 378
372 exception_handler.ReportAllFailures() 379 exception_handler.ReportAllFailures()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698