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 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1355 if parsed_metric: | 1359 if parsed_metric: |
1356 metric_values.append(math_utils.Mean(parsed_metric)) | 1360 metric_values.append(math_utils.Mean(parsed_metric)) |
1357 # If we're bisecting on a metric (ie, changes in the mean or | 1361 # If we're bisecting on a metric (ie, changes in the mean or |
1358 # standard deviation) and no metric values are produced, bail out. | 1362 # standard deviation) and no metric values are produced, bail out. |
1359 if not metric_values: | 1363 if not metric_values: |
1360 break | 1364 break |
1361 elif self._IsBisectModeReturnCode(): | 1365 elif self._IsBisectModeReturnCode(): |
1362 metric_values.append(return_code) | 1366 metric_values.append(return_code) |
1363 | 1367 |
1364 elapsed_minutes = (time.time() - start_time) / 60.0 | 1368 elapsed_minutes = (time.time() - start_time) / 60.0 |
1365 time_limit = self.opts.max_time_minutes * test_run_multiplier | 1369 time_limit = self.opts.max_time_minutes * test_run_multiplier |
1366 if elapsed_minutes >= time_limit: | 1370 if elapsed_minutes >= time_limit: |
1367 break | 1371 break |
1368 | 1372 |
1369 if metric and len(metric_values) == 0: | 1373 if metric and len(metric_values) == 0: |
1370 err_text = 'Metric %s was not found in the test output.' % metric | 1374 err_text = 'Metric %s was not found in the test output.' % metric |
1371 # TODO(qyearsley): Consider also getting and displaying a list of metrics | 1375 # TODO(qyearsley): Consider also getting and displaying a list of metrics |
1372 # that were found in the output here. | 1376 # that were found in the output here. |
1373 return (err_text, failure_code, output_of_all_runs) | 1377 return (err_text, failure_code, output_of_all_runs) |
1374 | 1378 |
1375 # If we're bisecting on return codes, we're really just looking for zero vs | 1379 # If we're bisecting on return codes, we're really just looking for zero vs |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1435 def _RunPostSync(self, _depot): | 1439 def _RunPostSync(self, _depot): |
1436 """Performs any work after syncing. | 1440 """Performs any work after syncing. |
1437 | 1441 |
1438 Args: | 1442 Args: |
1439 depot: Depot name. | 1443 depot: Depot name. |
1440 | 1444 |
1441 Returns: | 1445 Returns: |
1442 True if successful. | 1446 True if successful. |
1443 """ | 1447 """ |
1444 if 'android' in self.opts.target_platform: | 1448 if 'android' in self.opts.target_platform: |
1445 if not builder.SetupAndroidBuildEnvironment(self.opts, | 1449 if not builder.SetupAndroidBuildEnvironment( |
1446 path_to_src=self.src_cwd): | 1450 self.opts, path_to_src=self.src_cwd): |
1447 return False | 1451 return False |
1448 | 1452 |
1449 return self.RunGClientHooks() | 1453 return self.RunGClientHooks() |
1450 | 1454 |
1451 @staticmethod | 1455 @staticmethod |
1452 def ShouldSkipRevision(depot, revision): | 1456 def ShouldSkipRevision(depot, revision): |
1453 """Checks whether a particular revision can be safely skipped. | 1457 """Checks whether a particular revision can be safely skipped. |
1454 | 1458 |
1455 Some commits can be safely skipped (such as a DEPS roll for the repos | 1459 Some commits can be safely skipped (such as a DEPS roll for the repos |
1456 still using .DEPS.git), since the tool is git based those changes | 1460 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... |
1541 | 1545 |
1542 # A value other than 0 indicates that the test couldn't be run, and results | 1546 # A value other than 0 indicates that the test couldn't be run, and results |
1543 # should also include an error message. | 1547 # should also include an error message. |
1544 if results[1] != 0: | 1548 if results[1] != 0: |
1545 return results | 1549 return results |
1546 | 1550 |
1547 external_revisions = self._Get3rdPartyRevisions(depot) | 1551 external_revisions = self._Get3rdPartyRevisions(depot) |
1548 | 1552 |
1549 if not external_revisions is None: | 1553 if not external_revisions is None: |
1550 return (results[0], results[1], external_revisions, | 1554 return (results[0], results[1], external_revisions, |
1551 time.time() - after_build_time, after_build_time - | 1555 time.time() - after_build_time, after_build_time - |
1552 start_build_time) | 1556 start_build_time) |
1553 else: | 1557 else: |
1554 return ('Failed to parse DEPS file for external revisions.', | 1558 return ('Failed to parse DEPS file for external revisions.', |
1555 BUILD_RESULT_FAIL) | 1559 BUILD_RESULT_FAIL) |
1556 | 1560 |
1557 def _SyncRevision(self, depot, revision, sync_client): | 1561 def _SyncRevision(self, depot, revision, sync_client): |
1558 """Syncs depot to particular revision. | 1562 """Syncs depot to particular revision. |
1559 | 1563 |
1560 Args: | 1564 Args: |
1561 depot: The depot that's being used at the moment (src, webkit, etc.) | 1565 depot: The depot that's being used at the moment (src, webkit, etc.) |
1562 revision: The revision to sync to. | 1566 revision: The revision to sync to. |
1563 sync_client: Program used to sync, e.g. "gclient". Can be None. | 1567 sync_client: Program used to sync, e.g. "gclient". Can be None. |
1564 | 1568 |
1565 Returns: | 1569 Returns: |
1566 True if successful, False otherwise. | 1570 True if successful, False otherwise. |
1567 """ | 1571 """ |
1568 self.depot_registry.ChangeToDepotDir(depot) | 1572 self.depot_registry.ChangeToDepotDir(depot) |
1569 | 1573 |
1570 if sync_client: | 1574 if sync_client: |
1571 self.PerformPreBuildCleanup() | 1575 self.PerformPreBuildCleanup() |
1572 | 1576 |
1573 # When using gclient to sync, you need to specify the depot you | 1577 # When using gclient to sync, you need to specify the depot you |
1574 # want so that all the dependencies sync properly as well. | 1578 # want so that all the dependencies sync properly as well. |
1575 # i.e. gclient sync src@<SHA1> | 1579 # i.e. gclient sync src@<SHA1> |
1576 if sync_client == 'gclient' and revision: | 1580 if sync_client == 'gclient' and revision: |
1577 revision = '%s@%s' % (bisect_utils.DEPOT_DEPS_NAME[depot]['src'], | 1581 revision = '%s@%s' % (bisect_utils.DEPOT_DEPS_NAME[depot]['src'], |
1578 revision) | 1582 revision) |
1579 if depot == 'chromium' and self.opts.target_platform == 'android-chrome': | 1583 if depot == 'chromium' and self.opts.target_platform == 'android-chrome': |
1580 return self._SyncRevisionsForAndroidChrome(revision) | 1584 return self._SyncRevisionsForAndroidChrome(revision) |
1581 | 1585 |
1582 return source_control.SyncToRevision(revision, sync_client) | 1586 return source_control.SyncToRevision(revision, sync_client) |
1583 | 1587 |
1584 def _SyncRevisionsForAndroidChrome(self, revision): | 1588 def _SyncRevisionsForAndroidChrome(self, revision): |
1585 """Syncs android-chrome and chromium repos to particular revision. | 1589 """Syncs android-chrome and chromium repos to particular revision. |
1586 | 1590 |
1587 This is a special case for android-chrome as the gclient sync for chromium | 1591 This is a special case for android-chrome as the gclient sync for chromium |
1588 overwrites the android-chrome revision to TOT. Therefore both the repos | 1592 overwrites the android-chrome revision to TOT. Therefore both the repos |
(...skipping 21 matching lines...) Expand all Loading... |
1610 current_value: The value of the metric being checked. | 1614 current_value: The value of the metric being checked. |
1611 known_bad_value: The reference value for a "failed" run. | 1615 known_bad_value: The reference value for a "failed" run. |
1612 known_good_value: The reference value for a "passed" run. | 1616 known_good_value: The reference value for a "passed" run. |
1613 | 1617 |
1614 Returns: | 1618 Returns: |
1615 True if the current_value is closer to the known_good_value than the | 1619 True if the current_value is closer to the known_good_value than the |
1616 known_bad_value. | 1620 known_bad_value. |
1617 """ | 1621 """ |
1618 if self.opts.bisect_mode == bisect_utils.BISECT_MODE_STD_DEV: | 1622 if self.opts.bisect_mode == bisect_utils.BISECT_MODE_STD_DEV: |
1619 dist_to_good_value = abs(current_value['std_dev'] - | 1623 dist_to_good_value = abs(current_value['std_dev'] - |
1620 known_good_value['std_dev']) | 1624 known_good_value['std_dev']) |
1621 dist_to_bad_value = abs(current_value['std_dev'] - | 1625 dist_to_bad_value = abs(current_value['std_dev'] - |
1622 known_bad_value['std_dev']) | 1626 known_bad_value['std_dev']) |
1623 else: | 1627 else: |
1624 dist_to_good_value = abs(current_value['mean'] - known_good_value['mean']) | 1628 dist_to_good_value = abs(current_value['mean'] - known_good_value['mean']) |
1625 dist_to_bad_value = abs(current_value['mean'] - known_bad_value['mean']) | 1629 dist_to_bad_value = abs(current_value['mean'] - known_bad_value['mean']) |
1626 | 1630 |
1627 return dist_to_good_value < dist_to_bad_value | 1631 return dist_to_good_value < dist_to_bad_value |
1628 | 1632 |
1629 def _GetV8BleedingEdgeFromV8TrunkIfMappable( | 1633 def _GetV8BleedingEdgeFromV8TrunkIfMappable( |
1630 self, revision, bleeding_edge_branch): | 1634 self, revision, bleeding_edge_branch): |
1631 """Gets v8 bleeding edge revision mapped to v8 revision in trunk. | 1635 """Gets v8 bleeding edge revision mapped to v8 revision in trunk. |
1632 | 1636 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1687 return re_results.group('git_revision') | 1691 return re_results.group('git_revision') |
1688 except (IndexError, ValueError): | 1692 except (IndexError, ValueError): |
1689 pass | 1693 pass |
1690 if not git_revision: | 1694 if not git_revision: |
1691 # Wasn't successful, try the old way of looking for "Prepare push to" | 1695 # Wasn't successful, try the old way of looking for "Prepare push to" |
1692 git_revision = source_control.ResolveToRevision( | 1696 git_revision = source_control.ResolveToRevision( |
1693 int(commit_position) - 1, 'v8_bleeding_edge', | 1697 int(commit_position) - 1, 'v8_bleeding_edge', |
1694 bisect_utils.DEPOT_DEPS_NAME, -1, cwd=v8_bleeding_edge_dir) | 1698 bisect_utils.DEPOT_DEPS_NAME, -1, cwd=v8_bleeding_edge_dir) |
1695 | 1699 |
1696 if git_revision: | 1700 if git_revision: |
1697 revision_info = source_control.QueryRevisionInfo(git_revision, | 1701 revision_info = source_control.QueryRevisionInfo( |
1698 cwd=v8_bleeding_edge_dir) | 1702 git_revision, cwd=v8_bleeding_edge_dir) |
1699 | 1703 |
1700 if 'Prepare push to trunk' in revision_info['subject']: | 1704 if 'Prepare push to trunk' in revision_info['subject']: |
1701 return git_revision | 1705 return git_revision |
1702 return None | 1706 return None |
1703 | 1707 |
1704 def _GetNearestV8BleedingEdgeFromTrunk( | 1708 def _GetNearestV8BleedingEdgeFromTrunk( |
1705 self, revision, v8_branch, bleeding_edge_branch, search_forward=True): | 1709 self, revision, v8_branch, bleeding_edge_branch, search_forward=True): |
1706 """Gets the nearest V8 roll and maps to bleeding edge revision. | 1710 """Gets the nearest V8 roll and maps to bleeding edge revision. |
1707 | 1711 |
1708 V8 is a bit tricky to bisect since it isn't just rolled out like blink. | 1712 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... |
1765 | 1769 |
1766 # Support for the chromium revisions with external V8 repo. | 1770 # Support for the chromium revisions with external V8 repo. |
1767 # ie https://chromium.googlesource.com/external/v8.git | 1771 # ie https://chromium.googlesource.com/external/v8.git |
1768 cmd = ['config', '--get', 'remote.origin.url'] | 1772 cmd = ['config', '--get', 'remote.origin.url'] |
1769 v8_repo_url = bisect_utils.CheckRunGit(cmd, cwd=cwd) | 1773 v8_repo_url = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
1770 | 1774 |
1771 if 'external/v8.git' in v8_repo_url: | 1775 if 'external/v8.git' in v8_repo_url: |
1772 v8_branch = 'origin/master' | 1776 v8_branch = 'origin/master' |
1773 bleeding_edge_branch = 'origin/bleeding_edge' | 1777 bleeding_edge_branch = 'origin/bleeding_edge' |
1774 | 1778 |
1775 r1 = self._GetNearestV8BleedingEdgeFromTrunk(min_revision_state.revision, | 1779 r1 = self._GetNearestV8BleedingEdgeFromTrunk( |
1776 v8_branch, bleeding_edge_branch, search_forward=True) | 1780 min_revision_state.revision, |
1777 r2 = self._GetNearestV8BleedingEdgeFromTrunk(max_revision_state.revision, | 1781 v8_branch, |
1778 v8_branch, bleeding_edge_branch, search_forward=False) | 1782 bleeding_edge_branch, |
| 1783 search_forward=True) |
| 1784 r2 = self._GetNearestV8BleedingEdgeFromTrunk( |
| 1785 max_revision_state.revision, |
| 1786 v8_branch, |
| 1787 bleeding_edge_branch, |
| 1788 search_forward=False) |
1779 min_revision_state.external['v8_bleeding_edge'] = r1 | 1789 min_revision_state.external['v8_bleeding_edge'] = r1 |
1780 max_revision_state.external['v8_bleeding_edge'] = r2 | 1790 max_revision_state.external['v8_bleeding_edge'] = r2 |
1781 | 1791 |
1782 if (not self._GetV8BleedingEdgeFromV8TrunkIfMappable( | 1792 if (not self._GetV8BleedingEdgeFromV8TrunkIfMappable( |
1783 min_revision_state.revision, bleeding_edge_branch) | 1793 min_revision_state.revision, bleeding_edge_branch) |
1784 or not self._GetV8BleedingEdgeFromV8TrunkIfMappable( | 1794 or not self._GetV8BleedingEdgeFromV8TrunkIfMappable( |
1785 max_revision_state.revision, bleeding_edge_branch)): | 1795 max_revision_state.revision, bleeding_edge_branch)): |
1786 self.warnings.append( | 1796 self.warnings.append( |
1787 'Trunk revisions in V8 did not map directly to bleeding_edge. ' | 1797 'Trunk revisions in V8 did not map directly to bleeding_edge. ' |
1788 'Attempted to expand the range to find V8 rolls which did map ' | 1798 'Attempted to expand the range to find V8 rolls which did map ' |
1789 'directly to bleeding_edge revisions, but results might not be ' | 1799 'directly to bleeding_edge revisions, but results might not be ' |
1790 'valid.') | 1800 'valid.') |
1791 | 1801 |
1792 def _FindNextDepotToBisect( | 1802 def _FindNextDepotToBisect( |
1793 self, current_depot, min_revision_state, max_revision_state): | 1803 self, current_depot, min_revision_state, max_revision_state): |
1794 """Decides which depot the script should dive into next (if any). | 1804 """Decides which depot the script should dive into next (if any). |
1795 | 1805 |
1796 Args: | 1806 Args: |
1797 current_depot: Current depot being bisected. | 1807 current_depot: Current depot being bisected. |
1798 min_revision_state: State of the earliest revision in the bisect range. | 1808 min_revision_state: State of the earliest revision in the bisect range. |
1799 max_revision_state: State of the latest revision in the bisect range. | 1809 max_revision_state: State of the latest revision in the bisect range. |
1800 | 1810 |
1801 Returns: | 1811 Returns: |
1802 Name of the depot to bisect next, or None. | 1812 Name of the depot to bisect next, or None. |
1803 """ | 1813 """ |
1804 external_depot = None | 1814 external_depot = None |
1805 for next_depot in bisect_utils.DEPOT_NAMES: | 1815 for next_depot in bisect_utils.DEPOT_NAMES: |
1806 if bisect_utils.DEPOT_DEPS_NAME[next_depot].has_key('platform'): | 1816 if ('platform' in bisect_utils.DEPOT_DEPS_NAME[next_depot] and |
1807 if bisect_utils.DEPOT_DEPS_NAME[next_depot]['platform'] != os.name: | 1817 bisect_utils.DEPOT_DEPS_NAME[next_depot]['platform'] != os.name): |
1808 continue | 1818 continue |
1809 | 1819 |
1810 if not (bisect_utils.DEPOT_DEPS_NAME[next_depot]['recurse'] | 1820 if not (bisect_utils.DEPOT_DEPS_NAME[next_depot]['recurse'] |
1811 and min_revision_state.depot | 1821 and min_revision_state.depot |
1812 in bisect_utils.DEPOT_DEPS_NAME[next_depot]['from']): | 1822 in bisect_utils.DEPOT_DEPS_NAME[next_depot]['from']): |
1813 continue | 1823 continue |
1814 | 1824 |
1815 if current_depot == 'v8': | 1825 if current_depot == 'v8': |
1816 # We grab the bleeding_edge info here rather than earlier because we | 1826 # We grab the bleeding_edge info here rather than earlier because we |
1817 # finally have the revision range. From that we can search forwards and | 1827 # finally have the revision range. From that we can search forwards and |
1818 # backwards to try to match trunk revisions to bleeding_edge. | 1828 # backwards to try to match trunk revisions to bleeding_edge. |
(...skipping 24 matching lines...) Expand all Loading... |
1843 Returns: | 1853 Returns: |
1844 A list containing the revisions between |start_revision| and | 1854 A list containing the revisions between |start_revision| and |
1845 |end_revision| inclusive. | 1855 |end_revision| inclusive. |
1846 """ | 1856 """ |
1847 # Change into working directory of external library to run | 1857 # Change into working directory of external library to run |
1848 # subsequent commands. | 1858 # subsequent commands. |
1849 self.depot_registry.ChangeToDepotDir(current_depot) | 1859 self.depot_registry.ChangeToDepotDir(current_depot) |
1850 | 1860 |
1851 # V8 (and possibly others) is merged in periodically. Bisecting | 1861 # V8 (and possibly others) is merged in periodically. Bisecting |
1852 # this directory directly won't give much good info. | 1862 # this directory directly won't give much good info. |
1853 if bisect_utils.DEPOT_DEPS_NAME[current_depot].has_key('custom_deps'): | 1863 if 'custom_deps' in bisect_utils.DEPOT_DEPS_NAME[current_depot]: |
1854 config_path = os.path.join(self.src_cwd, '..') | 1864 config_path = os.path.join(self.src_cwd, '..') |
1855 if bisect_utils.RunGClientAndCreateConfig( | 1865 if bisect_utils.RunGClientAndCreateConfig( |
1856 self.opts, bisect_utils.DEPOT_DEPS_NAME[current_depot]['custom_deps'], | 1866 self.opts, bisect_utils.DEPOT_DEPS_NAME[current_depot]['custom_deps'], |
1857 cwd=config_path): | 1867 cwd=config_path): |
1858 return [] | 1868 return [] |
1859 if bisect_utils.RunGClient( | 1869 if bisect_utils.RunGClient( |
1860 ['sync', '--revision', previous_revision], cwd=self.src_cwd): | 1870 ['sync', '--revision', previous_revision], cwd=self.src_cwd): |
1861 return [] | 1871 return [] |
1862 | 1872 |
1863 if current_depot == 'v8_bleeding_edge': | 1873 if current_depot == 'v8_bleeding_edge': |
1864 self.depot_registry.ChangeToDepotDir('chromium') | 1874 self.depot_registry.ChangeToDepotDir('chromium') |
1865 | 1875 |
1866 shutil.move('v8', 'v8.bak') | 1876 shutil.move('v8', 'v8.bak') |
1867 shutil.move('v8_bleeding_edge', 'v8') | 1877 shutil.move('v8_bleeding_edge', 'v8') |
1868 | 1878 |
1869 self.cleanup_commands.append(['mv', 'v8', 'v8_bleeding_edge']) | 1879 self.cleanup_commands.append(['mv', 'v8', 'v8_bleeding_edge']) |
1870 self.cleanup_commands.append(['mv', 'v8.bak', 'v8']) | 1880 self.cleanup_commands.append(['mv', 'v8.bak', 'v8']) |
1871 | 1881 |
1872 self.depot_registry.SetDepotDir('v8_bleeding_edge', | 1882 self.depot_registry.SetDepotDir( |
1873 os.path.join(self.src_cwd, 'v8')) | 1883 'v8_bleeding_edge', os.path.join(self.src_cwd, 'v8')) |
1874 self.depot_registry.SetDepotDir('v8', os.path.join(self.src_cwd, | 1884 self.depot_registry.SetDepotDir( |
1875 'v8.bak')) | 1885 'v8', os.path.join(self.src_cwd, 'v8.bak')) |
1876 | 1886 |
1877 self.depot_registry.ChangeToDepotDir(current_depot) | 1887 self.depot_registry.ChangeToDepotDir(current_depot) |
1878 | 1888 |
1879 depot_revision_list = self.GetRevisionList(current_depot, | 1889 depot_revision_list = self.GetRevisionList(current_depot, |
1880 end_revision, | 1890 end_revision, |
1881 start_revision) | 1891 start_revision) |
1882 | 1892 |
1883 self.depot_registry.ChangeToDepotDir('chromium') | 1893 self.depot_registry.ChangeToDepotDir('chromium') |
1884 | 1894 |
1885 return depot_revision_list | 1895 return depot_revision_list |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1953 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) | 1963 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) |
1954 | 1964 |
1955 if len(changes_to_deps) != len(changes_to_gitdeps): | 1965 if len(changes_to_deps) != len(changes_to_gitdeps): |
1956 # Grab the timestamp of the last DEPS change | 1966 # Grab the timestamp of the last DEPS change |
1957 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] | 1967 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] |
1958 output = bisect_utils.CheckRunGit(cmd) | 1968 output = bisect_utils.CheckRunGit(cmd) |
1959 commit_time = int(output) | 1969 commit_time = int(output) |
1960 | 1970 |
1961 # Try looking for a commit that touches the .DEPS.git file in the | 1971 # Try looking for a commit that touches the .DEPS.git file in the |
1962 # next 15 minutes after the DEPS file change. | 1972 # next 15 minutes after the DEPS file change. |
1963 cmd = ['log', '--format=%H', '-1', | 1973 cmd = [ |
1964 '--before=%d' % (commit_time + 900), '--after=%d' % commit_time, | 1974 'log', '--format=%H', '-1', |
1965 'origin/master', '--', bisect_utils.FILE_DEPS_GIT] | 1975 '--before=%d' % (commit_time + 900), |
| 1976 '--after=%d' % commit_time, |
| 1977 'origin/master', '--', bisect_utils.FILE_DEPS_GIT |
| 1978 ] |
1966 output = bisect_utils.CheckRunGit(cmd) | 1979 output = bisect_utils.CheckRunGit(cmd) |
1967 output = output.strip() | 1980 output = output.strip() |
1968 if output: | 1981 if output: |
1969 self.warnings.append('Detected change to DEPS and modified ' | 1982 self.warnings.append( |
| 1983 'Detected change to DEPS and modified ' |
1970 'revision range to include change to .DEPS.git') | 1984 'revision range to include change to .DEPS.git') |
1971 return (output, good_revision) | 1985 return (output, good_revision) |
1972 else: | 1986 else: |
1973 self.warnings.append('Detected change to DEPS but couldn\'t find ' | 1987 self.warnings.append( |
| 1988 'Detected change to DEPS but couldn\'t find ' |
1974 'matching change to .DEPS.git') | 1989 'matching change to .DEPS.git') |
1975 return (bad_revision, good_revision) | 1990 return (bad_revision, good_revision) |
1976 | 1991 |
1977 def CheckIfRevisionsInProperOrder( | 1992 def CheckIfRevisionsInProperOrder( |
1978 self, target_depot, good_revision, bad_revision): | 1993 self, target_depot, good_revision, bad_revision): |
1979 """Checks that |good_revision| is an earlier revision than |bad_revision|. | 1994 """Checks that |good_revision| is an earlier revision than |bad_revision|. |
1980 | 1995 |
1981 Args: | 1996 Args: |
1982 good_revision: Number/tag of the known good revision. | 1997 good_revision: Number/tag of the known good revision. |
1983 bad_revision: Number/tag of the known bad revision. | 1998 bad_revision: Number/tag of the known bad revision. |
(...skipping 10 matching lines...) Expand all Loading... |
1994 'depot %s', good_position, bad_position, target_depot) | 2009 'depot %s', good_position, bad_position, target_depot) |
1995 good_position = source_control.GetCommitTime(good_revision, cwd=cwd) | 2010 good_position = source_control.GetCommitTime(good_revision, cwd=cwd) |
1996 bad_position = source_control.GetCommitTime(bad_revision, cwd=cwd) | 2011 bad_position = source_control.GetCommitTime(bad_revision, cwd=cwd) |
1997 | 2012 |
1998 return good_position <= bad_position | 2013 return good_position <= bad_position |
1999 | 2014 |
2000 def CanPerformBisect(self, good_revision, bad_revision): | 2015 def CanPerformBisect(self, good_revision, bad_revision): |
2001 """Checks whether a given revision is bisectable. | 2016 """Checks whether a given revision is bisectable. |
2002 | 2017 |
2003 Checks for following: | 2018 Checks for following: |
2004 1. Non-bisectable revsions for android bots (refer to crbug.com/385324). | 2019 1. Non-bisectable revisions for android bots (refer to crbug.com/385324). |
2005 2. Non-bisectable revsions for Windows bots (refer to crbug.com/405274). | 2020 2. Non-bisectable revisions for Windows bots (refer to crbug.com/405274). |
2006 | 2021 |
2007 Args: | 2022 Args: |
2008 good_revision: Known good revision. | 2023 good_revision: Known good revision. |
2009 bad_revision: Known bad revision. | 2024 bad_revision: Known bad revision. |
2010 | 2025 |
2011 Returns: | 2026 Returns: |
2012 A dictionary indicating the result. If revision is not bisectable, | 2027 A dictionary indicating the result. If revision is not bisectable, |
2013 this will contain the field "error", otherwise None. | 2028 this will contain the field "error", otherwise None. |
2014 """ | 2029 """ |
2015 if self.opts.target_platform == 'android': | 2030 if self.opts.target_platform == 'android': |
(...skipping 29 matching lines...) Expand all Loading... |
2045 performance tests again with and without the CL, adding the results to | 2060 performance tests again with and without the CL, adding the results to |
2046 the over bisect results. | 2061 the over bisect results. |
2047 | 2062 |
2048 Args: | 2063 Args: |
2049 results: BisectResults from the bisect. | 2064 results: BisectResults from the bisect. |
2050 target_depot: The target depot we're bisecting. | 2065 target_depot: The target depot we're bisecting. |
2051 command_to_run: Specify the command to execute the performance test. | 2066 command_to_run: Specify the command to execute the performance test. |
2052 metric: The performance metric to monitor. | 2067 metric: The performance metric to monitor. |
2053 """ | 2068 """ |
2054 run_results_tot, run_results_reverted = self._RevertCulpritCLAndRetest( | 2069 run_results_tot, run_results_reverted = self._RevertCulpritCLAndRetest( |
2055 results, target_depot, command_to_run, metric) | 2070 results, target_depot, command_to_run, metric) |
2056 | 2071 |
2057 results.AddRetestResults(run_results_tot, run_results_reverted) | 2072 results.AddRetestResults(run_results_tot, run_results_reverted) |
2058 | 2073 |
2059 if len(results.culprit_revisions) != 1: | 2074 if len(results.culprit_revisions) != 1: |
2060 return | 2075 return |
2061 | 2076 |
2062 # Cleanup reverted files if anything is left. | 2077 # Cleanup reverted files if anything is left. |
2063 _, _, culprit_depot = results.culprit_revisions[0] | 2078 _, _, culprit_depot = results.culprit_revisions[0] |
2064 bisect_utils.CheckRunGit(['reset', '--hard', 'HEAD'], | 2079 bisect_utils.CheckRunGit( |
| 2080 ['reset', '--hard', 'HEAD'], |
2065 cwd=self.depot_registry.GetDepotDir(culprit_depot)) | 2081 cwd=self.depot_registry.GetDepotDir(culprit_depot)) |
2066 | 2082 |
2067 def _RevertCL(self, culprit_revision, culprit_depot): | 2083 def _RevertCL(self, culprit_revision, culprit_depot): |
2068 """Reverts the specified revision in the specified depot.""" | 2084 """Reverts the specified revision in the specified depot.""" |
2069 if self.opts.output_buildbot_annotations: | 2085 if self.opts.output_buildbot_annotations: |
2070 bisect_utils.OutputAnnotationStepStart( | 2086 bisect_utils.OutputAnnotationStepStart( |
2071 'Reverting culprit CL: %s' % culprit_revision) | 2087 'Reverting culprit CL: %s' % culprit_revision) |
2072 _, return_code = bisect_utils.RunGit( | 2088 _, return_code = bisect_utils.RunGit( |
2073 ['revert', '--no-commit', culprit_revision], | 2089 ['revert', '--no-commit', culprit_revision], |
2074 cwd=self.depot_registry.GetDepotDir(culprit_depot)) | 2090 cwd=self.depot_registry.GetDepotDir(culprit_depot)) |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2125 'Culprit CL is in another depot, attempting to revert and build' | 2141 'Culprit CL is in another depot, attempting to revert and build' |
2126 ' locally to retest. This may not match the performance of official' | 2142 ' locally to retest. This may not match the performance of official' |
2127 ' builds.') | 2143 ' builds.') |
2128 | 2144 |
2129 run_results_reverted = self._RunTestWithAnnotations( | 2145 run_results_reverted = self._RunTestWithAnnotations( |
2130 'Re-Testing ToT with reverted culprit', | 2146 'Re-Testing ToT with reverted culprit', |
2131 'Failed to run reverted CL.', | 2147 'Failed to run reverted CL.', |
2132 head_revision, target_depot, command_to_run, metric, force_build) | 2148 head_revision, target_depot, command_to_run, metric, force_build) |
2133 | 2149 |
2134 # Clear the reverted file(s). | 2150 # Clear the reverted file(s). |
2135 bisect_utils.RunGit(['reset', '--hard', 'HEAD'], | 2151 bisect_utils.RunGit( |
| 2152 ['reset', '--hard', 'HEAD'], |
2136 cwd=self.depot_registry.GetDepotDir(culprit_depot)) | 2153 cwd=self.depot_registry.GetDepotDir(culprit_depot)) |
2137 | 2154 |
2138 # Retesting with the reverted CL failed, so bail out of retesting against | 2155 # Retesting with the reverted CL failed, so bail out of retesting against |
2139 # ToT. | 2156 # ToT. |
2140 if run_results_reverted[1]: | 2157 if run_results_reverted[1]: |
2141 return (None, None) | 2158 return (None, None) |
2142 | 2159 |
2143 run_results_tot = self._RunTestWithAnnotations( | 2160 run_results_tot = self._RunTestWithAnnotations( |
2144 'Re-Testing ToT', | 2161 'Re-Testing ToT', |
2145 'Failed to run ToT.', | 2162 'Failed to run ToT.', |
2146 head_revision, target_depot, command_to_run, metric, force_build) | 2163 head_revision, target_depot, command_to_run, metric, force_build) |
2147 | 2164 |
2148 return (run_results_tot, run_results_reverted) | 2165 return (run_results_tot, run_results_reverted) |
2149 | 2166 |
2150 def _RunTestWithAnnotations(self, step_text, error_text, head_revision, | 2167 def _RunTestWithAnnotations( |
| 2168 self, step_text, error_text, head_revision, |
2151 target_depot, command_to_run, metric, force_build): | 2169 target_depot, command_to_run, metric, force_build): |
2152 """Runs the performance test and outputs start/stop annotations. | 2170 """Runs the performance test and outputs start/stop annotations. |
2153 | 2171 |
2154 Args: | 2172 Args: |
2155 results: BisectResults from the bisect. | 2173 results: BisectResults from the bisect. |
2156 target_depot: The target depot we're bisecting. | 2174 target_depot: The target depot we're bisecting. |
2157 command_to_run: Specify the command to execute the performance test. | 2175 command_to_run: Specify the command to execute the performance test. |
2158 metric: The performance metric to monitor. | 2176 metric: The performance metric to monitor. |
2159 force_build: Whether to force a build locally. | 2177 force_build: Whether to force a build locally. |
2160 | 2178 |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2323 | 2341 |
2324 # Check how likely it is that the good and bad results are different | 2342 # Check how likely it is that the good and bad results are different |
2325 # beyond chance-induced variation. | 2343 # beyond chance-induced variation. |
2326 confidence_error = False | 2344 confidence_error = False |
2327 if not self.opts.debug_ignore_regression_confidence: | 2345 if not self.opts.debug_ignore_regression_confidence: |
2328 confidence_error = _CheckRegressionConfidenceError(good_revision, | 2346 confidence_error = _CheckRegressionConfidenceError(good_revision, |
2329 bad_revision, | 2347 bad_revision, |
2330 known_good_value, | 2348 known_good_value, |
2331 known_bad_value) | 2349 known_bad_value) |
2332 if confidence_error: | 2350 if confidence_error: |
| 2351 # If there is no significant difference between "good" and "bad" |
| 2352 # revision results, then the "bad revision" is considered "good". |
| 2353 # TODO(qyearsley): Remove this if it is not necessary. |
| 2354 bad_revision_state.passed = True |
2333 self.warnings.append(confidence_error) | 2355 self.warnings.append(confidence_error) |
2334 bad_revision_state.passed = True # Marking the 'bad' revision as good. | |
2335 return BisectResults(bisect_state, self.depot_registry, self.opts, | 2356 return BisectResults(bisect_state, self.depot_registry, self.opts, |
2336 self.warnings) | 2357 self.warnings) |
2337 | 2358 |
2338 while True: | 2359 while True: |
2339 if not revision_states: | 2360 if not revision_states: |
2340 break | 2361 break |
2341 | 2362 |
2342 if max_revision - min_revision <= 1: | 2363 if max_revision - min_revision <= 1: |
2343 min_revision_state = revision_states[min_revision] | 2364 min_revision_state = revision_states[min_revision] |
2344 max_revision_state = revision_states[max_revision] | 2365 max_revision_state = revision_states[max_revision] |
2345 current_depot = min_revision_state.depot | 2366 current_depot = min_revision_state.depot |
2346 # TODO(sergiyb): Under which conditions can first two branches be hit? | 2367 # TODO(sergiyb): Under which conditions can first two branches be hit? |
2347 if min_revision_state.passed == '?': | 2368 if min_revision_state.passed == '?': |
2348 next_revision_index = min_revision | 2369 next_revision_index = min_revision |
2349 elif max_revision_state.passed == '?': | 2370 elif max_revision_state.passed == '?': |
2350 next_revision_index = max_revision | 2371 next_revision_index = max_revision |
2351 elif current_depot in ['android-chrome', 'chromium', 'v8']: | 2372 elif current_depot in ['android-chrome', 'chromium', 'v8']: |
2352 previous_revision = revision_states[min_revision].revision | 2373 previous_revision = revision_states[min_revision].revision |
2353 # If there were changes to any of the external libraries we track, | 2374 # If there were changes to any of the external libraries we track, |
2354 # should bisect the changes there as well. | 2375 # should bisect the changes there as well. |
2355 external_depot = self._FindNextDepotToBisect( | 2376 external_depot = self._FindNextDepotToBisect( |
2356 current_depot, min_revision_state, max_revision_state) | 2377 current_depot, min_revision_state, max_revision_state) |
2357 # If there was no change in any of the external depots, the search | 2378 # If there was no change in any of the external depots, the search |
2358 # is over. | 2379 # is over. |
2359 if not external_depot: | 2380 if not external_depot: |
2360 if current_depot == 'v8': | 2381 if current_depot == 'v8': |
2361 self.warnings.append('Unfortunately, V8 bisection couldn\'t ' | 2382 self.warnings.append( |
| 2383 'Unfortunately, V8 bisection couldn\'t ' |
2362 'continue any further. The script can only bisect into ' | 2384 'continue any further. The script can only bisect into ' |
2363 'V8\'s bleeding_edge repository if both the current and ' | 2385 'V8\'s bleeding_edge repository if both the current and ' |
2364 'previous revisions in trunk map directly to revisions in ' | 2386 'previous revisions in trunk map directly to revisions in ' |
2365 'bleeding_edge.') | 2387 'bleeding_edge.') |
2366 break | 2388 break |
2367 | 2389 |
2368 earliest_revision = max_revision_state.external[external_depot] | 2390 earliest_revision = max_revision_state.external[external_depot] |
2369 latest_revision = min_revision_state.external[external_depot] | 2391 latest_revision = min_revision_state.external[external_depot] |
2370 | 2392 |
2371 new_revision_list = self.PrepareToBisectOnDepot( | 2393 new_revision_list = self.PrepareToBisectOnDepot( |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2441 | 2463 |
2442 # If the build is broken, remove it and redo search. | 2464 # If the build is broken, remove it and redo search. |
2443 revision_states.pop(next_revision_index) | 2465 revision_states.pop(next_revision_index) |
2444 | 2466 |
2445 max_revision -= 1 | 2467 max_revision -= 1 |
2446 | 2468 |
2447 if self.opts.output_buildbot_annotations: | 2469 if self.opts.output_buildbot_annotations: |
2448 self.printer.PrintPartialResults(bisect_state) | 2470 self.printer.PrintPartialResults(bisect_state) |
2449 bisect_utils.OutputAnnotationStepClosed() | 2471 bisect_utils.OutputAnnotationStepClosed() |
2450 | 2472 |
2451 | |
2452 self._ConfidenceExtraTestRuns(min_revision_state, max_revision_state, | 2473 self._ConfidenceExtraTestRuns(min_revision_state, max_revision_state, |
2453 command_to_run, metric) | 2474 command_to_run, metric) |
2454 results = BisectResults(bisect_state, self.depot_registry, self.opts, | 2475 results = BisectResults(bisect_state, self.depot_registry, self.opts, |
2455 self.warnings) | 2476 self.warnings) |
2456 | 2477 |
2457 self._GatherResultsFromRevertedCulpritCL( | 2478 self._GatherResultsFromRevertedCulpritCL( |
2458 results, target_depot, command_to_run, metric) | 2479 results, target_depot, command_to_run, metric) |
2459 | 2480 |
2460 return results | 2481 return results |
2461 else: | 2482 else: |
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2805 else: | 2826 else: |
2806 print 'Could not confirm bug is closed, proceeding.' | 2827 print 'Could not confirm bug is closed, proceeding.' |
2807 if opts.output_buildbot_annotations: | 2828 if opts.output_buildbot_annotations: |
2808 bisect_utils.OutputAnnotationStepClosed() | 2829 bisect_utils.OutputAnnotationStepClosed() |
2809 if issue_closed: | 2830 if issue_closed: |
2810 results = BisectResults(abort_reason='the bug is closed.') | 2831 results = BisectResults(abort_reason='the bug is closed.') |
2811 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) | 2832 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) |
2812 bisect_test.printer.FormatAndPrintResults(results) | 2833 bisect_test.printer.FormatAndPrintResults(results) |
2813 return 0 | 2834 return 0 |
2814 | 2835 |
2815 | |
2816 if opts.extra_src: | 2836 if opts.extra_src: |
2817 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) | 2837 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) |
2818 if not extra_src: | 2838 if not extra_src: |
2819 raise RuntimeError('Invalid or missing --extra_src.') | 2839 raise RuntimeError('Invalid or missing --extra_src.') |
2820 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) | 2840 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) |
2821 | 2841 |
2822 if opts.working_directory: | 2842 if opts.working_directory: |
2823 custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS | 2843 custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS |
2824 if opts.no_custom_deps: | 2844 if opts.no_custom_deps: |
2825 custom_deps = None | 2845 custom_deps = None |
(...skipping 30 matching lines...) Expand all Loading... |
2856 # bugs. If you change this, please update the perf dashboard as well. | 2876 # bugs. If you change this, please update the perf dashboard as well. |
2857 bisect_utils.OutputAnnotationStepStart('Results') | 2877 bisect_utils.OutputAnnotationStepStart('Results') |
2858 print 'Runtime Error: %s' % e | 2878 print 'Runtime Error: %s' % e |
2859 if opts.output_buildbot_annotations: | 2879 if opts.output_buildbot_annotations: |
2860 bisect_utils.OutputAnnotationStepClosed() | 2880 bisect_utils.OutputAnnotationStepClosed() |
2861 return 1 | 2881 return 1 |
2862 | 2882 |
2863 | 2883 |
2864 if __name__ == '__main__': | 2884 if __name__ == '__main__': |
2865 sys.exit(main()) | 2885 sys.exit(main()) |
OLD | NEW |