Chromium Code Reviews| 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 |