OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Chromium auto-bisect tool | 6 """Chromium auto-bisect tool |
7 | 7 |
8 This script bisects a range of commits using binary search. It starts by getting | 8 This script bisects a range of commits using binary search. It starts by getting |
9 reference values for the specified "good" and "bad" commits. Then, for revisions | 9 reference values for the specified "good" and "bad" commits. Then, for revisions |
10 in between, it will get builds, run tests and classify intermediate revisions as | 10 in between, it will get builds, run tests and classify intermediate revisions as |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
121 # Git master branch name. | 121 # Git master branch name. |
122 BISECT_MASTER_BRANCH = 'master' | 122 BISECT_MASTER_BRANCH = 'master' |
123 # File to store 'git diff' content. | 123 # File to store 'git diff' content. |
124 BISECT_PATCH_FILE = 'deps_patch.txt' | 124 BISECT_PATCH_FILE = 'deps_patch.txt' |
125 # SVN repo where the bisect try jobs are submitted. | 125 # SVN repo where the bisect try jobs are submitted. |
126 PERF_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try-perf' | 126 PERF_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try-perf' |
127 FULL_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try' | 127 FULL_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try' |
128 ANDROID_CHROME_SVN_REPO_URL = ('svn://svn.chromium.org/chrome-try-internal/' | 128 ANDROID_CHROME_SVN_REPO_URL = ('svn://svn.chromium.org/chrome-try-internal/' |
129 'try-perf') | 129 'try-perf') |
130 | 130 |
131 | |
131 class RunGitError(Exception): | 132 class RunGitError(Exception): |
132 | 133 |
133 def __str__(self): | 134 def __str__(self): |
134 return '%s\nError executing git command.' % self.args[0] | 135 return '%s\nError executing git command.' % self.args[0] |
135 | 136 |
136 | 137 |
137 def GetSHA1HexDigest(contents): | 138 def GetSHA1HexDigest(contents): |
138 """Returns SHA1 hex digest of the given string.""" | 139 """Returns SHA1 hex digest of the given string.""" |
139 return hashlib.sha1(contents).hexdigest() | 140 return hashlib.sha1(contents).hexdigest() |
140 | 141 |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
454 current_arg_split = current_arg.split('=') | 455 current_arg_split = current_arg.split('=') |
455 | 456 |
456 # Check 2 cases, --arg=<val> and --arg <val> | 457 # Check 2 cases, --arg=<val> and --arg <val> |
457 if len(current_arg_split) == 2: | 458 if len(current_arg_split) == 2: |
458 arg_dict[arg_to_parse] = current_arg_split[1] | 459 arg_dict[arg_to_parse] = current_arg_split[1] |
459 elif i + 1 < len(command_args): | 460 elif i + 1 < len(command_args): |
460 arg_dict[arg_to_parse] = command_args[i+1] | 461 arg_dict[arg_to_parse] = command_args[i+1] |
461 | 462 |
462 path_to_generate = os.path.join('tools', 'perf', 'generate_profile') | 463 path_to_generate = os.path.join('tools', 'perf', 'generate_profile') |
463 | 464 |
464 if arg_dict.has_key('--profile-dir') and arg_dict.has_key('--browser'): | 465 if '--profile-dir' in arg_dict and '--browser' in arg_dict: |
465 profile_path, profile_type = os.path.split(arg_dict['--profile-dir']) | 466 profile_path, profile_type = os.path.split(arg_dict['--profile-dir']) |
466 return not bisect_utils.RunProcess(['python', path_to_generate, | 467 return not bisect_utils.RunProcess( |
467 '--profile-type-to-generate', profile_type, | 468 [ |
468 '--browser', arg_dict['--browser'], '--output-dir', profile_path]) | 469 'python', path_to_generate, |
470 '--profile-type-to-generate', profile_type, | |
471 '--browser', arg_dict['--browser'], | |
472 '--output-dir', profile_path | |
473 ]) | |
469 return False | 474 return False |
470 return True | 475 return True |
471 | 476 |
472 | 477 |
473 def _CheckRegressionConfidenceError( | 478 def _CheckRegressionConfidenceError( |
474 good_revision, | 479 good_revision, |
475 bad_revision, | 480 bad_revision, |
476 known_good_value, | 481 known_good_value, |
477 known_bad_value): | 482 known_bad_value): |
478 """Checks whether we can be confident beyond a certain degree that the given | 483 """Checks whether we can be confident beyond a certain degree that the given |
479 metrics represent a regression. | 484 metrics represent a regression. |
480 | 485 |
481 Args: | 486 Args: |
482 good_revision: string representing the commit considered 'good' | 487 good_revision: string representing the commit considered 'good' |
483 bad_revision: Same as above for 'bad'. | 488 bad_revision: Same as above for 'bad'. |
484 known_good_value: A dict with at least: 'values', 'mean' and 'std_err' | 489 known_good_value: A dict with at least: 'values', 'mean' and 'std_err' |
485 known_bad_value: Same as above. | 490 known_bad_value: Same as above. |
486 | 491 |
487 Returns: | 492 Returns: |
488 False if there is no error (i.e. we can be confident there's a regressioni), | 493 False if there is no error (i.e. we can be confident there's a regression), |
489 a string containing the details of the lack of confidence otherwise. | 494 a string containing the details of the lack of confidence otherwise. |
490 """ | 495 """ |
491 error = False | 496 error = False |
492 # Adding good and bad values to a parameter list. | 497 # Adding good and bad values to a parameter list. |
493 confidence_params = [] | 498 confidence_params = [] |
494 for l in [known_bad_value['values'], known_good_value['values']]: | 499 for l in [known_bad_value['values'], known_good_value['values']]: |
495 # Flatten if needed, by averaging the values in each nested list | 500 # Flatten if needed, by averaging the values in each nested list |
496 if isinstance(l, list) and all([isinstance(x, list) for x in l]): | 501 if isinstance(l, list) and all([isinstance(x, list) for x in l]): |
497 averages = map(math_utils.Mean, l) | 502 averages = map(math_utils.Mean, l) |
498 confidence_params.append(averages) | 503 confidence_params.append(averages) |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
569 if returncode: | 574 if returncode: |
570 raise RunGitError('Deleting branch failed, %s', output) | 575 raise RunGitError('Deleting branch failed, %s', output) |
571 | 576 |
572 # Check if the tree is dirty: make sure the index is up to date and then | 577 # Check if the tree is dirty: make sure the index is up to date and then |
573 # run diff-index. | 578 # run diff-index. |
574 bisect_utils.RunGit(['update-index', '--refresh', '-q']) | 579 bisect_utils.RunGit(['update-index', '--refresh', '-q']) |
575 output, returncode = bisect_utils.RunGit(['diff-index', 'HEAD']) | 580 output, returncode = bisect_utils.RunGit(['diff-index', 'HEAD']) |
576 if output: | 581 if output: |
577 raise RunGitError('Cannot send a try job with a dirty tree.') | 582 raise RunGitError('Cannot send a try job with a dirty tree.') |
578 | 583 |
579 # Create/check out the telemetry-tryjob branch, and edit the configs | 584 # Create and check out the telemetry-tryjob branch, and edit the configs |
580 # for the tryjob there. | 585 # for the try job there. |
581 output, returncode = bisect_utils.RunGit(['checkout', '-b', new_branch]) | 586 output, returncode = bisect_utils.RunGit(['checkout', '-b', new_branch]) |
582 if returncode: | 587 if returncode: |
583 raise RunGitError('Failed to checkout branch: %s.' % output) | 588 raise RunGitError('Failed to checkout branch: %s.' % output) |
584 | 589 |
585 output, returncode = bisect_utils.RunGit( | 590 output, returncode = bisect_utils.RunGit( |
586 ['branch', '--set-upstream-to', parent_branch]) | 591 ['branch', '--set-upstream-to', parent_branch]) |
587 if returncode: | 592 if returncode: |
588 raise RunGitError('Error in git branch --set-upstream-to') | 593 raise RunGitError('Error in git branch --set-upstream-to') |
589 | 594 |
590 | 595 |
591 def _StartBuilderTryJob( | 596 def _StartBuilderTryJob( |
592 builder_type, git_revision, builder_name, job_name, patch=None): | 597 builder_type, git_revision, builder_name, job_name, patch=None): |
593 """Attempts to run a try job from the current directory. | 598 """Attempts to run a try job from the current directory. |
594 | 599 |
595 Args: | 600 Args: |
596 builder_type: One of the builder types in fetch_build, e.g. "perf". | 601 builder_type: One of the builder types in fetch_build, e.g. "perf". |
597 git_revision: A git commit hash. | 602 git_revision: A git commit hash. |
598 builder_name: Name of the bisect bot to be used for try job. | 603 builder_name: Name of the bisect bot to be used for try job. |
599 bisect_job_name: Try job name, used to identify which bisect | 604 bisect_job_name: Try job name, used to identify which bisect |
600 job was responsible for requesting a build. | 605 job was responsible for requesting a build. |
601 patch: A DEPS patch (used while bisecting dependency repositories), | 606 patch: A DEPS patch (used while bisecting dependency repositories), |
602 or None if we're bisecting the top-level repository. | 607 or None if we're bisecting the top-level repository. |
603 """ | 608 """ |
604 # TODO(prasadv, qyearsley): Make this a method of BuildArchive | 609 # TODO(prasadv, qyearsley): Make this a method of BuildArchive |
605 # (which may be renamed to BuilderTryBot or Builder). | 610 # (which may be renamed to BuilderTryBot or Builder). |
606 try: | 611 try: |
607 # Temporary branch for running tryjob. | 612 # Temporary branch for running a try job. |
608 _PrepareBisectBranch(BISECT_MASTER_BRANCH, BISECT_TRYJOB_BRANCH) | 613 _PrepareBisectBranch(BISECT_MASTER_BRANCH, BISECT_TRYJOB_BRANCH) |
609 patch_content = '/dev/null' | 614 patch_content = '/dev/null' |
610 # Create a temporary patch file. | 615 # Create a temporary patch file. |
611 if patch: | 616 if patch: |
612 WriteStringToFile(patch, BISECT_PATCH_FILE) | 617 WriteStringToFile(patch, BISECT_PATCH_FILE) |
613 patch_content = BISECT_PATCH_FILE | 618 patch_content = BISECT_PATCH_FILE |
614 | 619 |
615 try_command = [ | 620 try_command = [ |
616 'try', | 621 'try', |
617 '--bot=%s' % builder_name, | 622 '--bot=%s' % builder_name, |
618 '--revision=%s' % git_revision, | 623 '--revision=%s' % git_revision, |
619 '--name=%s' % job_name, | 624 '--name=%s' % job_name, |
620 '--svn_repo=%s' % _TryJobSvnRepo(builder_type), | 625 '--svn_repo=%s' % _TryJobSvnRepo(builder_type), |
621 '--diff=%s' % patch_content, | 626 '--diff=%s' % patch_content, |
622 ] | 627 ] |
623 # Execute try job to build revision. | 628 # Execute try job to build revision. |
624 print try_command | 629 print try_command |
625 output, return_code = bisect_utils.RunGit(try_command) | 630 output, return_code = bisect_utils.RunGit(try_command) |
626 | 631 |
627 command_string = ' '.join(['git'] + try_command) | 632 command_string = ' '.join(['git'] + try_command) |
628 if return_code: | 633 if return_code: |
629 raise RunGitError('Could not execute tryjob: %s.\n' | 634 raise RunGitError('Could not execute try job: %s.\n' |
630 'Error: %s' % (command_string, output)) | 635 'Error: %s' % (command_string, output)) |
631 logging.info('Try job successfully submitted.\n TryJob Details: %s\n%s', | 636 logging.info('Try job successfully submitted.\n TryJob Details: %s\n%s', |
632 command_string, output) | 637 command_string, output) |
633 finally: | 638 finally: |
634 # Delete patch file if exists. | 639 # Delete patch file if exists. |
635 try: | 640 try: |
636 os.remove(BISECT_PATCH_FILE) | 641 os.remove(BISECT_PATCH_FILE) |
637 except OSError as e: | 642 except OSError as e: |
638 if e.errno != errno.ENOENT: | 643 if e.errno != errno.ENOENT: |
639 raise | 644 raise |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
740 results[depot_name] = None | 745 results[depot_name] = None |
741 return results | 746 return results |
742 except ImportError: | 747 except ImportError: |
743 deps_file_contents = ReadStringFromFile(deps_file) | 748 deps_file_contents = ReadStringFromFile(deps_file) |
744 parse_results = _ParseRevisionsFromDEPSFileManually(deps_file_contents) | 749 parse_results = _ParseRevisionsFromDEPSFileManually(deps_file_contents) |
745 results = {} | 750 results = {} |
746 for depot_name, depot_revision in parse_results.iteritems(): | 751 for depot_name, depot_revision in parse_results.iteritems(): |
747 depot_revision = depot_revision.strip('@') | 752 depot_revision = depot_revision.strip('@') |
748 logging.warn(depot_name, depot_revision) | 753 logging.warn(depot_name, depot_revision) |
749 for cur_name, cur_data in bisect_utils.DEPOT_DEPS_NAME.iteritems(): | 754 for cur_name, cur_data in bisect_utils.DEPOT_DEPS_NAME.iteritems(): |
750 if (cur_data.has_key('deps_var') and | 755 if cur_data.get('deps_var') == depot_name: |
751 cur_data['deps_var'] == depot_name): | |
752 src_name = cur_name | 756 src_name = cur_name |
753 results[src_name] = depot_revision | 757 results[src_name] = depot_revision |
754 break | 758 break |
755 return results | 759 return results |
756 | 760 |
757 def _Get3rdPartyRevisions(self, depot): | 761 def _Get3rdPartyRevisions(self, depot): |
758 """Parses the DEPS file to determine WebKit/v8/etc... versions. | 762 """Parses the DEPS file to determine WebKit/v8/etc... versions. |
759 | 763 |
760 Args: | 764 Args: |
761 depot: A depot name. Should be in the DEPOT_NAMES list. | 765 depot: A depot name. Should be in the DEPOT_NAMES list. |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
916 extra_src=self.opts.extra_src) | 920 extra_src=self.opts.extra_src) |
917 | 921 |
918 try: | 922 try: |
919 _StartBuilderTryJob(self.opts.builder_type, git_revision, builder_name, | 923 _StartBuilderTryJob(self.opts.builder_type, git_revision, builder_name, |
920 job_name=build_request_id, patch=deps_patch) | 924 job_name=build_request_id, patch=deps_patch) |
921 except RunGitError as e: | 925 except RunGitError as e: |
922 logging.warn('Failed to post builder try job for revision: [%s].\n' | 926 logging.warn('Failed to post builder try job for revision: [%s].\n' |
923 'Error: %s', git_revision, e) | 927 'Error: %s', git_revision, e) |
924 return None | 928 return None |
925 | 929 |
926 # Get the buildbot master url to monitor build status. | 930 # Get the buildbot master URL to monitor build status. |
927 buildbot_server_url = fetch_build.GetBuildBotUrl( | 931 buildbot_server_url = fetch_build.GetBuildBotUrl( |
928 builder_type=self.opts.builder_type, | 932 builder_type=self.opts.builder_type, |
929 target_arch=self.opts.target_arch, | 933 target_arch=self.opts.target_arch, |
930 target_platform=self.opts.target_platform, | 934 target_platform=self.opts.target_platform, |
931 extra_src=self.opts.extra_src) | 935 extra_src=self.opts.extra_src) |
932 | 936 |
933 archive_filename, error_msg = _WaitUntilBuildIsReady( | 937 archive_filename, error_msg = _WaitUntilBuildIsReady( |
934 fetch_build_func, builder_name, build_request_id, build_timeout, | 938 fetch_build_func, builder_name, build_request_id, build_timeout, |
935 buildbot_server_url) | 939 buildbot_server_url) |
936 if not archive_filename: | 940 if not archive_filename: |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1020 """Checks if build can be downloaded based on target platform and depot.""" | 1024 """Checks if build can be downloaded based on target platform and depot.""" |
1021 if (self.opts.target_platform in ['chromium', 'android', 'android-chrome'] | 1025 if (self.opts.target_platform in ['chromium', 'android', 'android-chrome'] |
1022 and self.opts.builder_type): | 1026 and self.opts.builder_type): |
1023 # In case of android-chrome platform, download archives only for | 1027 # In case of android-chrome platform, download archives only for |
1024 # android-chrome depot; for other depots such as chromium, v8, skia | 1028 # android-chrome depot; for other depots such as chromium, v8, skia |
1025 # etc., build the binary locally. | 1029 # etc., build the binary locally. |
1026 if self.opts.target_platform == 'android-chrome': | 1030 if self.opts.target_platform == 'android-chrome': |
1027 return depot == 'android-chrome' | 1031 return depot == 'android-chrome' |
1028 else: | 1032 else: |
1029 return (depot == 'chromium' or | 1033 return (depot == 'chromium' or |
1030 'chromium' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'] or | 1034 'chromium' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'] or |
1031 'v8' in bisect_utils.DEPOT_DEPS_NAME[depot]['from']) | 1035 'v8' in bisect_utils.DEPOT_DEPS_NAME[depot]['from']) |
1032 return False | 1036 return False |
1033 | 1037 |
1034 def UpdateDepsContents(self, deps_contents, depot, git_revision, deps_key): | 1038 def UpdateDepsContents(self, deps_contents, depot, git_revision, deps_key): |
1035 """Returns modified version of DEPS file contents. | 1039 """Returns modified version of DEPS file contents. |
1036 | 1040 |
1037 Args: | 1041 Args: |
1038 deps_contents: DEPS file content. | 1042 deps_contents: DEPS file content. |
1039 depot: Current depot being bisected. | 1043 depot: Current depot being bisected. |
1040 git_revision: A git hash to be updated in DEPS. | 1044 git_revision: A git hash to be updated in DEPS. |
1041 deps_key: Key in vars section of DEPS file to be searched. | 1045 deps_key: Key in vars section of DEPS file to be searched. |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 if parsed_metric: | 1355 if parsed_metric: |
1352 metric_values.append(math_utils.Mean(parsed_metric)) | 1356 metric_values.append(math_utils.Mean(parsed_metric)) |
1353 # If we're bisecting on a metric (ie, changes in the mean or | 1357 # If we're bisecting on a metric (ie, changes in the mean or |
1354 # standard deviation) and no metric values are produced, bail out. | 1358 # standard deviation) and no metric values are produced, bail out. |
1355 if not metric_values: | 1359 if not metric_values: |
1356 break | 1360 break |
1357 elif self._IsBisectModeReturnCode(): | 1361 elif self._IsBisectModeReturnCode(): |
1358 metric_values.append(return_code) | 1362 metric_values.append(return_code) |
1359 | 1363 |
1360 elapsed_minutes = (time.time() - start_time) / 60.0 | 1364 elapsed_minutes = (time.time() - start_time) / 60.0 |
1361 time_limit = self.opts.max_time_minutes * test_run_multiplier | 1365 time_limit = self.opts.max_time_minutes * test_run_multiplier |
1362 if elapsed_minutes >= time_limit: | 1366 if elapsed_minutes >= time_limit: |
1363 break | 1367 break |
1364 | 1368 |
1365 if metric and len(metric_values) == 0: | 1369 if metric and len(metric_values) == 0: |
1366 err_text = 'Metric %s was not found in the test output.' % metric | 1370 err_text = 'Metric %s was not found in the test output.' % metric |
1367 # TODO(qyearsley): Consider also getting and displaying a list of metrics | 1371 # TODO(qyearsley): Consider also getting and displaying a list of metrics |
1368 # that were found in the output here. | 1372 # that were found in the output here. |
1369 return (err_text, failure_code, output_of_all_runs) | 1373 return (err_text, failure_code, output_of_all_runs) |
1370 | 1374 |
1371 # If we're bisecting on return codes, we're really just looking for zero vs | 1375 # If we're bisecting on return codes, we're really just looking for zero vs |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1423 def _RunPostSync(self, _depot): | 1427 def _RunPostSync(self, _depot): |
1424 """Performs any work after syncing. | 1428 """Performs any work after syncing. |
1425 | 1429 |
1426 Args: | 1430 Args: |
1427 depot: Depot name. | 1431 depot: Depot name. |
1428 | 1432 |
1429 Returns: | 1433 Returns: |
1430 True if successful. | 1434 True if successful. |
1431 """ | 1435 """ |
1432 if 'android' in self.opts.target_platform: | 1436 if 'android' in self.opts.target_platform: |
1433 if not builder.SetupAndroidBuildEnvironment(self.opts, | 1437 if not builder.SetupAndroidBuildEnvironment( |
1434 path_to_src=self.src_cwd): | 1438 self.opts, path_to_src=self.src_cwd): |
1435 return False | 1439 return False |
1436 | 1440 |
1437 return self.RunGClientHooks() | 1441 return self.RunGClientHooks() |
1438 | 1442 |
1439 @staticmethod | 1443 @staticmethod |
1440 def ShouldSkipRevision(depot, revision): | 1444 def ShouldSkipRevision(depot, revision): |
1441 """Checks whether a particular revision can be safely skipped. | 1445 """Checks whether a particular revision can be safely skipped. |
1442 | 1446 |
1443 Some commits can be safely skipped (such as a DEPS roll for the repos | 1447 Some commits can be safely skipped (such as a DEPS roll for the repos |
1444 still using .DEPS.git), since the tool is git based those changes | 1448 still using .DEPS.git), since the tool is git based those changes |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1529 | 1533 |
1530 # A value other than 0 indicates that the test couldn't be run, and results | 1534 # A value other than 0 indicates that the test couldn't be run, and results |
1531 # should also include an error message. | 1535 # should also include an error message. |
1532 if results[1] != 0: | 1536 if results[1] != 0: |
1533 return results | 1537 return results |
1534 | 1538 |
1535 external_revisions = self._Get3rdPartyRevisions(depot) | 1539 external_revisions = self._Get3rdPartyRevisions(depot) |
1536 | 1540 |
1537 if not external_revisions is None: | 1541 if not external_revisions is None: |
1538 return (results[0], results[1], external_revisions, | 1542 return (results[0], results[1], external_revisions, |
1539 time.time() - after_build_time, after_build_time - | 1543 time.time() - after_build_time, after_build_time - |
1540 start_build_time) | 1544 start_build_time) |
1541 else: | 1545 else: |
1542 return ('Failed to parse DEPS file for external revisions.', | 1546 return ('Failed to parse DEPS file for external revisions.', |
1543 BUILD_RESULT_FAIL) | 1547 BUILD_RESULT_FAIL) |
1544 | 1548 |
1545 def _SyncRevision(self, depot, revision, sync_client): | 1549 def _SyncRevision(self, depot, revision, sync_client): |
1546 """Syncs depot to particular revision. | 1550 """Syncs depot to particular revision. |
1547 | 1551 |
1548 Args: | 1552 Args: |
1549 depot: The depot that's being used at the moment (src, webkit, etc.) | 1553 depot: The depot that's being used at the moment (src, webkit, etc.) |
1550 revision: The revision to sync to. | 1554 revision: The revision to sync to. |
1551 sync_client: Program used to sync, e.g. "gclient". Can be None. | 1555 sync_client: Program used to sync, e.g. "gclient". Can be None. |
1552 | 1556 |
1553 Returns: | 1557 Returns: |
1554 True if successful, False otherwise. | 1558 True if successful, False otherwise. |
1555 """ | 1559 """ |
1556 self.depot_registry.ChangeToDepotDir(depot) | 1560 self.depot_registry.ChangeToDepotDir(depot) |
1557 | 1561 |
1558 if sync_client: | 1562 if sync_client: |
1559 self.PerformPreBuildCleanup() | 1563 self.PerformPreBuildCleanup() |
1560 | 1564 |
1561 # When using gclient to sync, you need to specify the depot you | 1565 # When using gclient to sync, you need to specify the depot you |
1562 # want so that all the dependencies sync properly as well. | 1566 # want so that all the dependencies sync properly as well. |
1563 # i.e. gclient sync src@<SHA1> | 1567 # i.e. gclient sync src@<SHA1> |
1564 if sync_client == 'gclient' and revision: | 1568 if sync_client == 'gclient' and revision: |
1565 revision = '%s@%s' % (bisect_utils.DEPOT_DEPS_NAME[depot]['src'], | 1569 revision = '%s@%s' % (bisect_utils.DEPOT_DEPS_NAME[depot]['src'], |
1566 revision) | 1570 revision) |
1567 if depot == 'chromium' and self.opts.target_platform == 'android-chrome': | 1571 if depot == 'chromium' and self.opts.target_platform == 'android-chrome': |
1568 return self._SyncRevisionsForAndroidChrome(revision) | 1572 return self._SyncRevisionsForAndroidChrome(revision) |
1569 | 1573 |
1570 return source_control.SyncToRevision(revision, sync_client) | 1574 return source_control.SyncToRevision(revision, sync_client) |
1571 | 1575 |
1572 def _SyncRevisionsForAndroidChrome(self, revision): | 1576 def _SyncRevisionsForAndroidChrome(self, revision): |
1573 """Syncs android-chrome and chromium repos to particular revision. | 1577 """Syncs android-chrome and chromium repos to particular revision. |
1574 | 1578 |
1575 This is a special case for android-chrome as the gclient sync for chromium | 1579 This is a special case for android-chrome as the gclient sync for chromium |
1576 overwrites the android-chrome revision to TOT. Therefore both the repos | 1580 overwrites the android-chrome revision to TOT. Therefore both the repos |
(...skipping 21 matching lines...) Expand all Loading... | |
1598 current_value: The value of the metric being checked. | 1602 current_value: The value of the metric being checked. |
1599 known_bad_value: The reference value for a "failed" run. | 1603 known_bad_value: The reference value for a "failed" run. |
1600 known_good_value: The reference value for a "passed" run. | 1604 known_good_value: The reference value for a "passed" run. |
1601 | 1605 |
1602 Returns: | 1606 Returns: |
1603 True if the current_value is closer to the known_good_value than the | 1607 True if the current_value is closer to the known_good_value than the |
1604 known_bad_value. | 1608 known_bad_value. |
1605 """ | 1609 """ |
1606 if self.opts.bisect_mode == bisect_utils.BISECT_MODE_STD_DEV: | 1610 if self.opts.bisect_mode == bisect_utils.BISECT_MODE_STD_DEV: |
1607 dist_to_good_value = abs(current_value['std_dev'] - | 1611 dist_to_good_value = abs(current_value['std_dev'] - |
1608 known_good_value['std_dev']) | 1612 known_good_value['std_dev']) |
1609 dist_to_bad_value = abs(current_value['std_dev'] - | 1613 dist_to_bad_value = abs(current_value['std_dev'] - |
1610 known_bad_value['std_dev']) | 1614 known_bad_value['std_dev']) |
1611 else: | 1615 else: |
1612 dist_to_good_value = abs(current_value['mean'] - known_good_value['mean']) | 1616 dist_to_good_value = abs(current_value['mean'] - known_good_value['mean']) |
1613 dist_to_bad_value = abs(current_value['mean'] - known_bad_value['mean']) | 1617 dist_to_bad_value = abs(current_value['mean'] - known_bad_value['mean']) |
1614 | 1618 |
1615 return dist_to_good_value < dist_to_bad_value | 1619 return dist_to_good_value < dist_to_bad_value |
1616 | 1620 |
1617 def _GetV8BleedingEdgeFromV8TrunkIfMappable( | 1621 def _GetV8BleedingEdgeFromV8TrunkIfMappable( |
1618 self, revision, bleeding_edge_branch): | 1622 self, revision, bleeding_edge_branch): |
1619 """Gets v8 bleeding edge revision mapped to v8 revision in trunk. | 1623 """Gets v8 bleeding edge revision mapped to v8 revision in trunk. |
1620 | 1624 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1675 return re_results.group('git_revision') | 1679 return re_results.group('git_revision') |
1676 except (IndexError, ValueError): | 1680 except (IndexError, ValueError): |
1677 pass | 1681 pass |
1678 if not git_revision: | 1682 if not git_revision: |
1679 # Wasn't successful, try the old way of looking for "Prepare push to" | 1683 # Wasn't successful, try the old way of looking for "Prepare push to" |
1680 git_revision = source_control.ResolveToRevision( | 1684 git_revision = source_control.ResolveToRevision( |
1681 int(commit_position) - 1, 'v8_bleeding_edge', | 1685 int(commit_position) - 1, 'v8_bleeding_edge', |
1682 bisect_utils.DEPOT_DEPS_NAME, -1, cwd=v8_bleeding_edge_dir) | 1686 bisect_utils.DEPOT_DEPS_NAME, -1, cwd=v8_bleeding_edge_dir) |
1683 | 1687 |
1684 if git_revision: | 1688 if git_revision: |
1685 revision_info = source_control.QueryRevisionInfo(git_revision, | 1689 revision_info = source_control.QueryRevisionInfo( |
1686 cwd=v8_bleeding_edge_dir) | 1690 git_revision, cwd=v8_bleeding_edge_dir) |
1687 | 1691 |
1688 if 'Prepare push to trunk' in revision_info['subject']: | 1692 if 'Prepare push to trunk' in revision_info['subject']: |
1689 return git_revision | 1693 return git_revision |
1690 return None | 1694 return None |
1691 | 1695 |
1692 def _GetNearestV8BleedingEdgeFromTrunk( | 1696 def _GetNearestV8BleedingEdgeFromTrunk( |
1693 self, revision, v8_branch, bleeding_edge_branch, search_forward=True): | 1697 self, revision, v8_branch, bleeding_edge_branch, search_forward=True): |
1694 """Gets the nearest V8 roll and maps to bleeding edge revision. | 1698 """Gets the nearest V8 roll and maps to bleeding edge revision. |
1695 | 1699 |
1696 V8 is a bit tricky to bisect since it isn't just rolled out like blink. | 1700 V8 is a bit tricky to bisect since it isn't just rolled out like blink. |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1753 | 1757 |
1754 # Support for the chromium revisions with external V8 repo. | 1758 # Support for the chromium revisions with external V8 repo. |
1755 # ie https://chromium.googlesource.com/external/v8.git | 1759 # ie https://chromium.googlesource.com/external/v8.git |
1756 cmd = ['config', '--get', 'remote.origin.url'] | 1760 cmd = ['config', '--get', 'remote.origin.url'] |
1757 v8_repo_url = bisect_utils.CheckRunGit(cmd, cwd=cwd) | 1761 v8_repo_url = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
1758 | 1762 |
1759 if 'external/v8.git' in v8_repo_url: | 1763 if 'external/v8.git' in v8_repo_url: |
1760 v8_branch = 'origin/master' | 1764 v8_branch = 'origin/master' |
1761 bleeding_edge_branch = 'origin/bleeding_edge' | 1765 bleeding_edge_branch = 'origin/bleeding_edge' |
1762 | 1766 |
1763 r1 = self._GetNearestV8BleedingEdgeFromTrunk(min_revision_state.revision, | 1767 r1 = self._GetNearestV8BleedingEdgeFromTrunk( |
1764 v8_branch, bleeding_edge_branch, search_forward=True) | 1768 min_revision_state.revision, |
1765 r2 = self._GetNearestV8BleedingEdgeFromTrunk(max_revision_state.revision, | 1769 v8_branch, |
1766 v8_branch, bleeding_edge_branch, search_forward=False) | 1770 bleeding_edge_branch, |
1771 search_forward=True) | |
1772 r2 = self._GetNearestV8BleedingEdgeFromTrunk( | |
1773 max_revision_state.revision, | |
1774 v8_branch, | |
1775 bleeding_edge_branch, | |
1776 search_forward=False) | |
1767 min_revision_state.external['v8_bleeding_edge'] = r1 | 1777 min_revision_state.external['v8_bleeding_edge'] = r1 |
1768 max_revision_state.external['v8_bleeding_edge'] = r2 | 1778 max_revision_state.external['v8_bleeding_edge'] = r2 |
1769 | 1779 |
1770 if (not self._GetV8BleedingEdgeFromV8TrunkIfMappable( | 1780 if (not self._GetV8BleedingEdgeFromV8TrunkIfMappable( |
1771 min_revision_state.revision, bleeding_edge_branch) | 1781 min_revision_state.revision, bleeding_edge_branch) |
1772 or not self._GetV8BleedingEdgeFromV8TrunkIfMappable( | 1782 or not self._GetV8BleedingEdgeFromV8TrunkIfMappable( |
1773 max_revision_state.revision, bleeding_edge_branch)): | 1783 max_revision_state.revision, bleeding_edge_branch)): |
1774 self.warnings.append( | 1784 self.warnings.append( |
1775 'Trunk revisions in V8 did not map directly to bleeding_edge. ' | 1785 'Trunk revisions in V8 did not map directly to bleeding_edge. ' |
1776 'Attempted to expand the range to find V8 rolls which did map ' | 1786 'Attempted to expand the range to find V8 rolls which did map ' |
1777 'directly to bleeding_edge revisions, but results might not be ' | 1787 'directly to bleeding_edge revisions, but results might not be ' |
1778 'valid.') | 1788 'valid.') |
1779 | 1789 |
1780 def _FindNextDepotToBisect( | 1790 def _FindNextDepotToBisect( |
1781 self, current_depot, min_revision_state, max_revision_state): | 1791 self, current_depot, min_revision_state, max_revision_state): |
1782 """Decides which depot the script should dive into next (if any). | 1792 """Decides which depot the script should dive into next (if any). |
1783 | 1793 |
1784 Args: | 1794 Args: |
1785 current_depot: Current depot being bisected. | 1795 current_depot: Current depot being bisected. |
1786 min_revision_state: State of the earliest revision in the bisect range. | 1796 min_revision_state: State of the earliest revision in the bisect range. |
1787 max_revision_state: State of the latest revision in the bisect range. | 1797 max_revision_state: State of the latest revision in the bisect range. |
1788 | 1798 |
1789 Returns: | 1799 Returns: |
1790 Name of the depot to bisect next, or None. | 1800 Name of the depot to bisect next, or None. |
1791 """ | 1801 """ |
1792 external_depot = None | 1802 external_depot = None |
1793 for next_depot in bisect_utils.DEPOT_NAMES: | 1803 for next_depot in bisect_utils.DEPOT_NAMES: |
1794 if bisect_utils.DEPOT_DEPS_NAME[next_depot].has_key('platform'): | 1804 if ('platform' in bisect_utils.DEPOT_DEPS_NAME[next_depot] and |
1795 if bisect_utils.DEPOT_DEPS_NAME[next_depot]['platform'] != os.name: | 1805 bisect_utils.DEPOT_DEPS_NAME[next_depot]['platform'] != os.name): |
1796 continue | 1806 continue |
1797 | 1807 |
1798 if not (bisect_utils.DEPOT_DEPS_NAME[next_depot]['recurse'] | 1808 if not (bisect_utils.DEPOT_DEPS_NAME[next_depot]['recurse'] |
1799 and min_revision_state.depot | 1809 and min_revision_state.depot |
1800 in bisect_utils.DEPOT_DEPS_NAME[next_depot]['from']): | 1810 in bisect_utils.DEPOT_DEPS_NAME[next_depot]['from']): |
1801 continue | 1811 continue |
1802 | 1812 |
1803 if current_depot == 'v8': | 1813 if current_depot == 'v8': |
1804 # We grab the bleeding_edge info here rather than earlier because we | 1814 # We grab the bleeding_edge info here rather than earlier because we |
1805 # finally have the revision range. From that we can search forwards and | 1815 # finally have the revision range. From that we can search forwards and |
1806 # backwards to try to match trunk revisions to bleeding_edge. | 1816 # backwards to try to match trunk revisions to bleeding_edge. |
(...skipping 24 matching lines...) Expand all Loading... | |
1831 Returns: | 1841 Returns: |
1832 A list containing the revisions between |start_revision| and | 1842 A list containing the revisions between |start_revision| and |
1833 |end_revision| inclusive. | 1843 |end_revision| inclusive. |
1834 """ | 1844 """ |
1835 # Change into working directory of external library to run | 1845 # Change into working directory of external library to run |
1836 # subsequent commands. | 1846 # subsequent commands. |
1837 self.depot_registry.ChangeToDepotDir(current_depot) | 1847 self.depot_registry.ChangeToDepotDir(current_depot) |
1838 | 1848 |
1839 # V8 (and possibly others) is merged in periodically. Bisecting | 1849 # V8 (and possibly others) is merged in periodically. Bisecting |
1840 # this directory directly won't give much good info. | 1850 # this directory directly won't give much good info. |
1841 if bisect_utils.DEPOT_DEPS_NAME[current_depot].has_key('custom_deps'): | 1851 if 'custom_deps' in bisect_utils.DEPOT_DEPS_NAME[current_depot]: |
1842 config_path = os.path.join(self.src_cwd, '..') | 1852 config_path = os.path.join(self.src_cwd, '..') |
1843 if bisect_utils.RunGClientAndCreateConfig( | 1853 if bisect_utils.RunGClientAndCreateConfig( |
1844 self.opts, bisect_utils.DEPOT_DEPS_NAME[current_depot]['custom_deps'], | 1854 self.opts, bisect_utils.DEPOT_DEPS_NAME[current_depot]['custom_deps'], |
1845 cwd=config_path): | 1855 cwd=config_path): |
1846 return [] | 1856 return [] |
1847 if bisect_utils.RunGClient( | 1857 if bisect_utils.RunGClient( |
1848 ['sync', '--revision', previous_revision], cwd=self.src_cwd): | 1858 ['sync', '--revision', previous_revision], cwd=self.src_cwd): |
1849 return [] | 1859 return [] |
1850 | 1860 |
1851 if current_depot == 'v8_bleeding_edge': | 1861 if current_depot == 'v8_bleeding_edge': |
1852 self.depot_registry.ChangeToDepotDir('chromium') | 1862 self.depot_registry.ChangeToDepotDir('chromium') |
1853 | 1863 |
1854 shutil.move('v8', 'v8.bak') | 1864 shutil.move('v8', 'v8.bak') |
1855 shutil.move('v8_bleeding_edge', 'v8') | 1865 shutil.move('v8_bleeding_edge', 'v8') |
1856 | 1866 |
1857 self.cleanup_commands.append(['mv', 'v8', 'v8_bleeding_edge']) | 1867 self.cleanup_commands.append(['mv', 'v8', 'v8_bleeding_edge']) |
1858 self.cleanup_commands.append(['mv', 'v8.bak', 'v8']) | 1868 self.cleanup_commands.append(['mv', 'v8.bak', 'v8']) |
1859 | 1869 |
1860 self.depot_registry.SetDepotDir('v8_bleeding_edge', | 1870 self.depot_registry.SetDepotDir( |
1861 os.path.join(self.src_cwd, 'v8')) | 1871 'v8_bleeding_edge', os.path.join(self.src_cwd, 'v8')) |
1862 self.depot_registry.SetDepotDir('v8', os.path.join(self.src_cwd, | 1872 self.depot_registry.SetDepotDir( |
1863 'v8.bak')) | 1873 'v8', os.path.join(self.src_cwd, 'v8.bak')) |
1864 | 1874 |
1865 self.depot_registry.ChangeToDepotDir(current_depot) | 1875 self.depot_registry.ChangeToDepotDir(current_depot) |
1866 | 1876 |
1867 depot_revision_list = self.GetRevisionList(current_depot, | 1877 depot_revision_list = self.GetRevisionList(current_depot, |
1868 end_revision, | 1878 end_revision, |
1869 start_revision) | 1879 start_revision) |
1870 | 1880 |
1871 self.depot_registry.ChangeToDepotDir('chromium') | 1881 self.depot_registry.ChangeToDepotDir('chromium') |
1872 | 1882 |
1873 return depot_revision_list | 1883 return depot_revision_list |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1941 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) | 1951 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) |
1942 | 1952 |
1943 if len(changes_to_deps) != len(changes_to_gitdeps): | 1953 if len(changes_to_deps) != len(changes_to_gitdeps): |
1944 # Grab the timestamp of the last DEPS change | 1954 # Grab the timestamp of the last DEPS change |
1945 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] | 1955 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] |
1946 output = bisect_utils.CheckRunGit(cmd) | 1956 output = bisect_utils.CheckRunGit(cmd) |
1947 commit_time = int(output) | 1957 commit_time = int(output) |
1948 | 1958 |
1949 # Try looking for a commit that touches the .DEPS.git file in the | 1959 # Try looking for a commit that touches the .DEPS.git file in the |
1950 # next 15 minutes after the DEPS file change. | 1960 # next 15 minutes after the DEPS file change. |
1951 cmd = ['log', '--format=%H', '-1', | 1961 cmd = [ |
1952 '--before=%d' % (commit_time + 900), '--after=%d' % commit_time, | 1962 'log', '--format=%H', '-1', |
1953 'origin/master', '--', bisect_utils.FILE_DEPS_GIT] | 1963 '--before=%d' % (commit_time + 900), |
1964 '--after=%d' % commit_time, | |
1965 'origin/master', '--', bisect_utils.FILE_DEPS_GIT | |
1966 ] | |
1954 output = bisect_utils.CheckRunGit(cmd) | 1967 output = bisect_utils.CheckRunGit(cmd) |
1955 output = output.strip() | 1968 output = output.strip() |
1956 if output: | 1969 if output: |
1957 self.warnings.append('Detected change to DEPS and modified ' | 1970 self.warnings.append( |
1971 'Detected change to DEPS and modified ' | |
1958 'revision range to include change to .DEPS.git') | 1972 'revision range to include change to .DEPS.git') |
1959 return (output, good_revision) | 1973 return (output, good_revision) |
1960 else: | 1974 else: |
1961 self.warnings.append('Detected change to DEPS but couldn\'t find ' | 1975 self.warnings.append( |
1976 'Detected change to DEPS but couldn\'t find ' | |
1962 'matching change to .DEPS.git') | 1977 'matching change to .DEPS.git') |
1963 return (bad_revision, good_revision) | 1978 return (bad_revision, good_revision) |
1964 | 1979 |
1965 def CheckIfRevisionsInProperOrder( | 1980 def CheckIfRevisionsInProperOrder( |
1966 self, target_depot, good_revision, bad_revision): | 1981 self, target_depot, good_revision, bad_revision): |
1967 """Checks that |good_revision| is an earlier revision than |bad_revision|. | 1982 """Checks that |good_revision| is an earlier revision than |bad_revision|. |
1968 | 1983 |
1969 Args: | 1984 Args: |
1970 good_revision: Number/tag of the known good revision. | 1985 good_revision: Number/tag of the known good revision. |
1971 bad_revision: Number/tag of the known bad revision. | 1986 bad_revision: Number/tag of the known bad revision. |
1972 | 1987 |
1973 Returns: | 1988 Returns: |
1974 True if the revisions are in the proper order (good earlier than bad). | 1989 True if the revisions are in the proper order (good earlier than bad). |
1975 """ | 1990 """ |
1976 cwd = self.depot_registry.GetDepotDir(target_depot) | 1991 cwd = self.depot_registry.GetDepotDir(target_depot) |
1977 good_position = source_control.GetCommitPosition(good_revision, cwd) | 1992 good_position = source_control.GetCommitPosition(good_revision, cwd) |
1978 bad_position = source_control.GetCommitPosition(bad_revision, cwd) | 1993 bad_position = source_control.GetCommitPosition(bad_revision, cwd) |
1979 # Compare commit timestamp for repos that don't support commit position. | 1994 # Compare commit timestamp for repos that don't support commit position. |
1980 if not (bad_position and good_position): | 1995 if not (bad_position and good_position): |
1981 good_position = source_control.GetCommitTime(good_revision, cwd=cwd) | 1996 good_position = source_control.GetCommitTime(good_revision, cwd=cwd) |
1982 bad_position = source_control.GetCommitTime(bad_revision, cwd=cwd) | 1997 bad_position = source_control.GetCommitTime(bad_revision, cwd=cwd) |
1983 | 1998 |
1984 return good_position <= bad_position | 1999 return good_position <= bad_position |
1985 | 2000 |
1986 def CanPerformBisect(self, good_revision, bad_revision): | 2001 def CanPerformBisect(self, good_revision, bad_revision): |
1987 """Checks whether a given revision is bisectable. | 2002 """Checks whether a given revision is bisectable. |
1988 | 2003 |
1989 Checks for following: | 2004 Checks for following: |
1990 1. Non-bisectable revsions for android bots (refer to crbug.com/385324). | 2005 1. Non-bisectable revisions for android bots (refer to crbug.com/385324). |
1991 2. Non-bisectable revsions for Windows bots (refer to crbug.com/405274). | 2006 2. Non-bisectable revisions for Windows bots (refer to crbug.com/405274). |
1992 | 2007 |
1993 Args: | 2008 Args: |
1994 good_revision: Known good revision. | 2009 good_revision: Known good revision. |
1995 bad_revision: Known bad revision. | 2010 bad_revision: Known bad revision. |
1996 | 2011 |
1997 Returns: | 2012 Returns: |
1998 A dictionary indicating the result. If revision is not bisectable, | 2013 A dictionary indicating the result. If revision is not bisectable, |
1999 this will contain the field "error", otherwise None. | 2014 this will contain the field "error", otherwise None. |
2000 """ | 2015 """ |
2001 if self.opts.target_platform == 'android': | 2016 if self.opts.target_platform == 'android': |
(...skipping 29 matching lines...) Expand all Loading... | |
2031 performance tests again with and without the CL, adding the results to | 2046 performance tests again with and without the CL, adding the results to |
2032 the over bisect results. | 2047 the over bisect results. |
2033 | 2048 |
2034 Args: | 2049 Args: |
2035 results: BisectResults from the bisect. | 2050 results: BisectResults from the bisect. |
2036 target_depot: The target depot we're bisecting. | 2051 target_depot: The target depot we're bisecting. |
2037 command_to_run: Specify the command to execute the performance test. | 2052 command_to_run: Specify the command to execute the performance test. |
2038 metric: The performance metric to monitor. | 2053 metric: The performance metric to monitor. |
2039 """ | 2054 """ |
2040 run_results_tot, run_results_reverted = self._RevertCulpritCLAndRetest( | 2055 run_results_tot, run_results_reverted = self._RevertCulpritCLAndRetest( |
2041 results, target_depot, command_to_run, metric) | 2056 results, target_depot, command_to_run, metric) |
2042 | 2057 |
2043 results.AddRetestResults(run_results_tot, run_results_reverted) | 2058 results.AddRetestResults(run_results_tot, run_results_reverted) |
2044 | 2059 |
2045 if len(results.culprit_revisions) != 1: | 2060 if len(results.culprit_revisions) != 1: |
2046 return | 2061 return |
2047 | 2062 |
2048 # Cleanup reverted files if anything is left. | 2063 # Cleanup reverted files if anything is left. |
2049 _, _, culprit_depot = results.culprit_revisions[0] | 2064 _, _, culprit_depot = results.culprit_revisions[0] |
2050 bisect_utils.CheckRunGit(['reset', '--hard', 'HEAD'], | 2065 bisect_utils.CheckRunGit( |
2066 ['reset', '--hard', 'HEAD'], | |
2051 cwd=self.depot_registry.GetDepotDir(culprit_depot)) | 2067 cwd=self.depot_registry.GetDepotDir(culprit_depot)) |
2052 | 2068 |
2053 def _RevertCL(self, culprit_revision, culprit_depot): | 2069 def _RevertCL(self, culprit_revision, culprit_depot): |
2054 """Reverts the specified revision in the specified depot.""" | 2070 """Reverts the specified revision in the specified depot.""" |
2055 if self.opts.output_buildbot_annotations: | 2071 if self.opts.output_buildbot_annotations: |
2056 bisect_utils.OutputAnnotationStepStart( | 2072 bisect_utils.OutputAnnotationStepStart( |
2057 'Reverting culprit CL: %s' % culprit_revision) | 2073 'Reverting culprit CL: %s' % culprit_revision) |
2058 _, return_code = bisect_utils.RunGit( | 2074 _, return_code = bisect_utils.RunGit( |
2059 ['revert', '--no-commit', culprit_revision], | 2075 ['revert', '--no-commit', culprit_revision], |
2060 cwd=self.depot_registry.GetDepotDir(culprit_depot)) | 2076 cwd=self.depot_registry.GetDepotDir(culprit_depot)) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2111 'Culprit CL is in another depot, attempting to revert and build' | 2127 'Culprit CL is in another depot, attempting to revert and build' |
2112 ' locally to retest. This may not match the performance of official' | 2128 ' locally to retest. This may not match the performance of official' |
2113 ' builds.') | 2129 ' builds.') |
2114 | 2130 |
2115 run_results_reverted = self._RunTestWithAnnotations( | 2131 run_results_reverted = self._RunTestWithAnnotations( |
2116 'Re-Testing ToT with reverted culprit', | 2132 'Re-Testing ToT with reverted culprit', |
2117 'Failed to run reverted CL.', | 2133 'Failed to run reverted CL.', |
2118 head_revision, target_depot, command_to_run, metric, force_build) | 2134 head_revision, target_depot, command_to_run, metric, force_build) |
2119 | 2135 |
2120 # Clear the reverted file(s). | 2136 # Clear the reverted file(s). |
2121 bisect_utils.RunGit(['reset', '--hard', 'HEAD'], | 2137 bisect_utils.RunGit( |
2138 ['reset', '--hard', 'HEAD'], | |
2122 cwd=self.depot_registry.GetDepotDir(culprit_depot)) | 2139 cwd=self.depot_registry.GetDepotDir(culprit_depot)) |
2123 | 2140 |
2124 # Retesting with the reverted CL failed, so bail out of retesting against | 2141 # Retesting with the reverted CL failed, so bail out of retesting against |
2125 # ToT. | 2142 # ToT. |
2126 if run_results_reverted[1]: | 2143 if run_results_reverted[1]: |
2127 return (None, None) | 2144 return (None, None) |
2128 | 2145 |
2129 run_results_tot = self._RunTestWithAnnotations( | 2146 run_results_tot = self._RunTestWithAnnotations( |
2130 'Re-Testing ToT', | 2147 'Re-Testing ToT', |
2131 'Failed to run ToT.', | 2148 'Failed to run ToT.', |
2132 head_revision, target_depot, command_to_run, metric, force_build) | 2149 head_revision, target_depot, command_to_run, metric, force_build) |
2133 | 2150 |
2134 return (run_results_tot, run_results_reverted) | 2151 return (run_results_tot, run_results_reverted) |
2135 | 2152 |
2136 def _RunTestWithAnnotations(self, step_text, error_text, head_revision, | 2153 def _RunTestWithAnnotations( |
2154 self, step_text, error_text, head_revision, | |
2137 target_depot, command_to_run, metric, force_build): | 2155 target_depot, command_to_run, metric, force_build): |
2138 """Runs the performance test and outputs start/stop annotations. | 2156 """Runs the performance test and outputs start/stop annotations. |
2139 | 2157 |
2140 Args: | 2158 Args: |
2141 results: BisectResults from the bisect. | 2159 results: BisectResults from the bisect. |
2142 target_depot: The target depot we're bisecting. | 2160 target_depot: The target depot we're bisecting. |
2143 command_to_run: Specify the command to execute the performance test. | 2161 command_to_run: Specify the command to execute the performance test. |
2144 metric: The performance metric to monitor. | 2162 metric: The performance metric to monitor. |
2145 force_build: Whether to force a build locally. | 2163 force_build: Whether to force a build locally. |
2146 | 2164 |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2310 # Check how likely it is that the good and bad results are different | 2328 # Check how likely it is that the good and bad results are different |
2311 # beyond chance-induced variation. | 2329 # beyond chance-induced variation. |
2312 confidence_error = False | 2330 confidence_error = False |
2313 if not self.opts.debug_ignore_regression_confidence: | 2331 if not self.opts.debug_ignore_regression_confidence: |
2314 confidence_error = _CheckRegressionConfidenceError(good_revision, | 2332 confidence_error = _CheckRegressionConfidenceError(good_revision, |
2315 bad_revision, | 2333 bad_revision, |
2316 known_good_value, | 2334 known_good_value, |
2317 known_bad_value) | 2335 known_bad_value) |
2318 if confidence_error: | 2336 if confidence_error: |
2319 self.warnings.append(confidence_error) | 2337 self.warnings.append(confidence_error) |
2320 bad_revision_state.passed = True # Marking the 'bad' revision as good. | 2338 # Marking the 'bad' revision as good BECAUSE XXX ... |
RobertoCN
2015/03/12 20:57:03
because if there is no confidence that there's a r
qyearsley
2015/03/12 21:09:03
Ah, thanks for catching this, I meant to expand on
RobertoCN
2015/03/13 22:46:17
I don't remember there being any real need for thi
| |
2339 bad_revision_state.passed = True | |
2321 return BisectResults(bisect_state, self.depot_registry, self.opts, | 2340 return BisectResults(bisect_state, self.depot_registry, self.opts, |
2322 self.warnings) | 2341 self.warnings) |
2323 | 2342 |
2324 while True: | 2343 while True: |
2325 if not revision_states: | 2344 if not revision_states: |
2326 break | 2345 break |
2327 | 2346 |
2328 if max_revision - min_revision <= 1: | 2347 if max_revision - min_revision <= 1: |
2329 min_revision_state = revision_states[min_revision] | 2348 min_revision_state = revision_states[min_revision] |
2330 max_revision_state = revision_states[max_revision] | 2349 max_revision_state = revision_states[max_revision] |
2331 current_depot = min_revision_state.depot | 2350 current_depot = min_revision_state.depot |
2332 # TODO(sergiyb): Under which conditions can first two branches be hit? | 2351 # TODO(sergiyb): Under which conditions can first two branches be hit? |
2333 if min_revision_state.passed == '?': | 2352 if min_revision_state.passed == '?': |
2334 next_revision_index = min_revision | 2353 next_revision_index = min_revision |
2335 elif max_revision_state.passed == '?': | 2354 elif max_revision_state.passed == '?': |
2336 next_revision_index = max_revision | 2355 next_revision_index = max_revision |
2337 elif current_depot in ['android-chrome', 'chromium', 'v8']: | 2356 elif current_depot in ['android-chrome', 'chromium', 'v8']: |
2338 previous_revision = revision_states[min_revision].revision | 2357 previous_revision = revision_states[min_revision].revision |
2339 # If there were changes to any of the external libraries we track, | 2358 # If there were changes to any of the external libraries we track, |
2340 # should bisect the changes there as well. | 2359 # should bisect the changes there as well. |
2341 external_depot = self._FindNextDepotToBisect( | 2360 external_depot = self._FindNextDepotToBisect( |
2342 current_depot, min_revision_state, max_revision_state) | 2361 current_depot, min_revision_state, max_revision_state) |
2343 # If there was no change in any of the external depots, the search | 2362 # If there was no change in any of the external depots, the search |
2344 # is over. | 2363 # is over. |
2345 if not external_depot: | 2364 if not external_depot: |
2346 if current_depot == 'v8': | 2365 if current_depot == 'v8': |
2347 self.warnings.append('Unfortunately, V8 bisection couldn\'t ' | 2366 self.warnings.append( |
2367 'Unfortunately, V8 bisection couldn\'t ' | |
2348 'continue any further. The script can only bisect into ' | 2368 'continue any further. The script can only bisect into ' |
2349 'V8\'s bleeding_edge repository if both the current and ' | 2369 'V8\'s bleeding_edge repository if both the current and ' |
2350 'previous revisions in trunk map directly to revisions in ' | 2370 'previous revisions in trunk map directly to revisions in ' |
2351 'bleeding_edge.') | 2371 'bleeding_edge.') |
2352 break | 2372 break |
2353 | 2373 |
2354 earliest_revision = max_revision_state.external[external_depot] | 2374 earliest_revision = max_revision_state.external[external_depot] |
2355 latest_revision = min_revision_state.external[external_depot] | 2375 latest_revision = min_revision_state.external[external_depot] |
2356 | 2376 |
2357 new_revision_list = self.PrepareToBisectOnDepot( | 2377 new_revision_list = self.PrepareToBisectOnDepot( |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2427 | 2447 |
2428 # If the build is broken, remove it and redo search. | 2448 # If the build is broken, remove it and redo search. |
2429 revision_states.pop(next_revision_index) | 2449 revision_states.pop(next_revision_index) |
2430 | 2450 |
2431 max_revision -= 1 | 2451 max_revision -= 1 |
2432 | 2452 |
2433 if self.opts.output_buildbot_annotations: | 2453 if self.opts.output_buildbot_annotations: |
2434 self.printer.PrintPartialResults(bisect_state) | 2454 self.printer.PrintPartialResults(bisect_state) |
2435 bisect_utils.OutputAnnotationStepClosed() | 2455 bisect_utils.OutputAnnotationStepClosed() |
2436 | 2456 |
2437 | |
2438 self._ConfidenceExtraTestRuns(min_revision_state, max_revision_state, | 2457 self._ConfidenceExtraTestRuns(min_revision_state, max_revision_state, |
2439 command_to_run, metric) | 2458 command_to_run, metric) |
2440 results = BisectResults(bisect_state, self.depot_registry, self.opts, | 2459 results = BisectResults(bisect_state, self.depot_registry, self.opts, |
2441 self.warnings) | 2460 self.warnings) |
2442 | 2461 |
2443 self._GatherResultsFromRevertedCulpritCL( | 2462 self._GatherResultsFromRevertedCulpritCL( |
2444 results, target_depot, command_to_run, metric) | 2463 results, target_depot, command_to_run, metric) |
2445 | 2464 |
2446 return results | 2465 return results |
2447 else: | 2466 else: |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2791 else: | 2810 else: |
2792 print 'Could not confirm bug is closed, proceeding.' | 2811 print 'Could not confirm bug is closed, proceeding.' |
2793 if opts.output_buildbot_annotations: | 2812 if opts.output_buildbot_annotations: |
2794 bisect_utils.OutputAnnotationStepClosed() | 2813 bisect_utils.OutputAnnotationStepClosed() |
2795 if issue_closed: | 2814 if issue_closed: |
2796 results = BisectResults(abort_reason='the bug is closed.') | 2815 results = BisectResults(abort_reason='the bug is closed.') |
2797 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) | 2816 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) |
2798 bisect_test.printer.FormatAndPrintResults(results) | 2817 bisect_test.printer.FormatAndPrintResults(results) |
2799 return 0 | 2818 return 0 |
2800 | 2819 |
2801 | |
2802 if opts.extra_src: | 2820 if opts.extra_src: |
2803 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) | 2821 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) |
2804 if not extra_src: | 2822 if not extra_src: |
2805 raise RuntimeError('Invalid or missing --extra_src.') | 2823 raise RuntimeError('Invalid or missing --extra_src.') |
2806 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) | 2824 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) |
2807 | 2825 |
2808 if opts.working_directory: | 2826 if opts.working_directory: |
2809 custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS | 2827 custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS |
2810 if opts.no_custom_deps: | 2828 if opts.no_custom_deps: |
2811 custom_deps = None | 2829 custom_deps = None |
(...skipping 30 matching lines...) Expand all Loading... | |
2842 # bugs. If you change this, please update the perf dashboard as well. | 2860 # bugs. If you change this, please update the perf dashboard as well. |
2843 bisect_utils.OutputAnnotationStepStart('Results') | 2861 bisect_utils.OutputAnnotationStepStart('Results') |
2844 print 'Runtime Error: %s' % e | 2862 print 'Runtime Error: %s' % e |
2845 if opts.output_buildbot_annotations: | 2863 if opts.output_buildbot_annotations: |
2846 bisect_utils.OutputAnnotationStepClosed() | 2864 bisect_utils.OutputAnnotationStepClosed() |
2847 return 1 | 2865 return 1 |
2848 | 2866 |
2849 | 2867 |
2850 if __name__ == '__main__': | 2868 if __name__ == '__main__': |
2851 sys.exit(main()) | 2869 sys.exit(main()) |
OLD | NEW |