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

Side by Side Diff: scripts/slave/recipe_modules/perf_try/api.py

Issue 2113033002: Reland "Build delegation for perf tryjobs" (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: update step data and expectation files Created 4 years, 5 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
OLDNEW
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 perf try job recipe module. 5 """API for the perf try job recipe module.
6 6
7 This API is meant to enable the perf try job recipe on any chromium-supported 7 This API is meant to enable the perf try job recipe on 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 re 11 import re
12 import urllib 12 import urllib
13 import uuid
13 14
14 from recipe_engine import recipe_api 15 from recipe_engine import recipe_api
16 from . import build_state
15 17
16 PERF_CONFIG_FILE = 'tools/run-perf-test.cfg' 18 PERF_CONFIG_FILE = 'tools/run-perf-test.cfg'
17 WEBKIT_PERF_CONFIG_FILE = 'third_party/WebKit/Tools/run-perf-test.cfg' 19 WEBKIT_PERF_CONFIG_FILE = 'third_party/WebKit/Tools/run-perf-test.cfg'
18 PERF_BENCHMARKS_PATH = 'tools/perf/benchmarks' 20 PERF_BENCHMARKS_PATH = 'tools/perf/benchmarks'
19 PERF_MEASUREMENTS_PATH = 'tools/perf/measurements' 21 PERF_MEASUREMENTS_PATH = 'tools/perf/measurements'
20 BUILDBOT_BUILDERNAME = 'BUILDBOT_BUILDERNAME' 22 BUILDBOT_BUILDERNAME = 'BUILDBOT_BUILDERNAME'
21 BENCHMARKS_JSON_FILE = 'benchmarks.json' 23 BENCHMARKS_JSON_FILE = 'benchmarks.json'
22 24
23 CLOUD_RESULTS_LINK = (r'\s(?P<VALUES>http://storage.googleapis.com/' 25 CLOUD_RESULTS_LINK = (r'\s(?P<VALUES>http://storage.googleapis.com/'
24 'chromium-telemetry/html-results/results-[a-z0-9-_]+)\s') 26 'chromium-telemetry/html-results/results-[a-z0-9-_]+)\s')
25 PROFILER_RESULTS_LINK = (r'\s(?P<VALUES>https://console.developers.google.com/' 27 PROFILER_RESULTS_LINK = (r'\s(?P<VALUES>https://console.developers.google.com/'
26 'm/cloudstorage/b/[a-z-]+/o/profiler-[a-z0-9-_.]+)\s') 28 'm/cloudstorage/b/[a-z-]+/o/profiler-[a-z0-9-_.]+)\s')
27 RESULTS_BANNER = """ 29 RESULTS_BANNER = """
28 ===== PERF TRY JOB RESULTS ===== 30 ===== PERF TRY JOB RESULTS =====
29 31
30 Test Command: %(command)s 32 Test Command: %(command)s
31 Test Metric: %(metric)s 33 Test Metric: %(metric)s
32 Relative Change: %(relative_change).05f%% 34 Relative Change: %(relative_change).05f%%
33 Standard Error: +- %(std_err).05f delta 35 Standard Error: +- %(std_err).05f delta
34 36
35 %(results)s 37 %(results)s
36 """ 38 """
37 39 SERVICE_ACCOUNT = 'chromium-bisect'
38 40
39 class PerfTryJobApi(recipe_api.RecipeApi): 41 class PerfTryJobApi(recipe_api.RecipeApi):
40 42
41 def __init__(self, *args, **kwargs): 43 def __init__(self, *args, **kwargs):
42 super(PerfTryJobApi, self).__init__(*args, **kwargs) 44 super(PerfTryJobApi, self).__init__(*args, **kwargs)
43 45
44 def start_perf_try_job(self, affected_files, bot_update_step, bot_db): 46 def start_perf_try_job(self, affected_files, bot_update_step, bot_db):
45 """Entry point pert tryjob or CQ tryjob.""" 47 """Entry point pert tryjob or CQ tryjob."""
46 perf_config = self._get_perf_config(affected_files) 48 perf_config = self._get_perf_config(affected_files)
47 if perf_config: 49 if perf_config:
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 # try job leading to unwanted cache and temp data. The best way to 189 # try job leading to unwanted cache and temp data. The best way to
188 # ensure the old build directory is removed before doing any 190 # ensure the old build directory is removed before doing any
189 # compilation. 191 # compilation.
190 self.m.file.rmtree( 192 self.m.file.rmtree(
191 'build directory', 193 'build directory',
192 self.m.chromium.c.build_dir.join(self.m.chromium.c.build_config_fs)) 194 self.m.chromium.c.build_dir.join(self.m.chromium.c.build_config_fs))
193 self.m.chromium_tests.transient_check( 195 self.m.chromium_tests.transient_check(
194 update_step, 196 update_step,
195 lambda transform_name: self.m.chromium_tests.run_mb_and_compile( 197 lambda transform_name: self.m.chromium_tests.run_mb_and_compile(
196 compile_targets, None, name_suffix=transform_name(''))) 198 compile_targets, None, name_suffix=transform_name('')))
197 else: 199 else: # pragma: no cover
198 self.m.chromium_tests.run_mb_and_compile( 200 self.m.chromium_tests.run_mb_and_compile(
199 compile_targets, None, name_suffix=' %s' % name) 201 compile_targets, None, name_suffix=' %s' % name)
200 202
201 def _run_test(self, cfg, **kwargs): 203 def _run_test(self, cfg, **kwargs):
202 """Runs test from config and return results.""" 204 """Runs test from config and return results."""
203 values, overall_output, retcodes = self.m.bisect_tester.run_test( 205 values, overall_output, retcodes = self.m.bisect_tester.run_test(
204 cfg, **kwargs) 206 cfg, **kwargs)
205 all_values = self.m.bisect_tester.digest_run_results(values, retcodes, cfg) 207 all_values = self.m.bisect_tester.digest_run_results(values, retcodes, cfg)
206 overall_success = True 208 overall_success = True
207 if (not kwargs.get('allow_flakes', True) and 209 if (not kwargs.get('allow_flakes', True) and
208 cfg.get('test_type', 'perf') != 'return_code'): 210 cfg.get('test_type', 'perf') != 'return_code'):
209 overall_success = all(v == 0 for v in retcodes) 211 overall_success = all(v == 0 for v in retcodes)
210 return { 212 return {
211 'results': all_values, 213 'results': all_values,
212 'ret_code': overall_success, 214 'ret_code': overall_success,
213 'output': ''.join(overall_output) 215 'output': ''.join(overall_output)
214 } 216 }
215 217
216 def _build_and_run_tests(self, cfg, update_step, bot_db, revision, 218 def _build_and_run_tests(self, cfg, update_step, bot_db, revision_hash,
217 **kwargs): 219 **kwargs):
218 """Compiles binaries and runs tests for a given a revision.""" 220 """Compiles binaries and runs tests for a given a revision."""
219 update_step = self._checkout_revision(update_step, bot_db, revision) 221 with_patch = kwargs.get('name') == 'With Patch'
220 self._compile(kwargs['name'], self.m.properties['mastername'], 222 update_step = self._checkout_revision(update_step, bot_db, revision_hash)
221 self.m.properties['buildername'], update_step, bot_db) 223 if update_step.presentation.properties:
222 224 revision_hash = update_step.presentation.properties['got_revision']
225 revision = build_state.BuildState(self, revision_hash, with_patch)
226 # request build and wait for it only when the build is nonexistent
227 if with_patch or not self._gsutil_file_exists(revision.build_file_path):
228 try:
229 self._request_build(revision, with_patch)
230 self._wait_for(revision)
231 except Exception, e:
232 raise self.m.step.StepFailure('Error occurs when building %s: %s' % (
233 revision.build_id, str(e)))
234 self._download_build(update_step, bot_db, revision)
223 if self.m.chromium.c.TARGET_PLATFORM == 'android': 235 if self.m.chromium.c.TARGET_PLATFORM == 'android':
224 self.m.chromium_android.adb_install_apk('ChromePublic.apk') 236 self.m.chromium_android.adb_install_apk('ChromePublic.apk')
225 237
226 return self._run_test(cfg, **kwargs) 238 return self._run_test(cfg, **kwargs)
227 239
240 def _gsutil_file_exists(self, path):
241 """Returns True if a file exists at the given GS path."""
242 try:
243 self.m.gsutil(['ls', path], name='exists')
244 except self.m.step.StepFailure: # pragma: no cover
245 return False
246 return True
247
248 # Duplicate code from auto_bisect.revision_state._request_build
249 def _request_build(self, revision, with_patch):
250 if self.m.chromium.c.TARGET_PLATFORM == 'android':
251 self.m.chromium_android.clean_local_files()
252 else:
253 # Removes any chrome temporary files or build.dead directories.
254 self.m.chromium.cleanup_temp()
255 if with_patch:
256 properties = {
257 'parent_got_revision': revision.commit_hash,
258 'clobber': True,
259 'build_archive_url': revision.build_file_path,
260 'issue': self.m.properties['issue'],
261 'patch_storage': self.m.properties['patch_storage'],
262 'patchset': self.m.properties['patchset'],
263 'rietveld': self.m.properties['rietveld']
264 }
265 else:
266 properties = {
267 'parent_got_revision': revision.commit_hash,
268 'clobber': True,
269 'build_archive_url': revision.build_file_path,
270 }
271 bot_name = self.get_builder_bot_for_this_platform()
272 if self.m.properties.get('is_test'):
273 client_operation_id = '123456'
274 else:
275 client_operation_id = uuid.uuid4().hex # pragma: no cover
276 build_details = {
277 'bucket': 'master.' + self.m.properties['mastername'],
278 'parameters': {
279 'buildername': bot_name,
280 'properties': properties
281 },
282 'client_operation_id': client_operation_id,
283 'tags':{}
284 }
285 result = self.m.buildbucket.put(
286 [build_details],
287 self.m.service_account.get_json_path(SERVICE_ACCOUNT))
288 revision.build_id = result.stdout['results'][0]['build']['id']
289
290
291 def _wait_for(self, revision): # pragma: no cover
292 while True:
293 if revision.is_completed():
294 if revision.is_build_archived:
295 break
296 raise self.m.step.StepFailure('Build %s fails' % revision.build_id)
297 else:
298 self.m.python.inline(
299 'sleeping',
300 """
301 import sys
302 import time
303 time.sleep(20*60)
304 sys.exit(0)
305 """)
306
307 # Duplicate code from auto_bisect.api.start_test_run_for_bisect
308 def _download_build(self, update_step, bot_db,
309 revision, run_locally=False,
310 skip_download=False):
311 mastername = self.m.properties.get('mastername')
312 buildername = self.m.properties.get('buildername')
313 bot_config = bot_db.get_bot_config(mastername, buildername)
314 build_archive_url = revision.build_file_path
315 if not skip_download:
316 if self.m.chromium.c.TARGET_PLATFORM == 'android':
317 # The best way to ensure the old build directory is not used is to
318 # remove it.
319 build_dir = self.m.chromium.c.build_dir.join(
320 self.m.chromium.c.build_config_fs)
321 self.m.file.rmtree('build directory', build_dir)
322
323 # The way android builders on tryserver.chromium.perf are archived is
324 # different from builders on chromium.perf. In order to support both
325 # forms of archives, we added this temporary hack until builders are
326 # fixed. See http://crbug.com/535218.
327 zip_dir = self.m.path.join(self.m.path['checkout'], 'full-build-linux')
328 if self.m.path.exists(zip_dir): # pragma: no cover
329 self.m.file.rmtree('full-build-linux directory', zip_dir)
330 gs_bucket = 'gs://%s/' % revision.bucket
331 archive_path = build_archive_url[len(gs_bucket):]
332 self.m.chromium_android.download_build(
333 bucket=bot_config['bucket'],
334 path=archive_path)
335
336 # The way android builders on tryserver.chromium.perf are archived is
337 # different from builders on chromium.perf. In order to support both
338 # forms of archives, we added this temporary hack until builders are
339 # fixed. See http://crbug.com/535218.
340 if self.m.path.exists(zip_dir): # pragma: no cover
341 self.m.python.inline(
342 'moving full-build-linux to out/Release',
343 """
344 import shutil
345 import sys
346 shutil.move(sys.argv[1], sys.argv[2])
347 """,
348 args=[zip_dir, build_dir])
349 else:
350 self.m.chromium_tests.download_and_unzip_build(
351 mastername, buildername, update_step, bot_db,
352 build_archive_url=build_archive_url,
353 build_revision=revision.commit_hash,
354 override_bot_type='tester')
355
356 # Duplicate code from auto_bisect.bisector.get_builder_bot_for_this_platform
357 def get_builder_bot_for_this_platform(self): # pragma: no cover
358 bot_name = self.m.properties.get('buildername', '')
359 if 'win' in bot_name:
360 if any(b in bot_name for b in ['x64', 'gpu']):
361 return 'winx64_bisect_builder'
362 return 'win_perf_bisect_builder'
363
364 if 'android' in bot_name:
365 if 'nexus9' in bot_name:
366 return 'android_arm64_perf_bisect_builder'
367 return 'android_perf_bisect_builder'
368
369 if 'mac' in bot_name:
370 return 'mac_perf_bisect_builder'
371
372 return 'linux_perf_bisect_builder'
373
228 def _load_config_file(self, name, src_path, **kwargs): 374 def _load_config_file(self, name, src_path, **kwargs):
229 """Attempts to load the specified config file and grab config dict.""" 375 """Attempts to load the specified config file and grab config dict."""
230 step_result = self.m.python( 376 step_result = self.m.python(
231 name, 377 name,
232 self.resource('load_config_to_json.py'), 378 self.resource('load_config_to_json.py'),
233 ['--source', src_path, '--output_json', self.m.json.output()], 379 ['--source', src_path, '--output_json', self.m.json.output()],
234 **kwargs) 380 **kwargs)
235 if not step_result.json.output: # pragma: no cover 381 if not step_result.json.output: # pragma: no cover
236 raise self.m.step.StepFailure('Loading config file failed. [%s]' % 382 raise self.m.step.StepFailure('Loading config file failed. [%s]' %
237 src_path) 383 src_path)
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
511 657
512 def _prepend_src_to_path_in_command(test_cfg): 658 def _prepend_src_to_path_in_command(test_cfg):
513 command_to_run = [] 659 command_to_run = []
514 for v in test_cfg.get('command').split(): 660 for v in test_cfg.get('command').split():
515 if v in ['./tools/perf/run_benchmark', 661 if v in ['./tools/perf/run_benchmark',
516 'tools/perf/run_benchmark', 662 'tools/perf/run_benchmark',
517 'tools\\perf\\run_benchmark']: 663 'tools\\perf\\run_benchmark']:
518 v = 'src/tools/perf/run_benchmark' 664 v = 'src/tools/perf/run_benchmark'
519 command_to_run.append(v) 665 command_to_run.append(v)
520 test_cfg.update({'command': ' '.join(command_to_run)}) 666 test_cfg.update({'command': ' '.join(command_to_run)})
OLDNEW
« no previous file with comments | « scripts/slave/recipe_modules/perf_try/__init__.py ('k') | scripts/slave/recipe_modules/perf_try/build_state.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698