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

Side by Side Diff: scripts/slave/recipe_modules/auto_bisect/bisector.py

Issue 1339613005: Refactoring scripts that wait for buildbot jobs to complete. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@hax
Patch Set: . Created 5 years, 3 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 import json 5 import json
6 import re 6 import re
7 7
8 from . import bisect_results 8 from . import bisect_results
9 from . import depot_config 9 from . import depot_config
10 from . import revision_state 10 from . import revision_state
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 """Waits for all revisions in list to finish.""" 446 """Waits for all revisions in list to finish."""
447 while any([r.in_progress for r in revision_list]): 447 while any([r.in_progress for r in revision_list]):
448 revision_list.remove(self.wait_for_any(revision_list)) 448 revision_list.remove(self.wait_for_any(revision_list))
449 449
450 def sleep_until_next_revision_ready(self, revision_list): 450 def sleep_until_next_revision_ready(self, revision_list):
451 """Produces a single step that sleeps until any revision makes progress. 451 """Produces a single step that sleeps until any revision makes progress.
452 452
453 A revision is considered to make progress when a build file is uploaded to 453 A revision is considered to make progress when a build file is uploaded to
454 the appropriate bucket, or when buildbot test job is complete. 454 the appropriate bucket, or when buildbot test job is complete.
455 """ 455 """
456 gsutil_path = self.api.m.gsutil.get_gsutil_path() 456
457 name = 'Waiting for revision ' + revision_list[0].revision_string 457 revision_mapping = {}
458 if len(revision_list) > 1: 458 gs_jobs = []
459 name += ' and %d other revision(s).' % (len(revision_list) - 1) 459 buildbot_jobs = []
460
461 for revision in revision_list:
462 url = revision.get_next_url()
463 buildbot_job = revision.get_buildbot_locator()
464 if url:
465 gs_jobs.append({'type': 'gs', 'location': url})
466 revision_mapping[url] = revision
467 if buildbot_job:
468 buildbot_job['type'] = 'buildbot'
prasadv 2015/09/17 22:33:34 Just curious, why 'type' is not added in get_build
RobertoCN 2015/09/19 00:32:54 Because the 'type': 'gs' is just 2 lines above. Bu
469 buildbot_jobs.append(buildbot_job)
470 revision_mapping[buildbot_job['job_name']] = revision
471
472 jobs_config = {'jobs': buildbot_jobs + gs_jobs}
473
460 script = self.api.resource('wait_for_any.py') 474 script = self.api.resource('wait_for_any.py')
461 args_list = [gsutil_path] 475 args_list = [self.api.m.gsutil.get_gsutil_path()] if gs_jobs else []
462 url_mapping = {r.get_next_url(): r for r in revision_list} 476
463 bb_locator_mapping = {r.get_buildbot_locator(): r for r in revision_list}
464 bb_locator_list = bb_locator_mapping.keys()
465 url_list = url_mapping.keys()
466 args_list += [url for url in url_list if url and url is not None]
467 args_list += [entry for entry in bb_locator_list
468 if entry and entry is not None]
469 args_list.append(
470 '--timeout=%d' % (
471 self.get_build_timeout_minutes() * 60))
472 try: 477 try:
478 step_name = 'Waiting for revision ' + revision_list[0].revision_string
479 if len(revision_list) > 1:
480 step_name += ' and %d other revision(s).' % (len(revision_list) - 1)
473 step_result = self.api.m.python( 481 step_result = self.api.m.python(
474 str(name), 482 str(step_name),
475 script, 483 script,
476 args_list, 484 args_list,
477 stdout=self.api.m.raw_io.output()) 485 stdout=self.api.m.json.output(),
486 stdin=self.api.m.json.input(jobs_config))
478 except self.api.m.step.StepFailure: # pragma: no cover 487 except self.api.m.step.StepFailure: # pragma: no cover
479 # StepFailure is interpreted as a timeout. 488 # StepFailure is interpreted as a timeout.
480 for revision in revision_list: 489 for revision in revision_list:
481 revision.status = revision_state.RevisionState.FAILED 490 revision.status = revision_state.RevisionState.FAILED
482 return None 491 return None
prasadv 2015/09/17 22:33:34 When this happens what should be the behavior of w
RobertoCN 2015/09/19 00:32:54 Changed it so that we keep the step red and procee
RobertoCN 2015/09/19 00:32:54 If wait_for_any.py errors out, all revisions will
483 step_output = step_result.stdout or 'Build finished: Unknown' 492 if not step_result.stdout:
484 for line in step_output.splitlines(): 493 return None
485 if line.startswith('Build finished: '): 494 step_results = step_result.stdout
486 finished_url = line[len('Build finished: '):].strip() 495 failed_jobs = step_results.get('failed', [])
487 return url_mapping.get(finished_url) 496 completed_jobs = step_results.get('completed', [])
488 if line.startswith('Failed build url: '): # pragma: no cover 497 assert failed_jobs or completed_jobs
489 url = line[len('Failed build url: '):].strip() 498 # Marked all failed builds as failed
490 step_result.presentation.links['Failed build'] = url 499 for job in failed_jobs:
prasadv 2015/09/17 22:33:34 This is missing.
RobertoCN 2015/09/19 00:32:54 Done.
491 if line.startswith('Build failed: '): # pragma: no cover 500 last_failed_revision = revision_mapping[str(job.get(
492 failed_build_locator = line[len('Build failed: '):].strip() 501 'location', job.get('job_name')))]
493 failed_build = bb_locator_mapping.get(failed_build_locator) 502 last_failed_revision.status = revision_state.RevisionState.FAILED
494 failed_build.status = revision_state.RevisionState.FAILED 503
495 return failed_build 504 # Return a completed job if availavle
505 for job in completed_jobs:
506 return revision_mapping[str(job.get(
507 'location', job.get('job_name')))]
508
509 # Or return any of the failed revisions
510 return last_failed_revision
496 511
497 def wait_for_any(self, revision_list): 512 def wait_for_any(self, revision_list):
498 """Waits for any of the revisions in the list to finish its job(s).""" 513 """Waits for any of the revisions in the list to finish its job(s)."""
499 while True: 514 while True:
500 if not revision_list or not any( 515 if not revision_list or not any(
501 r.in_progress or r.tested for r in revision_list): # pragma: no cover 516 r.in_progress or r.tested for r in revision_list): # pragma: no cover
502 break 517 break
503 518
504 finished_revision = self.sleep_until_next_revision_ready(revision_list) 519 finished_revision = self.sleep_until_next_revision_ready(revision_list)
505 520
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 recipe_tester_name = self.bisect_config.get('recipe_tester_name') 568 recipe_tester_name = self.bisect_config.get('recipe_tester_name')
554 original_bot_name = self.bisect_config.get('original_bot_name', '') 569 original_bot_name = self.bisect_config.get('original_bot_name', '')
555 if recipe_tester_name: 570 if recipe_tester_name:
556 return recipe_tester_name 571 return recipe_tester_name
557 elif 'win' in original_bot_name: # pragma: no cover 572 elif 'win' in original_bot_name: # pragma: no cover
558 return 'win64_nv_tester' 573 return 'win64_nv_tester'
559 else: # pragma: no cover 574 else: # pragma: no cover
560 # Reasonable fallback 575 # Reasonable fallback
561 return 'linux_perf_tester' 576 return 'linux_perf_tester'
562 577
563 def get_build_timeout_minutes(self):
564 if 'win' in self.get_perf_tester_name():
565 return 4 * 60
566 return 2 * 60
567
568 def get_builder_bot_for_this_platform(self): 578 def get_builder_bot_for_this_platform(self):
569 # TODO(prasadv): We should refactor these codes to remove hard coded values. 579 # TODO(prasadv): We should refactor these codes to remove hard coded values.
570 bot_name = self.get_perf_tester_name() 580 bot_name = self.get_perf_tester_name()
571 if 'win' in bot_name: 581 if 'win' in bot_name:
572 if any(b in bot_name for b in ['x64', 'gpu']): 582 if any(b in bot_name for b in ['x64', 'gpu']):
573 return 'winx64_bisect_builder' 583 return 'winx64_bisect_builder'
574 return 'win_perf_bisect_builder' 584 return 'win_perf_bisect_builder'
575 585
576 if 'android' in bot_name: 586 if 'android' in bot_name:
577 if 'nexus9' in bot_name: 587 if 'nexus9' in bot_name:
(...skipping 28 matching lines...) Expand all
606 616
607 We have seen on several occasions that the local master branch gets reset 617 We have seen on several occasions that the local master branch gets reset
608 to previous revisions and also detached head states. Running this should 618 to previous revisions and also detached head states. Running this should
609 take care of either situation. 619 take care of either situation.
610 """ 620 """
611 # TODO(robertocn): Investigate what causes the states mentioned in the 621 # TODO(robertocn): Investigate what causes the states mentioned in the
612 # docstring in the first place. 622 # docstring in the first place.
613 self.api.m.git('update-ref', 'refs/heads/master', 623 self.api.m.git('update-ref', 'refs/heads/master',
614 'refs/remotes/origin/master') 624 'refs/remotes/origin/master')
615 self.api.m.git('checkout', 'master', cwd=self.api.m.path['checkout']) 625 self.api.m.git('checkout', 'master', cwd=self.api.m.path['checkout'])
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698