OLD | NEW |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """API for the bisect recipe module. | 5 """API for the bisect recipe module. |
6 | 6 |
7 This API is meant to enable the bisect recipe to bisect any chromium-supported | 7 This API is meant to enable the bisect recipe to bisect any chromium-supported |
8 platform for any test that can be run via buildbot, perf or otherwise. | 8 platform for any test that can be run via buildbot, perf or otherwise. |
9 """ | 9 """ |
10 | 10 |
11 import os | 11 import os |
12 | 12 |
13 from recipe_engine import recipe_api | 13 from recipe_engine import recipe_api |
14 from . import bisector | 14 from auto_bisect import bisector |
15 from . import depot_config | 15 from auto_bisect import depot_config |
16 from . import revision_state | 16 from auto_bisect import revision_state |
17 from . import local_bisect | 17 from auto_bisect import local_bisect |
18 | 18 |
19 BISECT_CONFIG_FILE = 'tools/auto_bisect/bisect.cfg' | 19 BISECT_CONFIG_FILE = 'tools/auto_bisect/bisect.cfg' |
20 | 20 |
21 | 21 |
22 class AutoBisectApi(recipe_api.RecipeApi): | 22 class AutoBisectApi(recipe_api.RecipeApi): |
23 """A module for bisect specific functions.""" | 23 """A module for bisect specific functions.""" |
24 | 24 |
25 # Number of seconds to wait between polls for test results. | 25 # Number of seconds to wait between polls for test results. |
26 POLLING_INTERVAL = 60 | 26 POLLING_INTERVAL = 60 |
27 # GS bucket to use for communicating results and job state between bisector | 27 # GS bucket to use for communicating results and job state between bisector |
(...skipping 22 matching lines...) Expand all Loading... |
50 # Keep track of working directory (which contains the checkout). | 50 # Keep track of working directory (which contains the checkout). |
51 # None means "default value". | 51 # None means "default value". |
52 self._working_dir = None | 52 self._working_dir = None |
53 | 53 |
54 @property | 54 @property |
55 def working_dir(self): | 55 def working_dir(self): |
56 if not self._working_dir: | 56 if not self._working_dir: |
57 self._working_dir = self.m.chromium_checkout.get_checkout_dir({}) | 57 self._working_dir = self.m.chromium_checkout.get_checkout_dir({}) |
58 return self._working_dir or self.m.path['slave_build'] | 58 return self._working_dir or self.m.path['slave_build'] |
59 | 59 |
60 def perform_bisect(self, **flags): | |
61 return local_bisect.perform_bisect(self, **flags) | |
62 | |
63 def create_bisector(self, bisect_config_dict, dummy_mode=False, **flags): | 60 def create_bisector(self, bisect_config_dict, dummy_mode=False, **flags): |
64 """Passes the api and the config dictionary to the Bisector constructor. | 61 """Passes the api and the config dictionary to the Bisector constructor. |
65 | 62 |
66 For details about the keys in the bisect config dictionary go to: | 63 For details about the keys in the bisect config dictionary go to: |
67 http://chromium.org/developers/speed-infra/perf-try-bots-bisect-bots/config | 64 http://chromium.org/developers/speed-infra/perf-try-bots-bisect-bots/config |
68 | 65 |
69 Args: | 66 Args: |
70 bisect_config_dict (dict): Contains the configuration for the bisect job. | 67 bisect_config_dict (dict): Contains the configuration for the bisect job. |
71 dummy_mode (bool): In dummy mode we prevent the bisector for expanding | 68 dummy_mode (bool): In dummy mode we prevent the bisector for expanding |
72 the revision range at construction, to avoid the need for lots of step | 69 the revision range at construction, to avoid the need for lots of step |
(...skipping 24 matching lines...) Expand all Loading... |
97 depot_config.add_addition_depot_into(depot_info) # pragma: no cover | 94 depot_config.add_addition_depot_into(depot_info) # pragma: no cover |
98 | 95 |
99 def set_deploy_script(self, path): # pragma: no cover | 96 def set_deploy_script(self, path): # pragma: no cover |
100 """Sets apk deployment script path for android-chrome.""" | 97 """Sets apk deployment script path for android-chrome.""" |
101 self.full_deploy_script = path | 98 self.full_deploy_script = path |
102 | 99 |
103 def set_svn_repo(self, svn_repo_url): # pragma: no cover | 100 def set_svn_repo(self, svn_repo_url): # pragma: no cover |
104 """Sets SVN repo url for triggering build jobs.""" | 101 """Sets SVN repo url for triggering build jobs.""" |
105 self.svn_repo_url = svn_repo_url | 102 self.svn_repo_url = svn_repo_url |
106 | 103 |
107 def gsutil_file_exists(self, path): | 104 def gsutil_file_exists(self, path, **kwargs): |
108 """Returns True if a file exists at the given GS path.""" | 105 """Returns True if a file exists at the given GS path.""" |
109 try: | 106 try: |
110 self.m.gsutil(['ls', path]) | 107 self.m.gsutil( ['ls', path], **kwargs) |
111 except self.m.step.StepFailure: # pragma: no cover | 108 except self.m.step.StepFailure: |
112 # A step failure here simply means that the file does not exist, and | 109 # A step failure here simply means that the file does not exist, and |
113 # should not be treated as an error. | 110 # should not be treated as an error. |
114 self.m.step.active_result.presentation.status = self.m.step.SUCCESS | 111 self.m.step.active_result.presentation.status = self.m.step.SUCCESS |
115 return False | 112 return False |
116 return True | 113 return True |
117 | 114 |
118 def query_revision_info(self, revision): | 115 def query_revision_info(self, revision): |
119 """Gathers information on a particular revision. | 116 """Gathers information on a particular revision. |
120 | 117 |
121 Args: | 118 Args: |
122 revision (str): A git commit hash. | 119 revision (str): A git commit hash. |
123 | 120 |
124 Returns: | 121 Returns: |
125 A dict with the keys "author", "email", "date", "subject" and "body", | 122 A dict with the keys "author", "email", "date", "subject" and "body", |
126 as output by fetch_revision_info.py. | 123 as output by fetch_revision_info.py. |
127 """ | 124 """ |
128 step_name = 'Reading culprit cl information.' | 125 step_name = 'Reading culprit cl information.' |
129 # Use gitiles to get commit information. | 126 # Use gitiles to get commit information. |
130 if revision.depot_name == 'android-chrome': # pragma: no cover | 127 if revision.depot_name == 'android-chrome': # pragma: no cover |
131 commit_url = depot_config.DEPOT_DEPS_NAME[revision.depot_name]['url'] | 128 commit_url = depot_config.DEPOT_DEPS_NAME[revision.depot_name]['url'] |
132 return self._commit_info(revision.commit_hash, commit_url, step_name) | 129 return self._commit_info(revision.commit_hash, commit_url, step_name) |
133 result = self.m.python( | 130 result = self.m.python( |
134 step_name, | 131 step_name, |
135 self.resource('fetch_revision_info.py'), | 132 self.resource('fetch_revision_info.py'), |
136 [revision.commit_hash, revision.depot_name], | 133 [revision.commit_hash, revision.depot_name], |
137 stdout=self.m.json.output()) | 134 stdout=self.m.json.output(), |
| 135 step_test_data=lambda: self._test_data['cl_info'][revision.commit_hash], |
| 136 ) |
138 return result.stdout | 137 return result.stdout |
139 | 138 |
140 def _commit_info(self, commit_hash, url, step_name=None): # pragma: no cover | 139 def _commit_info(self, commit_hash, url, step_name=None): # pragma: no cover |
141 """Fetches information about a given commit. | 140 """Fetches information about a given commit. |
142 | 141 |
143 Args: | 142 Args: |
144 commit_hash (str): A git commit hash. | 143 commit_hash (str): A git commit hash. |
145 url (str): The URL of a repository, e.g. | 144 url (str): The URL of a repository, e.g. |
146 "https://chromium.googlesource.com/chromium/src". | 145 "https://chromium.googlesource.com/chromium/src". |
147 step_name (str): Optional step name. | 146 step_name (str): Optional step name. |
(...skipping 14 matching lines...) Expand all Loading... |
162 'email': commit_info['author']['email'], | 161 'email': commit_info['author']['email'], |
163 'subject': subject, | 162 'subject': subject, |
164 'body': body, | 163 'body': body, |
165 'date': commit_info['committer']['time'], | 164 'date': commit_info['committer']['time'], |
166 } | 165 } |
167 return None | 166 return None |
168 except self.m.step.StepFailure: # pragma: no cover | 167 except self.m.step.StepFailure: # pragma: no cover |
169 self.surface_result('BAD_REV') | 168 self.surface_result('BAD_REV') |
170 raise | 169 raise |
171 | 170 |
172 def run_bisect_script(self, **kwargs): | |
173 """Executes src/tools/run-perf-bisect-regression.py to perform bisection.""" | |
174 self.m.python( | |
175 'Preparing for Bisection', | |
176 script=self.m.path['checkout'].join( | |
177 'tools', 'prepare-bisect-perf-regression.py'), | |
178 args=['-w', self.m.path['cache'].join('bisect')]) | |
179 args = [] | |
180 | |
181 kwargs['allow_subannotations'] = True | |
182 | |
183 # TODO(prasadv): Remove this once bisect runs are no longer running | |
184 # against revisions from February 2016 or earlier. | |
185 if self.internal_bisect: # pragma: no cover | |
186 kwargs['env'] = {'CHROMIUM_OUTPUT_DIR': self.m.chromium.output_dir} | |
187 | |
188 if kwargs.get('extra_src'): | |
189 args = args + ['--extra_src', kwargs.pop('extra_src')] | |
190 if kwargs.get('path_to_config'): | |
191 args = args + ['--path_to_config', kwargs.pop('path_to_config')] | |
192 if self.m.chromium.c.TARGET_PLATFORM != 'android': | |
193 goma_dir = self.m.goma.ensure_goma() | |
194 args += ['--path_to_goma', goma_dir] | |
195 args += [ | |
196 '--build-properties', | |
197 self.m.json.dumps(dict(self.m.properties.legacy())), | |
198 ] | |
199 self.m.chromium.runtest( | |
200 self.m.path['checkout'].join('tools', 'run-bisect-perf-regression.py'), | |
201 ['-w', self.m.path['cache'].join('bisect')] + args, | |
202 name='Running Bisection', | |
203 xvfb=True, **kwargs) | |
204 | |
205 def run_local_test_run(self, test_config_params, | 171 def run_local_test_run(self, test_config_params, |
206 skip_download=False): # pragma: no cover | 172 skip_download=False, **kwargs): |
207 """Starts a test run on the same machine. | 173 """Starts a test run on the same machine. |
208 | 174 |
209 This is for the merged director/tester flow. | 175 This is for the merged director/tester flow. |
210 """ | 176 """ |
211 if self.m.platform.is_win: | 177 if self.m.platform.is_win: |
212 self.m.chromium.taskkill() | 178 self.m.chromium.taskkill() |
213 | 179 |
214 if skip_download: | 180 if skip_download: # pragma: no cover |
215 update_step = None | 181 update_step = None |
216 else: | 182 else: |
217 update_step = self._SyncRevisionToTest(test_config_params) | 183 update_step = self._SyncRevisionToTest(test_config_params) |
218 self.start_test_run_for_bisect(update_step, self.bot_db, | 184 return self.start_test_run_for_bisect( |
219 test_config_params, run_locally=True, | 185 update_step, self.bot_db, test_config_params, |
220 skip_download=skip_download) | 186 skip_download=skip_download, **kwargs) |
221 | 187 |
222 def ensure_checkout(self, *args, **kwargs): | 188 def ensure_checkout(self, *args, **kwargs): |
223 if self.working_dir: | 189 if self.working_dir: |
224 kwargs.setdefault('cwd', self.working_dir) | 190 kwargs.setdefault('cwd', self.working_dir) |
225 | 191 |
226 return self.m.bot_update.ensure_checkout(*args, **kwargs) | 192 return self.m.bot_update.ensure_checkout(*args, **kwargs) |
227 | 193 |
228 def _SyncRevisionToTest(self, test_config_params): # pragma: no cover | 194 def _SyncRevisionToTest(self, test_config_params): |
229 if not self.internal_bisect: | 195 if not self.internal_bisect: |
230 return self.ensure_checkout( | 196 return self.ensure_checkout( |
231 root_solution_revision=test_config_params['revision']) | 197 root_solution_revision=test_config_params['revision']) |
232 else: | 198 else: # pragma: no cover |
233 return self._SyncRevisionsForAndroidChrome( | 199 return self._SyncRevisionsForAndroidChrome( |
234 test_config_params['revision_ladder']) | 200 test_config_params['revision_ladder']) |
235 | 201 |
236 def _SyncRevisionsForAndroidChrome(self, revision_ladder): # pragma: no cover | 202 def _SyncRevisionsForAndroidChrome(self, revision_ladder): # pragma: no cover |
237 """Syncs android-chrome and chromium repos to particular revision.""" | 203 """Syncs android-chrome and chromium repos to particular revision.""" |
238 revisions = [] | 204 revisions = [] |
239 for d, r in revision_ladder.iteritems(): | 205 for d, r in revision_ladder.iteritems(): |
240 revisions.append('%s@%s' % (depot_config.DEPOT_DEPS_NAME[d]['src'], r)) | 206 revisions.append('%s@%s' % (depot_config.DEPOT_DEPS_NAME[d]['src'], r)) |
241 params = ['sync', '--verbose', '--nohooks', '--force', | 207 params = ['sync', '--verbose', '--nohooks', '--force', |
242 '--delete_unversioned_trees'] | 208 '--delete_unversioned_trees'] |
243 for revision in revisions: | 209 for revision in revisions: |
244 params.extend(['--revision', revision]) | 210 params.extend(['--revision', revision]) |
245 self.m.gclient('sync %s' % '-'.join(revisions), params) | 211 self.m.gclient('sync %s' % '-'.join(revisions), params) |
246 return None | 212 return None |
247 | 213 |
248 def start_test_run_for_bisect(self, update_step, bot_db, | 214 def start_test_run_for_bisect(self, update_step, bot_db, test_config_params, |
249 test_config_params, run_locally=False, | 215 skip_download=False, **kwargs): |
250 skip_download=False): | |
251 mastername = self.m.properties.get('mastername') | 216 mastername = self.m.properties.get('mastername') |
252 buildername = self.m.properties.get('buildername') | 217 buildername = self.m.properties.get('buildername') |
253 bot_config = bot_db.get_bot_config(mastername, buildername) | 218 bot_config = bot_db.get_bot_config(mastername, buildername) |
254 build_archive_url = test_config_params['parent_build_archive_url'] | 219 build_archive_url = test_config_params['parent_build_archive_url'] |
255 if not run_locally: | |
256 self.m.bisect_tester.upload_job_url() | |
257 if not skip_download: | 220 if not skip_download: |
258 if self.m.chromium.c.TARGET_PLATFORM == 'android': | 221 if self.m.chromium.c.TARGET_PLATFORM == 'android': |
259 # The best way to ensure the old build directory is not used is to | 222 # The best way to ensure the old build directory is not used is to |
260 # remove it. | 223 # remove it. |
261 build_dir = self.m.chromium.c.build_dir.join( | 224 build_dir = self.m.chromium.c.build_dir.join( |
262 self.m.chromium.c.build_config_fs) | 225 self.m.chromium.c.build_config_fs) |
263 self.m.file.rmtree('build directory', build_dir) | 226 self.m.file.rmtree('build directory', build_dir) |
264 | 227 |
265 # The way android builders on tryserver.chromium.perf are archived is | 228 # The way android builders on tryserver.chromium.perf are archived is |
266 # different from builders on chromium.perf. In order to support both | 229 # different from builders on chromium.perf. In order to support both |
(...skipping 22 matching lines...) Expand all Loading... |
289 shutil.move(sys.argv[1], sys.argv[2]) | 252 shutil.move(sys.argv[1], sys.argv[2]) |
290 """, | 253 """, |
291 args=[zip_dir, build_dir]) | 254 args=[zip_dir, build_dir]) |
292 else: | 255 else: |
293 self.m.chromium_tests.download_and_unzip_build( | 256 self.m.chromium_tests.download_and_unzip_build( |
294 mastername, buildername, update_step, bot_db, | 257 mastername, buildername, update_step, bot_db, |
295 build_archive_url=build_archive_url, | 258 build_archive_url=build_archive_url, |
296 build_revision=test_config_params['parent_got_revision'], | 259 build_revision=test_config_params['parent_got_revision'], |
297 override_bot_type='tester') | 260 override_bot_type='tester') |
298 | 261 |
299 tests = [self.m.chromium_tests.steps.BisectTest(test_config_params)] | 262 tests = [ |
| 263 self.m.chromium_tests.steps.BisectTest( |
| 264 test_config_params, **kwargs)] |
300 | 265 |
301 if not tests: # pragma: no cover | 266 if not tests: # pragma: no cover |
302 return | 267 return |
303 self.m.chromium_swarming.configure_swarming( | 268 self.m.chromium_swarming.configure_swarming( |
304 'chromium', precommit=False, mastername=mastername) | 269 'chromium', precommit=False, mastername=mastername) |
305 test_runner = self.m.chromium_tests.create_test_runner(self.m, tests) | 270 test_runner = self.m.chromium_tests.create_test_runner(self.m, tests) |
306 | 271 |
307 bot_config_object = self.m.chromium_tests.create_bot_config_object( | 272 bot_config_object = self.m.chromium_tests.create_bot_config_object( |
308 mastername, buildername) | 273 mastername, buildername) |
309 with self.m.chromium_tests.wrap_chromium_tests(bot_config_object, tests): | 274 with self.m.chromium_tests.wrap_chromium_tests(bot_config_object, tests): |
310 if self.m.chromium.c.TARGET_PLATFORM == 'android' and not skip_download: | 275 if self.m.chromium.c.TARGET_PLATFORM == 'android' and not skip_download: |
311 deploy_apks = [] | 276 deploy_apks = [] |
312 deploy_args = [] | 277 deploy_args = [] |
313 if self.internal_bisect: # pragma: no cover | 278 if self.internal_bisect: # pragma: no cover |
314 deploy_args = list(bot_config['deploy_args']) | 279 deploy_args = list(bot_config['deploy_args']) |
315 deploy_apks = bot_config.get('deploy_apks') | 280 deploy_apks = bot_config.get('deploy_apks') |
316 if deploy_apks: | 281 if deploy_apks: |
317 deploy_args.extend([ | 282 deploy_args.extend([ |
318 '--apks', | 283 '--apks', |
319 ','.join(str(self.m.chromium_android.apk_path(apk)) | 284 ','.join(str(self.m.chromium_android.apk_path(apk)) |
320 for apk in deploy_apks)]) | 285 for apk in deploy_apks)]) |
321 else: | 286 else: |
322 if bot_config.get('webview'): | 287 if bot_config.get('webview'): |
323 deploy_apks = ['SystemWebView.apk', 'SystemWebViewShell.apk'] | 288 deploy_apks = ['SystemWebView.apk', 'SystemWebViewShell.apk'] |
324 else: | 289 else: |
325 deploy_apks = ['ChromePublic.apk'] | 290 deploy_apks = ['ChromePublic.apk'] |
326 self.deploy_apk_on_device( | 291 self.deploy_apk_on_device( |
327 self.full_deploy_script, deploy_apks, deploy_args) | 292 self.full_deploy_script, deploy_apks, deploy_args) |
328 test_runner() | 293 test_runner() |
| 294 return tests[0].run_results |
329 | 295 |
330 def deploy_apk_on_device(self, deploy_script, deploy_apks, deploy_args): | 296 def deploy_apk_on_device(self, deploy_script, deploy_apks, deploy_args): |
331 """Installs apk on the android device.""" | 297 """Installs apk on the android device.""" |
332 if deploy_script: # pragma: no cover | 298 if deploy_script: # pragma: no cover |
333 self.full_deploy_on_device(deploy_script, deploy_args) | 299 self.full_deploy_on_device(deploy_script, deploy_args) |
334 else: | 300 else: |
335 for apk in deploy_apks: | 301 for apk in deploy_apks: |
336 self.m.chromium_android.adb_install_apk(apk) | 302 self.m.chromium_android.adb_install_apk(apk) |
337 | 303 |
338 def full_deploy_on_device(self, deploy_script, args=None): # pragma: no cover | 304 def full_deploy_on_device(self, deploy_script, args=None): # pragma: no cover |
(...skipping 29 matching lines...) Expand all Loading... |
368 api: The recipe api object. | 334 api: The recipe api object. |
369 update_step: Extra update_step to, used for some job types. | 335 update_step: Extra update_step to, used for some job types. |
370 bot_db: A BotConfigAndTestDB object, used for some job types. | 336 bot_db: A BotConfigAndTestDB object, used for some job types. |
371 kwargs: Args to use only for legacy bisect. | 337 kwargs: Args to use only for legacy bisect. |
372 """ | 338 """ |
373 flags = {} | 339 flags = {} |
374 if kwargs.get('do_not_nest_wait_for_revision'): | 340 if kwargs.get('do_not_nest_wait_for_revision'): |
375 flags['do_not_nest_wait_for_revision'] = kwargs.pop( | 341 flags['do_not_nest_wait_for_revision'] = kwargs.pop( |
376 'do_not_nest_wait_for_revision') | 342 'do_not_nest_wait_for_revision') |
377 if bot_db is None: # pragma: no cover | 343 if bot_db is None: # pragma: no cover |
378 self.bot_db = api.chromium_tests.create_bot_db_from_master_dict( | 344 self.bot_db = api.chromium_tests.create_bot_db_from_master_dict('', None) |
379 '', None, None) | |
380 else: | 345 else: |
381 self.bot_db = bot_db | 346 self.bot_db = bot_db |
382 | 347 |
383 context = {} | 348 context = {} |
384 if self.working_dir: | 349 if self.working_dir: |
385 context['cwd'] = self.working_dir | 350 context['cwd'] = self.working_dir |
386 | 351 |
387 with api.step.context(context): | 352 with api.step.context(context): |
388 affected_files = self.m.tryserver.get_files_affected_by_patch() | 353 affected_files = self.m.tryserver.get_files_affected_by_patch() |
389 # Skip device setup for internal bisect as it is taken care in | 354 # Skip device setup for internal bisect as it is taken care in |
390 # internal recipes. | 355 # internal recipes. |
391 if (api.chromium.c.TARGET_PLATFORM == 'android' and | 356 if (api.chromium.c.TARGET_PLATFORM == 'android' and |
392 not self.internal_bisect): | 357 not self.internal_bisect): |
393 api.chromium_android.common_tests_setup_steps( | 358 api.chromium_android.common_tests_setup_steps( |
394 perf_setup=True, remove_system_webview=True) | 359 perf_setup=True, remove_system_webview=True) |
395 api.chromium.runhooks() | 360 api.chromium.runhooks() |
396 try: | 361 try: |
397 # Run legacy bisect script if the patch contains bisect.cfg. | |
398 if BISECT_CONFIG_FILE in affected_files: | 362 if BISECT_CONFIG_FILE in affected_files: |
399 api.step('***LEGACY BISECT (deprecated)***', []) | 363 api.step('***LEGACY BISECT HAS BEEN DEPRECATED***', []) |
400 self.run_bisect_script(**kwargs) | 364 api.step.active_result.presentation.status = api.step.FAILURE |
| 365 return |
401 elif api.properties.get('bisect_config'): | 366 elif api.properties.get('bisect_config'): |
402 # We can distinguish between a config for a full bisect vs a single | 367 # We can distinguish between a config for a full bisect vs a single |
403 # test by checking for the presence of the good_revision key. | 368 # test by checking for the presence of the good_revision key. |
404 if api.properties.get('bisect_config').get('good_revision'): | 369 if api.properties.get('bisect_config').get('good_revision'): |
405 api.step('***BISECT***', []) | 370 api.step('***BISECT***', []) |
406 local_bisect.perform_bisect(self, **flags) # pragma: no cover | 371 local_bisect.perform_bisect(self, **flags) |
407 else: | 372 else: |
408 api.step('***SINGLE TEST (deprecated)***', []) | 373 api.step('***SINGLE TEST (deprecated)***', []) |
409 self.start_test_run_for_bisect(update_step, self.bot_db, | 374 self.start_test_run_for_bisect(update_step, self.bot_db, |
410 api.properties) | 375 api.properties) |
411 else: | 376 else: |
412 api.step('***PERF TRYJOB***', []) | 377 api.step('***PERF TRYJOB***', []) |
413 self.m.perf_try.start_perf_try_job( | 378 self.m.perf_try.start_perf_try_job( |
414 api, affected_files, update_step, self.bot_db) | 379 api, affected_files, update_step, self.bot_db) |
415 finally: | 380 finally: |
416 if api.chromium.c.TARGET_PLATFORM == 'android': | 381 if api.chromium.c.TARGET_PLATFORM == 'android': |
417 if self.internal_bisect: # pragma: no cover | 382 if self.internal_bisect: # pragma: no cover |
418 api.chromium_android.init_and_sync( | 383 api.chromium_android.init_and_sync( |
419 gclient_config=api.chromium_android.c.internal_dir_name, | 384 gclient_config=api.chromium_android.c.internal_dir_name, |
420 use_bot_update=True) | 385 use_bot_update=True) |
421 else: | 386 else: |
422 self.ensure_checkout() | 387 self.ensure_checkout() |
423 api.chromium_android.common_tests_final_steps() | 388 api.chromium_android.common_tests_final_steps() |
| 389 |
| 390 |
| 391 def stat_compare(self, values_a, values_b, metric, |
| 392 output_format='chartjson', **kwargs): |
| 393 """Compares samples using catapult's statistics implementation. |
| 394 |
| 395 Args: |
| 396 values_a, values_b: lists of paths to the json files containing the values |
| 397 produced by the test. |
| 398 metric: the name of the metric as sent by dashboard. |
| 399 output_format: 'chartjson', 'valueset' or 'buildbot' |
| 400 |
| 401 Returns: |
| 402 a dict containing 'result' which may be True, False or 'needMoreData', as |
| 403 well as details about each sample ('debug_values', 'mean' and 'std_dev'). |
| 404 |
| 405 """ |
| 406 args = [','.join(map(str, values_a)), |
| 407 ','.join(map(str, values_b)), |
| 408 metric, |
| 409 '--' + output_format] |
| 410 |
| 411 script = self.m.path['catapult'].join( |
| 412 'tracing', 'bin', 'compare_samples_cmdline') |
| 413 return self.m.python( |
| 414 'Compare samples', |
| 415 script=script, |
| 416 args=args, |
| 417 stdout=self.m.json.output(), |
| 418 **kwargs).stdout |
OLD | NEW |