OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 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 """Performance Test Bisect Tool | 6 """Performance Test Bisect Tool |
7 | 7 |
8 This script bisects a series of changelists using binary search. It starts at | 8 This script bisects a series of changelists using binary search. It starts at |
9 a bad revision where a performance metric has regressed, and asks for a last | 9 a bad revision where a performance metric has regressed, and asks for a last |
10 known-good revision. It will then binary search across this revision range by | 10 known-good revision. It will then binary search across this revision range by |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 command: A list containing the command and args to execute. | 271 command: A list containing the command and args to execute. |
272 | 272 |
273 Returns: | 273 Returns: |
274 The return code of the call. | 274 The return code of the call. |
275 """ | 275 """ |
276 # On Windows, use shell=True to get PATH interpretation. | 276 # On Windows, use shell=True to get PATH interpretation. |
277 shell = IsWindows() | 277 shell = IsWindows() |
278 return subprocess.call(command, shell=shell) | 278 return subprocess.call(command, shell=shell) |
279 | 279 |
280 | 280 |
281 def RunProcessAndRetrieveOutput(command): | 281 def RunProcessAndRetrieveOutput(command, cwd=None): |
282 """Run an arbitrary command, returning its output and return code. Since | 282 """Run an arbitrary command, returning its output and return code. Since |
283 output is collected via communicate(), there will be no output until the | 283 output is collected via communicate(), there will be no output until the |
284 call terminates. If you need output while the program runs (ie. so | 284 call terminates. If you need output while the program runs (ie. so |
285 that the buildbot doesn't terminate the script), consider RunProcess(). | 285 that the buildbot doesn't terminate the script), consider RunProcess(). |
286 | 286 |
287 Args: | 287 Args: |
288 command: A list containing the command and args to execute. | 288 command: A list containing the command and args to execute. |
289 print_output: Optional parameter to write output to stdout as it's | |
290 being collected. | |
291 | 289 |
292 Returns: | 290 Returns: |
293 A tuple of the output and return code. | 291 A tuple of the output and return code. |
294 """ | 292 """ |
295 # On Windows, use shell=True to get PATH interpretation. | 293 # On Windows, use shell=True to get PATH interpretation. |
296 shell = IsWindows() | 294 shell = IsWindows() |
297 proc = subprocess.Popen(command, | 295 proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, cwd=cwd) |
298 shell=shell, | |
299 stdout=subprocess.PIPE) | |
300 | 296 |
301 (output, _) = proc.communicate() | 297 (output, _) = proc.communicate() |
302 | 298 |
303 return (output, proc.returncode) | 299 return (output, proc.returncode) |
304 | 300 |
305 | 301 |
306 def RunGit(command): | 302 def RunGit(command, cwd=None): |
307 """Run a git subcommand, returning its output and return code. | 303 """Run a git subcommand, returning its output and return code. |
308 | 304 |
309 Args: | 305 Args: |
310 command: A list containing the args to git. | 306 command: A list containing the args to git. |
311 | 307 |
312 Returns: | 308 Returns: |
313 A tuple of the output and return code. | 309 A tuple of the output and return code. |
314 """ | 310 """ |
315 command = ['git'] + command | 311 command = ['git'] + command |
316 | 312 |
317 return RunProcessAndRetrieveOutput(command) | 313 return RunProcessAndRetrieveOutput(command, cwd=cwd) |
318 | 314 |
319 | 315 |
320 def CheckRunGit(command): | 316 def CheckRunGit(command, cwd=None): |
321 """Run a git subcommand, returning its output and return code. Asserts if | 317 """Run a git subcommand, returning its output and return code. Asserts if |
322 the return code of the call is non-zero. | 318 the return code of the call is non-zero. |
323 | 319 |
324 Args: | 320 Args: |
325 command: A list containing the args to git. | 321 command: A list containing the args to git. |
326 | 322 |
327 Returns: | 323 Returns: |
328 A tuple of the output and return code. | 324 A tuple of the output and return code. |
329 """ | 325 """ |
330 (output, return_code) = RunGit(command) | 326 (output, return_code) = RunGit(command, cwd=cwd) |
331 | 327 |
332 assert not return_code, 'An error occurred while running'\ | 328 assert not return_code, 'An error occurred while running'\ |
333 ' "git %s"' % ' '.join(command) | 329 ' "git %s"' % ' '.join(command) |
334 return output | 330 return output |
335 | 331 |
336 | 332 |
337 def SetBuildSystemDefault(build_system): | 333 def SetBuildSystemDefault(build_system): |
338 """Sets up any environment variables needed to build with the specified build | 334 """Sets up any environment variables needed to build with the specified build |
339 system. | 335 system. |
340 | 336 |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 | 706 |
711 if not sync_client: | 707 if not sync_client: |
712 results = RunGit(['checkout', revision])[1] | 708 results = RunGit(['checkout', revision])[1] |
713 elif sync_client == 'gclient': | 709 elif sync_client == 'gclient': |
714 results = self.SyncToRevisionWithGClient(revision) | 710 results = self.SyncToRevisionWithGClient(revision) |
715 elif sync_client == 'repo': | 711 elif sync_client == 'repo': |
716 results = self.SyncToRevisionWithRepo(revision) | 712 results = self.SyncToRevisionWithRepo(revision) |
717 | 713 |
718 return not results | 714 return not results |
719 | 715 |
720 def ResolveToRevision(self, revision_to_check, depot, search): | 716 def ResolveToRevision(self, revision_to_check, depot, search, cwd=None): |
721 """If an SVN revision is supplied, try to resolve it to a git SHA1. | 717 """If an SVN revision is supplied, try to resolve it to a git SHA1. |
722 | 718 |
723 Args: | 719 Args: |
724 revision_to_check: The user supplied revision string that may need to be | 720 revision_to_check: The user supplied revision string that may need to be |
725 resolved to a git SHA1. | 721 resolved to a git SHA1. |
726 depot: The depot the revision_to_check is from. | 722 depot: The depot the revision_to_check is from. |
727 search: The number of changelists to try if the first fails to resolve | 723 search: The number of changelists to try if the first fails to resolve |
728 to a git hash. If the value is negative, the function will search | 724 to a git hash. If the value is negative, the function will search |
729 backwards chronologically, otherwise it will search forward. | 725 backwards chronologically, otherwise it will search forward. |
730 | 726 |
(...skipping 15 matching lines...) Expand all Loading... |
746 if search > 0: | 742 if search > 0: |
747 search_range = xrange(svn_revision, svn_revision + search, 1) | 743 search_range = xrange(svn_revision, svn_revision + search, 1) |
748 else: | 744 else: |
749 search_range = xrange(svn_revision, svn_revision + search, -1) | 745 search_range = xrange(svn_revision, svn_revision + search, -1) |
750 | 746 |
751 for i in search_range: | 747 for i in search_range: |
752 svn_pattern = 'git-svn-id: %s@%d' % (depot_svn, i) | 748 svn_pattern = 'git-svn-id: %s@%d' % (depot_svn, i) |
753 cmd = ['log', '--format=%H', '-1', '--grep', svn_pattern, | 749 cmd = ['log', '--format=%H', '-1', '--grep', svn_pattern, |
754 'origin/master'] | 750 'origin/master'] |
755 | 751 |
756 (log_output, return_code) = RunGit(cmd) | 752 (log_output, return_code) = RunGit(cmd, cwd=cwd) |
757 | 753 |
758 assert not return_code, 'An error occurred while running'\ | 754 assert not return_code, 'An error occurred while running'\ |
759 ' "git %s"' % ' '.join(cmd) | 755 ' "git %s"' % ' '.join(cmd) |
760 | 756 |
761 if not return_code: | 757 if not return_code: |
762 log_output = log_output.strip() | 758 log_output = log_output.strip() |
763 | 759 |
764 if log_output: | 760 if log_output: |
765 git_revision = log_output | 761 git_revision = log_output |
766 | 762 |
767 break | 763 break |
768 | 764 |
769 return git_revision | 765 return git_revision |
770 else: | 766 else: |
771 if IsStringInt(revision_to_check): | 767 if IsStringInt(revision_to_check): |
772 return int(revision_to_check) | 768 return int(revision_to_check) |
773 else: | 769 else: |
774 cwd = os.getcwd() | 770 cwd = os.getcwd() |
775 os.chdir(os.path.join(os.getcwd(), 'src', 'third_party', | 771 os.chdir(os.path.join(os.getcwd(), 'src', 'third_party', |
776 'chromiumos-overlay')) | 772 'chromiumos-overlay')) |
777 pattern = CROS_VERSION_PATTERN % revision_to_check | 773 pattern = CROS_VERSION_PATTERN % revision_to_check |
778 cmd = ['log', '--format=%ct', '-1', '--grep', pattern] | 774 cmd = ['log', '--format=%ct', '-1', '--grep', pattern] |
779 | 775 |
780 git_revision = None | 776 git_revision = None |
781 | 777 |
782 log_output = CheckRunGit(cmd) | 778 log_output = CheckRunGit(cmd, cwd=cwd) |
783 if log_output: | 779 if log_output: |
784 git_revision = log_output | 780 git_revision = log_output |
785 git_revision = int(log_output.strip()) | 781 git_revision = int(log_output.strip()) |
786 os.chdir(cwd) | 782 os.chdir(cwd) |
787 | 783 |
788 return git_revision | 784 return git_revision |
789 | 785 |
790 def IsInProperBranch(self): | 786 def IsInProperBranch(self): |
791 """Confirms they're in the master branch for performing the bisection. | 787 """Confirms they're in the master branch for performing the bisection. |
792 This is needed or gclient will fail to sync properly. | 788 This is needed or gclient will fail to sync properly. |
(...skipping 20 matching lines...) Expand all Loading... |
813 cmd = ['svn', 'find-rev', revision] | 809 cmd = ['svn', 'find-rev', revision] |
814 | 810 |
815 output = CheckRunGit(cmd) | 811 output = CheckRunGit(cmd) |
816 svn_revision = output.strip() | 812 svn_revision = output.strip() |
817 | 813 |
818 if IsStringInt(svn_revision): | 814 if IsStringInt(svn_revision): |
819 return int(svn_revision) | 815 return int(svn_revision) |
820 | 816 |
821 return None | 817 return None |
822 | 818 |
823 def QueryRevisionInfo(self, revision): | 819 def QueryRevisionInfo(self, revision, cwd=None): |
824 """Gathers information on a particular revision, such as author's name, | 820 """Gathers information on a particular revision, such as author's name, |
825 email, subject, and date. | 821 email, subject, and date. |
826 | 822 |
827 Args: | 823 Args: |
828 revision: Revision you want to gather information on. | 824 revision: Revision you want to gather information on. |
829 Returns: | 825 Returns: |
830 A dict in the following format: | 826 A dict in the following format: |
831 { | 827 { |
832 'author': %s, | 828 'author': %s, |
833 'email': %s, | 829 'email': %s, |
834 'date': %s, | 830 'date': %s, |
835 'subject': %s, | 831 'subject': %s, |
836 'body': %s, | 832 'body': %s, |
837 } | 833 } |
838 """ | 834 """ |
839 commit_info = {} | 835 commit_info = {} |
840 | 836 |
841 formats = ['%cN', '%cE', '%s', '%cD', '%b'] | 837 formats = ['%cN', '%cE', '%s', '%cD', '%b'] |
842 targets = ['author', 'email', 'subject', 'date', 'body'] | 838 targets = ['author', 'email', 'subject', 'date', 'body'] |
843 | 839 |
844 for i in xrange(len(formats)): | 840 for i in xrange(len(formats)): |
845 cmd = ['log', '--format=%s' % formats[i], '-1', revision] | 841 cmd = ['log', '--format=%s' % formats[i], '-1', revision] |
846 output = CheckRunGit(cmd) | 842 output = CheckRunGit(cmd, cwd=cwd) |
847 commit_info[targets[i]] = output.rstrip() | 843 commit_info[targets[i]] = output.rstrip() |
848 | 844 |
849 return commit_info | 845 return commit_info |
850 | 846 |
851 def CheckoutFileAtRevision(self, file_name, revision): | 847 def CheckoutFileAtRevision(self, file_name, revision): |
852 """Performs a checkout on a file at the given revision. | 848 """Performs a checkout on a file at the given revision. |
853 | 849 |
854 Returns: | 850 Returns: |
855 True if successful. | 851 True if successful. |
856 """ | 852 """ |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 | 945 |
950 revision_work_list = list(set( | 946 revision_work_list = list(set( |
951 [int(o) for o in output.split('\n') if IsStringInt(o)])) | 947 [int(o) for o in output.split('\n') if IsStringInt(o)])) |
952 revision_work_list = sorted(revision_work_list, reverse=True) | 948 revision_work_list = sorted(revision_work_list, reverse=True) |
953 else: | 949 else: |
954 revision_work_list = self.source_control.GetRevisionList(bad_revision, | 950 revision_work_list = self.source_control.GetRevisionList(bad_revision, |
955 good_revision) | 951 good_revision) |
956 | 952 |
957 return revision_work_list | 953 return revision_work_list |
958 | 954 |
| 955 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision): |
| 956 svn_revision = self.source_control.SVNFindRev(revision) |
| 957 |
| 958 if IsStringInt(svn_revision): |
| 959 # V8 is tricky to bisect, in that there are only a few instances when |
| 960 # we can dive into bleeding_edge and get back a meaningful result. |
| 961 # Try to detect a V8 "business as usual" case, which is when: |
| 962 # 1. trunk revision N has description "Version X.Y.Z" |
| 963 # 2. bleeding_edge revision (N-1) has description "Prepare push to |
| 964 # trunk. Now working on X.Y.(Z+1)." |
| 965 v8_dir = self._GetDepotDirectory('v8') |
| 966 v8_bleeding_edge_dir = self._GetDepotDirectory('v8_bleeding_edge') |
| 967 |
| 968 revision_info = self.source_control.QueryRevisionInfo(revision, |
| 969 cwd=v8_dir) |
| 970 |
| 971 version_re = re.compile("Version (?P<values>[0-9,.]+)") |
| 972 |
| 973 regex_results = version_re.search(revision_info['subject']) |
| 974 |
| 975 if regex_results: |
| 976 version = regex_results.group('values') |
| 977 |
| 978 git_revision = self.source_control.ResolveToRevision( |
| 979 int(svn_revision) - 1, 'v8_bleeding_edge', -1, |
| 980 cwd=v8_bleeding_edge_dir) |
| 981 |
| 982 if git_revision: |
| 983 revision_info = self.source_control.QueryRevisionInfo(git_revision, |
| 984 cwd=v8_bleeding_edge_dir) |
| 985 |
| 986 if 'Prepare push to trunk' in revision_info['subject']: |
| 987 return git_revision |
| 988 return None |
| 989 |
| 990 def _GetNearestV8BleedingEdgeFromTrunk(self, revision, search_forward=True): |
| 991 cwd = self._GetDepotDirectory('v8') |
| 992 cmd = ['log', '--format=%ct', '-1', revision] |
| 993 output = CheckRunGit(cmd, cwd=cwd) |
| 994 commit_time = int(output) |
| 995 commits = [] |
| 996 |
| 997 if search_forward: |
| 998 cmd = ['log', '--format=%H', '-10', '--after=%d' % commit_time, |
| 999 'origin/master'] |
| 1000 output = CheckRunGit(cmd, cwd=cwd) |
| 1001 output = output.split() |
| 1002 commits = output |
| 1003 commits = reversed(commits) |
| 1004 else: |
| 1005 cmd = ['log', '--format=%H', '-10', '--before=%d' % commit_time, |
| 1006 'origin/master'] |
| 1007 output = CheckRunGit(cmd, cwd=cwd) |
| 1008 output = output.split() |
| 1009 commits = output |
| 1010 |
| 1011 bleeding_edge_revision = None |
| 1012 |
| 1013 for c in commits: |
| 1014 bleeding_edge_revision = self._GetV8BleedingEdgeFromV8TrunkIfMappable(c) |
| 1015 if bleeding_edge_revision: |
| 1016 break |
| 1017 |
| 1018 return bleeding_edge_revision |
| 1019 |
959 def Get3rdPartyRevisionsFromCurrentRevision(self, depot, revision): | 1020 def Get3rdPartyRevisionsFromCurrentRevision(self, depot, revision): |
960 """Parses the DEPS file to determine WebKit/v8/etc... versions. | 1021 """Parses the DEPS file to determine WebKit/v8/etc... versions. |
961 | 1022 |
962 Returns: | 1023 Returns: |
963 A dict in the format {depot:revision} if successful, otherwise None. | 1024 A dict in the format {depot:revision} if successful, otherwise None. |
964 """ | 1025 """ |
965 | 1026 |
966 cwd = os.getcwd() | 1027 cwd = os.getcwd() |
967 self.ChangeToDepotWorkingDirectory(depot) | 1028 self.ChangeToDepotWorkingDirectory(depot) |
968 | 1029 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1034 | 1095 |
1035 cwd = os.getcwd() | 1096 cwd = os.getcwd() |
1036 self.ChangeToDepotWorkingDirectory('chromium') | 1097 self.ChangeToDepotWorkingDirectory('chromium') |
1037 return_code = CheckRunGit(['log', '-1', '--format=%H', | 1098 return_code = CheckRunGit(['log', '-1', '--format=%H', |
1038 '--author=chrome-release@google.com', '--grep=to %s' % version, | 1099 '--author=chrome-release@google.com', '--grep=to %s' % version, |
1039 'origin/master']) | 1100 'origin/master']) |
1040 os.chdir(cwd) | 1101 os.chdir(cwd) |
1041 | 1102 |
1042 results['chromium'] = output.strip() | 1103 results['chromium'] = output.strip() |
1043 elif depot == 'v8': | 1104 elif depot == 'v8': |
| 1105 # We can't try to map the trunk revision to bleeding edge yet, because |
| 1106 # we don't know which direction to try to search in. Have to wait until |
| 1107 # the bisect has narrowed the results down to 2 v8 rolls. |
1044 results['v8_bleeding_edge'] = None | 1108 results['v8_bleeding_edge'] = None |
1045 | 1109 |
1046 svn_revision = self.source_control.SVNFindRev(revision) | |
1047 | |
1048 if IsStringInt(svn_revision): | |
1049 # V8 is tricky to bisect, in that there are only a few instances when | |
1050 # we can dive into bleeding_edge and get back a meaningful result. | |
1051 # Try to detect a V8 "business as usual" case, which is when: | |
1052 # 1. trunk revision N has description "Version X.Y.Z" | |
1053 # 2. bleeding_edge revision (N-1) has description "Prepare push to | |
1054 # trunk. Now working on X.Y.(Z+1)." | |
1055 self.ChangeToDepotWorkingDirectory(depot) | |
1056 | |
1057 revision_info = self.source_control.QueryRevisionInfo(revision) | |
1058 | |
1059 version_re = re.compile("Version (?P<values>[0-9,.]+)") | |
1060 | |
1061 regex_results = version_re.search(revision_info['subject']) | |
1062 | |
1063 if regex_results: | |
1064 version = regex_results.group('values') | |
1065 | |
1066 self.ChangeToDepotWorkingDirectory('v8_bleeding_edge') | |
1067 | |
1068 git_revision = self.source_control.ResolveToRevision( | |
1069 int(svn_revision) - 1, 'v8_bleeding_edge', -1) | |
1070 | |
1071 if git_revision: | |
1072 revision_info = self.source_control.QueryRevisionInfo(git_revision) | |
1073 | |
1074 if 'Prepare push to trunk' in revision_info['subject']: | |
1075 results['v8_bleeding_edge'] = git_revision | |
1076 | |
1077 return results | 1110 return results |
1078 | 1111 |
1079 def BuildCurrentRevision(self, depot): | 1112 def BuildCurrentRevision(self, depot): |
1080 """Builds chrome and performance_ui_tests on the current revision. | 1113 """Builds chrome and performance_ui_tests on the current revision. |
1081 | 1114 |
1082 Returns: | 1115 Returns: |
1083 True if the build was successful. | 1116 True if the build was successful. |
1084 """ | 1117 """ |
1085 if self.opts.debug_ignore_build: | 1118 if self.opts.debug_ignore_build: |
1086 return True | 1119 return True |
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1600 | 1633 |
1601 Returns: | 1634 Returns: |
1602 True if the current_value is closer to the known_good_value than the | 1635 True if the current_value is closer to the known_good_value than the |
1603 known_bad_value. | 1636 known_bad_value. |
1604 """ | 1637 """ |
1605 dist_to_good_value = abs(current_value['mean'] - known_good_value['mean']) | 1638 dist_to_good_value = abs(current_value['mean'] - known_good_value['mean']) |
1606 dist_to_bad_value = abs(current_value['mean'] - known_bad_value['mean']) | 1639 dist_to_bad_value = abs(current_value['mean'] - known_bad_value['mean']) |
1607 | 1640 |
1608 return dist_to_good_value < dist_to_bad_value | 1641 return dist_to_good_value < dist_to_bad_value |
1609 | 1642 |
| 1643 def _GetDepotDirectory(self, depot_name): |
| 1644 if depot_name == 'chromium': |
| 1645 return self.src_cwd |
| 1646 elif depot_name == 'cros': |
| 1647 return self.cros_cwd |
| 1648 elif depot_name in DEPOT_NAMES: |
| 1649 return self.depot_cwd[depot_name] |
| 1650 else: |
| 1651 assert False, 'Unknown depot [ %s ] encountered. Possibly a new one'\ |
| 1652 ' was added without proper support?' %\ |
| 1653 (depot_name,) |
| 1654 |
1610 def ChangeToDepotWorkingDirectory(self, depot_name): | 1655 def ChangeToDepotWorkingDirectory(self, depot_name): |
1611 """Given a depot, changes to the appropriate working directory. | 1656 """Given a depot, changes to the appropriate working directory. |
1612 | 1657 |
1613 Args: | 1658 Args: |
1614 depot_name: The name of the depot (see DEPOT_NAMES). | 1659 depot_name: The name of the depot (see DEPOT_NAMES). |
1615 """ | 1660 """ |
1616 if depot_name == 'chromium': | 1661 os.chdir(self._GetDepotDirectory(depot_name)) |
1617 os.chdir(self.src_cwd) | |
1618 elif depot_name == 'cros': | |
1619 os.chdir(self.cros_cwd) | |
1620 elif depot_name in DEPOT_NAMES: | |
1621 os.chdir(self.depot_cwd[depot_name]) | |
1622 else: | |
1623 assert False, 'Unknown depot [ %s ] encountered. Possibly a new one'\ | |
1624 ' was added without proper support?' %\ | |
1625 (depot_name,) | |
1626 | 1662 |
1627 def FindNextDepotToBisect(self, current_revision, min_revision_data, | 1663 def _FillInV8BleedingEdgeInfo(self, min_revision_data, max_revision_data): |
1628 max_revision_data): | 1664 r1 = self._GetNearestV8BleedingEdgeFromTrunk(min_revision_data['revision'], |
| 1665 search_forward=True) |
| 1666 r2 = self._GetNearestV8BleedingEdgeFromTrunk(max_revision_data['revision'], |
| 1667 search_forward=False) |
| 1668 min_revision_data['external']['v8_bleeding_edge'] = r1 |
| 1669 max_revision_data['external']['v8_bleeding_edge'] = r2 |
| 1670 |
| 1671 if (not self._GetV8BleedingEdgeFromV8TrunkIfMappable( |
| 1672 min_revision_data['revision']) or |
| 1673 not self._GetV8BleedingEdgeFromV8TrunkIfMappable( |
| 1674 max_revision_data['revision'])): |
| 1675 self.warnings.append('Trunk revisions in V8 did not map directly to ' |
| 1676 'bleeding_edge. Attempted to expand the range to find V8 rolls which ' |
| 1677 'did map directly to bleeding_edge revisions, but results might not ' |
| 1678 'be valid.') |
| 1679 |
| 1680 def _FindNextDepotToBisect(self, current_depot, current_revision, |
| 1681 min_revision_data, max_revision_data): |
1629 """Given the state of the bisect, decides which depot the script should | 1682 """Given the state of the bisect, decides which depot the script should |
1630 dive into next (if any). | 1683 dive into next (if any). |
1631 | 1684 |
1632 Args: | 1685 Args: |
| 1686 current_depot: Current depot being bisected. |
1633 current_revision: Current revision synced to. | 1687 current_revision: Current revision synced to. |
1634 min_revision_data: Data about the earliest revision in the bisect range. | 1688 min_revision_data: Data about the earliest revision in the bisect range. |
1635 max_revision_data: Data about the latest revision in the bisect range. | 1689 max_revision_data: Data about the latest revision in the bisect range. |
1636 | 1690 |
1637 Returns: | 1691 Returns: |
1638 The depot to bisect next, or None. | 1692 The depot to bisect next, or None. |
1639 """ | 1693 """ |
1640 external_depot = None | 1694 external_depot = None |
1641 for current_depot in DEPOT_NAMES: | 1695 for next_depot in DEPOT_NAMES: |
1642 if DEPOT_DEPS_NAME[current_depot].has_key('platform'): | 1696 if DEPOT_DEPS_NAME[next_depot].has_key('platform'): |
1643 if DEPOT_DEPS_NAME[current_depot]['platform'] != os.name: | 1697 if DEPOT_DEPS_NAME[next_depot]['platform'] != os.name: |
1644 continue | 1698 continue |
1645 | 1699 |
1646 if not (DEPOT_DEPS_NAME[current_depot]["recurse"] and | 1700 if not (DEPOT_DEPS_NAME[next_depot]["recurse"] and |
1647 DEPOT_DEPS_NAME[current_depot]['from'] == | 1701 DEPOT_DEPS_NAME[next_depot]['from'] == |
1648 min_revision_data['depot']): | 1702 min_revision_data['depot']): |
1649 continue | 1703 continue |
1650 | 1704 |
1651 if (min_revision_data['external'][current_depot] == | 1705 if current_depot == 'v8': |
1652 max_revision_data['external'][current_depot]): | 1706 # We grab the bleeding_edge info here rather than earlier because we |
| 1707 # finally have the revision range. From that we can search forwards and |
| 1708 # backwards to try to match trunk revisions to bleeding_edge. |
| 1709 self._FillInV8BleedingEdgeInfo(min_revision_data, max_revision_data) |
| 1710 |
| 1711 if (min_revision_data['external'][next_depot] == |
| 1712 max_revision_data['external'][next_depot]): |
1653 continue | 1713 continue |
1654 | 1714 |
1655 if (min_revision_data['external'][current_depot] and | 1715 if (min_revision_data['external'][next_depot] and |
1656 max_revision_data['external'][current_depot]): | 1716 max_revision_data['external'][next_depot]): |
1657 external_depot = current_depot | 1717 external_depot = next_depot |
1658 break | 1718 break |
1659 | 1719 |
1660 return external_depot | 1720 return external_depot |
1661 | 1721 |
1662 def PrepareToBisectOnDepot(self, | 1722 def PrepareToBisectOnDepot(self, |
1663 current_depot, | 1723 current_depot, |
1664 end_revision, | 1724 end_revision, |
1665 start_revision, | 1725 start_revision, |
1666 previous_depot, | 1726 previous_depot, |
1667 previous_revision): | 1727 previous_revision): |
(...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2047 if max_revision - min_revision <= 1: | 2107 if max_revision - min_revision <= 1: |
2048 current_depot = min_revision_data['depot'] | 2108 current_depot = min_revision_data['depot'] |
2049 if min_revision_data['passed'] == '?': | 2109 if min_revision_data['passed'] == '?': |
2050 next_revision_index = min_revision | 2110 next_revision_index = min_revision |
2051 elif max_revision_data['passed'] == '?': | 2111 elif max_revision_data['passed'] == '?': |
2052 next_revision_index = max_revision | 2112 next_revision_index = max_revision |
2053 elif current_depot in ['cros', 'chromium', 'v8']: | 2113 elif current_depot in ['cros', 'chromium', 'v8']: |
2054 previous_revision = revision_list[min_revision] | 2114 previous_revision = revision_list[min_revision] |
2055 # If there were changes to any of the external libraries we track, | 2115 # If there were changes to any of the external libraries we track, |
2056 # should bisect the changes there as well. | 2116 # should bisect the changes there as well. |
2057 external_depot = self.FindNextDepotToBisect( | 2117 external_depot = self._FindNextDepotToBisect(current_depot, |
2058 previous_revision, min_revision_data, max_revision_data) | 2118 previous_revision, min_revision_data, max_revision_data) |
2059 | 2119 |
2060 # If there was no change in any of the external depots, the search | 2120 # If there was no change in any of the external depots, the search |
2061 # is over. | 2121 # is over. |
2062 if not external_depot: | 2122 if not external_depot: |
2063 if current_depot == 'v8': | 2123 if current_depot == 'v8': |
2064 self.warnings.append('Unfortunately, V8 bisection couldn\'t ' | 2124 self.warnings.append('Unfortunately, V8 bisection couldn\'t ' |
2065 'continue any further. The script can only bisect into ' | 2125 'continue any further. The script can only bisect into ' |
2066 'V8\'s bleeding_edge repository if both the current and ' | 2126 'V8\'s bleeding_edge repository if both the current and ' |
2067 'previous revisions in trunk map directly to revisions in ' | 2127 'previous revisions in trunk map directly to revisions in ' |
(...skipping 778 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2846 # The perf dashboard scrapes the "results" step in order to comment on | 2906 # The perf dashboard scrapes the "results" step in order to comment on |
2847 # bugs. If you change this, please update the perf dashboard as well. | 2907 # bugs. If you change this, please update the perf dashboard as well. |
2848 bisect_utils.OutputAnnotationStepStart('Results') | 2908 bisect_utils.OutputAnnotationStepStart('Results') |
2849 print 'Error: %s' % e.message | 2909 print 'Error: %s' % e.message |
2850 if opts.output_buildbot_annotations: | 2910 if opts.output_buildbot_annotations: |
2851 bisect_utils.OutputAnnotationStepClosed() | 2911 bisect_utils.OutputAnnotationStepClosed() |
2852 return 1 | 2912 return 1 |
2853 | 2913 |
2854 if __name__ == '__main__': | 2914 if __name__ == '__main__': |
2855 sys.exit(main()) | 2915 sys.exit(main()) |
OLD | NEW |