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

Side by Side Diff: tools/rebaseline.py

Issue 16093025: rebaseline.py: if --tests is not specified, get test list from actual-results.json (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: fix_json_case Created 7 years, 6 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
epoger 2013/06/05 03:16:20 Toplevel comment: This change is part of "Step 1"
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 '''
11 Rebaselines the given GM tests, on all bots and all configurations. 11 Rebaselines the given GM tests, on all bots and all configurations.
12 Must be run from the gm-expected directory. If run from a git or SVN 12 Must be run from the gm-expected directory. If run from a git or SVN
13 checkout, the files will be added to the staging area for commit. 13 checkout, the files will be added to the staging area for commit.
14 ''' 14 '''
15 15
16 # System-level imports
16 import argparse 17 import argparse
17 import os 18 import os
18 import subprocess 19 import subprocess
19 import sys 20 import sys
21 import urllib2
22
23 # Imports from within Skia
24 #
25 # Make sure that they are in the PYTHONPATH, but add them at the *end*
26 # so any that are already in the PYTHONPATH will be preferred.
27 GM_DIRECTORY = os.path.realpath(
28 os.path.join(os.path.dirname(os.path.dirname(__file__)), 'gm'))
29 if GM_DIRECTORY not in sys.path:
30 sys.path.append(GM_DIRECTORY)
31 import gm_json
32
20 33
21 # Mapping of gm-expectations subdir (under 34 # Mapping of gm-expectations subdir (under
22 # https://skia.googlecode.com/svn/gm-expected/ ) 35 # https://skia.googlecode.com/svn/gm-expected/ )
23 # to builder name (see list at http://108.170.217.252:10117/builders ) 36 # to builder name (see list at http://108.170.217.252:10117/builders )
24 SUBDIR_MAPPING = { 37 SUBDIR_MAPPING = {
25 'base-shuttle-win7-intel-float': 38 'base-shuttle-win7-intel-float':
26 'Test-Win7-ShuttleA-HD2000-x86-Release', 39 'Test-Win7-ShuttleA-HD2000-x86-Release',
27 'base-shuttle-win7-intel-angle': 40 'base-shuttle-win7-intel-angle':
28 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE', 41 'Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE',
29 'base-shuttle-win7-intel-directwrite': 42 'base-shuttle-win7-intel-directwrite':
(...skipping 16 matching lines...) Expand all
46 'Test-Android-Nexus10-MaliT604-Arm7-Release', 59 'Test-Android-Nexus10-MaliT604-Arm7-Release',
47 } 60 }
48 61
49 62
50 class CommandFailedException(Exception): 63 class CommandFailedException(Exception):
51 pass 64 pass
52 65
53 class Rebaseliner(object): 66 class Rebaseliner(object):
54 67
55 # params: 68 # params:
56 # tests: list of tests to rebaseline 69 # tests: list of tests to rebaseline, or None if we should rebaseline
70 # whatever tests the actual-results.json file tells us to
71 # json_base_url: base URL from which to read json_filename
72 # json_filename: filename (under json_base_url) from which to read a
73 # summary of results
57 # configs: which configs to run for each test 74 # configs: which configs to run for each test
58 # subdirs: which platform subdirectories to rebaseline; if an empty list, 75 # subdirs: which platform subdirectories to rebaseline; if an empty list,
59 # rebaseline all platform subdirectories 76 # rebaseline all platform subdirectories
60 # dry_run: if True, instead of actually downloading files or adding 77 # dry_run: if True, instead of actually downloading files or adding
61 # files to checkout, display a list of operations that 78 # files to checkout, display a list of operations that
62 # we would normally perform 79 # we would normally perform
63 def __init__(self, tests, configs=[], subdirs=[], dry_run=False): 80 def __init__(self, tests, json_base_url, json_filename,
64 if not tests: 81 configs=[], subdirs=[], dry_run=False):
65 raise Exception('at least one test must be specified')
66 self._tests = tests 82 self._tests = tests
67 self._configs = configs 83 self._configs = configs
68 if not subdirs: 84 if not subdirs:
69 self._subdirs = sorted(SUBDIR_MAPPING.keys()) 85 self._subdirs = sorted(SUBDIR_MAPPING.keys())
70 else: 86 else:
71 self._subdirs = subdirs 87 self._subdirs = subdirs
88 self._json_base_url = json_base_url
89 self._json_filename = json_filename
72 self._dry_run = dry_run 90 self._dry_run = dry_run
73 self._is_svn_checkout = ( 91 self._is_svn_checkout = (
74 os.path.exists('.svn') or 92 os.path.exists('.svn') or
75 os.path.exists(os.path.join(os.pardir, '.svn'))) 93 os.path.exists(os.path.join(os.pardir, '.svn')))
76 self._is_git_checkout = ( 94 self._is_git_checkout = (
77 os.path.exists('.git') or 95 os.path.exists('.git') or
78 os.path.exists(os.path.join(os.pardir, '.git'))) 96 os.path.exists(os.path.join(os.pardir, '.git')))
79 97
80 # If dry_run is False, execute subprocess.call(cmd). 98 # If dry_run is False, execute subprocess.call(cmd).
81 # If dry_run is True, print the command we would have otherwise run. 99 # If dry_run is True, print the command we would have otherwise run.
(...skipping 12 matching lines...) Expand all
94 # so that we don't corrupt the existing file if it fails midway thru. 112 # so that we don't corrupt the existing file if it fails midway thru.
95 temp_filename = os.path.join(os.path.dirname(dest_filename), 113 temp_filename = os.path.join(os.path.dirname(dest_filename),
96 '.temp-' + os.path.basename(dest_filename)) 114 '.temp-' + os.path.basename(dest_filename))
97 115
98 # TODO(epoger): Replace calls to "curl"/"mv" (which will only work on 116 # TODO(epoger): Replace calls to "curl"/"mv" (which will only work on
99 # Unix) with a Python HTTP library (which should work cross-platform) 117 # Unix) with a Python HTTP library (which should work cross-platform)
100 self._Call([ 'curl', '--fail', '--silent', source_url, 118 self._Call([ 'curl', '--fail', '--silent', source_url,
101 '--output', temp_filename ]) 119 '--output', temp_filename ])
102 self._Call([ 'mv', temp_filename, dest_filename ]) 120 self._Call([ 'mv', temp_filename, dest_filename ])
103 121
122 # Returns the full contents of a URL, as a single string.
123 #
124 # Unlike standard URL handling, we allow relative "file:" URLs;
125 # for example, "file:one/two" resolves to the file ./one/two
126 # (relative to current working dir)
127 def _GetContentsOfUrl(self, url):
128 file_prefix = 'file:'
129 if url.startswith(file_prefix):
130 filename = url[len(file_prefix):]
131 return open(filename, 'r').read()
132 else:
133 return urllib2.urlopen(url).read()
134
135 # Returns a list of files that require rebaselining.
136 #
137 # Note that this returns a list of FILES, like this:
138 # ['imageblur_565.png', 'xfermodes_pdf.png']
139 # rather than a list of TESTS, like this:
140 # ['imageblur', 'xfermodes']
141 #
142 # params:
143 # json_url: URL pointing to a JSON actual result summary file
144 #
145 # TODO(epoger): add a parameter indicating whether "no-comparison"
146 # results (those for which we don't have any expectations yet)
147 # should be rebaselined. For now, we only return failed expectations.
148 def _GetFilesToRebaseline(self, json_url):
149 print ('# Getting tests to rebaseline from JSON summary URL %s ...'
150 % json_url)
151 json_contents = self._GetContentsOfUrl(json_url)
152 json_dict = gm_json.LoadFromString(json_contents)
153 actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
154
155 tests_to_rebaseline = []
156 failed_results = actual_results[gm_json.JSONKEY_ACTUALRESULTS_FAILED]
157 if failed_results:
158 tests_to_rebaseline.extend(failed_results.keys())
159
160 print '# ... found tests_to_rebaseline %s' % tests_to_rebaseline
161 return tests_to_rebaseline
162
104 # Rebaseline a single file. 163 # Rebaseline a single file.
105 def _RebaselineOneFile(self, expectations_subdir, builder_name, 164 def _RebaselineOneFile(self, expectations_subdir, builder_name,
106 infilename, outfilename): 165 infilename, outfilename):
166 print '# ' + infilename
107 url = ('http://skia-autogen.googlecode.com/svn/gm-actual/' + 167 url = ('http://skia-autogen.googlecode.com/svn/gm-actual/' +
108 expectations_subdir + '/' + builder_name + '/' + 168 expectations_subdir + '/' + builder_name + '/' +
109 expectations_subdir + '/' + infilename) 169 expectations_subdir + '/' + infilename)
110 170
111 # Try to download this file, but if that fails, keep going... 171 # Try to download this file, but if that fails, keep going...
112 # 172 #
113 # This not treated as a fatal failure because not all 173 # This not treated as a fatal failure because not all
114 # platforms generate all configs (e.g., Android does not 174 # platforms generate all configs (e.g., Android does not
115 # generate PDF). 175 # generate PDF).
116 # 176 #
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 configs = self._configs 208 configs = self._configs
149 else: 209 else:
150 if (expectations_subdir == 'base-shuttle-win7-intel-angle'): 210 if (expectations_subdir == 'base-shuttle-win7-intel-angle'):
151 configs = [ 'angle', 'anglemsaa16' ] 211 configs = [ 'angle', 'anglemsaa16' ]
152 else: 212 else:
153 configs = [ '565', '8888', 'gpu', 'pdf', 'mesa', 'msaa16', 213 configs = [ '565', '8888', 'gpu', 'pdf', 'mesa', 'msaa16',
154 'msaa4' ] 214 'msaa4' ]
155 print '# ' + expectations_subdir + ':' 215 print '# ' + expectations_subdir + ':'
156 for config in configs: 216 for config in configs:
157 infilename = test + '_' + config + '.png' 217 infilename = test + '_' + config + '.png'
158 print '# ' + infilename
159 outfilename = os.path.join(expectations_subdir, infilename); 218 outfilename = os.path.join(expectations_subdir, infilename);
160 self._RebaselineOneFile(expectations_subdir=expectations_subdir, 219 self._RebaselineOneFile(expectations_subdir=expectations_subdir,
161 builder_name=builder_name, 220 builder_name=builder_name,
162 infilename=infilename, 221 infilename=infilename,
163 outfilename=outfilename) 222 outfilename=outfilename)
164 223
165 # Rebaseline all platforms/tests/types we specified in the constructor. 224 # Rebaseline all platforms/tests/types we specified in the constructor.
166 def RebaselineAll(self): 225 def RebaselineAll(self):
167 for test in self._tests: 226 for subdir in self._subdirs:
168 for subdir in self._subdirs: 227 if not subdir in SUBDIR_MAPPING.keys():
169 if not subdir in SUBDIR_MAPPING.keys(): 228 raise Exception(('unrecognized platform subdir "%s"; ' +
170 raise Exception(('unrecognized platform subdir "%s"; ' + 229 'should be one of %s') % (
171 'should be one of %s') % ( 230 subdir, SUBDIR_MAPPING.keys()))
172 subdir, SUBDIR_MAPPING.keys())) 231 builder_name = SUBDIR_MAPPING[subdir]
173 builder_name = SUBDIR_MAPPING[subdir] 232 if self._tests:
174 self._RebaselineOneTest(expectations_subdir=subdir, 233 for test in self._tests:
175 builder_name=builder_name, 234 self._RebaselineOneTest(expectations_subdir=subdir,
176 test=test) 235 builder_name=builder_name,
177 236 test=test)
237 else: # get the raw list of files that need rebaselining from JSON
238 json_url = '/'.join([self._json_base_url,
239 subdir, builder_name, subdir,
240 self._json_filename])
241 filenames = self._GetFilesToRebaseline(json_url=json_url)
242 for filename in filenames:
243 outfilename = os.path.join(subdir, filename);
244 self._RebaselineOneFile(expectations_subdir=subdir,
epoger 2013/06/05 03:16:20 Patchset 5 fixes the JSON case: when rebaselining
245 builder_name=builder_name,
246 infilename=filename,
247 outfilename=outfilename)
178 248
179 # main... 249 # main...
180 250
181 parser = argparse.ArgumentParser() 251 parser = argparse.ArgumentParser()
182 parser.add_argument('--configs', metavar='CONFIG', nargs='+', 252 parser.add_argument('--configs', metavar='CONFIG', nargs='+',
183 help='which configurations to rebaseline, e.g. ' + 253 help='which configurations to rebaseline, e.g. ' +
184 '"--configs 565 8888"; if unspecified, run a default ' + 254 '"--configs 565 8888"; if unspecified, run a default ' +
185 'set of configs') 255 'set of configs')
186 parser.add_argument('--dry_run', action='store_true', 256 parser.add_argument('--dry_run', action='store_true',
187 help='instead of actually downloading files or adding ' + 257 help='instead of actually downloading files or adding ' +
188 'files to checkout, display a list of operations that ' + 258 'files to checkout, display a list of operations that ' +
189 'we would normally perform') 259 'we would normally perform')
260 parser.add_argument('--json_base_url',
261 help='base URL from which to read JSON_FILENAME ' +
262 'files; defaults to %(default)s',
263 default='http://skia-autogen.googlecode.com/svn/gm-actual')
264 parser.add_argument('--json_filename',
265 help='filename (under JSON_BASE_URL) to read a summary ' +
266 'of results from; defaults to %(default)s',
267 default='actual-results.json')
190 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+', 268 parser.add_argument('--subdirs', metavar='SUBDIR', nargs='+',
191 help='which platform subdirectories to rebaseline; ' + 269 help='which platform subdirectories to rebaseline; ' +
192 'if unspecified, rebaseline all subdirs, same as ' + 270 'if unspecified, rebaseline all subdirs, same as ' +
193 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys()))) 271 '"--subdirs %s"' % ' '.join(sorted(SUBDIR_MAPPING.keys())))
194 parser.add_argument('--tests', metavar='TEST', nargs='+', required=True, 272 parser.add_argument('--tests', metavar='TEST', nargs='+',
195 help='which tests to rebaseline, e.g. ' + 273 help='which tests to rebaseline, e.g. ' +
196 '"--tests aaclip bigmatrix"') 274 '"--tests aaclip bigmatrix"; if unspecified, then all ' +
275 'failing tests (according to the actual-results.json ' +
276 'file) will be rebaselined.')
197 args = parser.parse_args() 277 args = parser.parse_args()
198 rebaseliner = Rebaseliner(tests=args.tests, configs=args.configs, 278 rebaseliner = Rebaseliner(tests=args.tests, configs=args.configs,
199 subdirs=args.subdirs, dry_run=args.dry_run) 279 subdirs=args.subdirs, dry_run=args.dry_run,
280 json_base_url=args.json_base_url,
281 json_filename=args.json_filename)
200 rebaseliner.RebaselineAll() 282 rebaseliner.RebaselineAll()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698