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 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 [int(o) for o in output.split('\n') if bisect_utils.IsStringInt(o)])) | 968 [int(o) for o in output.split('\n') if bisect_utils.IsStringInt(o)])) |
969 revision_work_list = sorted(revision_work_list, reverse=True) | 969 revision_work_list = sorted(revision_work_list, reverse=True) |
970 else: | 970 else: |
971 cwd = self._GetDepotDirectory(depot) | 971 cwd = self._GetDepotDirectory(depot) |
972 revision_work_list = self.source_control.GetRevisionList(bad_revision, | 972 revision_work_list = self.source_control.GetRevisionList(bad_revision, |
973 good_revision, cwd=cwd) | 973 good_revision, cwd=cwd) |
974 | 974 |
975 return revision_work_list | 975 return revision_work_list |
976 | 976 |
977 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision): | 977 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision): |
978 svn_revision = self.source_control.SVNFindRev(revision) | 978 commit_position = self.source_control.GetCommitPosition(revision) |
979 | 979 |
980 if bisect_utils.IsStringInt(svn_revision): | 980 if bisect_utils.IsStringInt(commit_position): |
981 # V8 is tricky to bisect, in that there are only a few instances when | 981 # V8 is tricky to bisect, in that there are only a few instances when |
982 # we can dive into bleeding_edge and get back a meaningful result. | 982 # we can dive into bleeding_edge and get back a meaningful result. |
983 # Try to detect a V8 "business as usual" case, which is when: | 983 # Try to detect a V8 "business as usual" case, which is when: |
984 # 1. trunk revision N has description "Version X.Y.Z" | 984 # 1. trunk revision N has description "Version X.Y.Z" |
985 # 2. bleeding_edge revision (N-1) has description "Prepare push to | 985 # 2. bleeding_edge revision (N-1) has description "Prepare push to |
986 # trunk. Now working on X.Y.(Z+1)." | 986 # trunk. Now working on X.Y.(Z+1)." |
987 # | 987 # |
988 # As of 01/24/2014, V8 trunk descriptions are formatted: | 988 # As of 01/24/2014, V8 trunk descriptions are formatted: |
989 # "Version 3.X.Y (based on bleeding_edge revision rZ)" | 989 # "Version 3.X.Y (based on bleeding_edge revision rZ)" |
990 # So we can just try parsing that out first and fall back to the old way. | 990 # So we can just try parsing that out first and fall back to the old way. |
(...skipping 19 matching lines...) Expand all Loading... |
1010 git_revision = self.source_control.ResolveToRevision( | 1010 git_revision = self.source_control.ResolveToRevision( |
1011 bleeding_edge_revision, 'v8_bleeding_edge', DEPOT_DEPS_NAME, 1, | 1011 bleeding_edge_revision, 'v8_bleeding_edge', DEPOT_DEPS_NAME, 1, |
1012 cwd=v8_bleeding_edge_dir) | 1012 cwd=v8_bleeding_edge_dir) |
1013 return git_revision | 1013 return git_revision |
1014 except (IndexError, ValueError): | 1014 except (IndexError, ValueError): |
1015 pass | 1015 pass |
1016 | 1016 |
1017 if not git_revision: | 1017 if not git_revision: |
1018 # Wasn't successful, try the old way of looking for "Prepare push to" | 1018 # Wasn't successful, try the old way of looking for "Prepare push to" |
1019 git_revision = self.source_control.ResolveToRevision( | 1019 git_revision = self.source_control.ResolveToRevision( |
1020 int(svn_revision) - 1, 'v8_bleeding_edge', DEPOT_DEPS_NAME, -1, | 1020 int(commit_position) - 1, 'v8_bleeding_edge', DEPOT_DEPS_NAME, -1, |
1021 cwd=v8_bleeding_edge_dir) | 1021 cwd=v8_bleeding_edge_dir) |
1022 | 1022 |
1023 if git_revision: | 1023 if git_revision: |
1024 revision_info = self.source_control.QueryRevisionInfo(git_revision, | 1024 revision_info = self.source_control.QueryRevisionInfo(git_revision, |
1025 cwd=v8_bleeding_edge_dir) | 1025 cwd=v8_bleeding_edge_dir) |
1026 | 1026 |
1027 if 'Prepare push to trunk' in revision_info['subject']: | 1027 if 'Prepare push to trunk' in revision_info['subject']: |
1028 return git_revision | 1028 return git_revision |
1029 return None | 1029 return None |
1030 | 1030 |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1224 out_dir: Build output directory where downloaded file is stored. | 1224 out_dir: Build output directory where downloaded file is stored. |
1225 | 1225 |
1226 Returns: | 1226 Returns: |
1227 Downloaded archive file path if exists, otherwise None. | 1227 Downloaded archive file path if exists, otherwise None. |
1228 """ | 1228 """ |
1229 # Source archive file path on cloud storage using Git revision. | 1229 # Source archive file path on cloud storage using Git revision. |
1230 source_file = GetRemoteBuildPath( | 1230 source_file = GetRemoteBuildPath( |
1231 revision, self.opts.target_platform, target_arch, patch_sha) | 1231 revision, self.opts.target_platform, target_arch, patch_sha) |
1232 downloaded_archive = FetchFromCloudStorage(gs_bucket, source_file, out_dir) | 1232 downloaded_archive = FetchFromCloudStorage(gs_bucket, source_file, out_dir) |
1233 if not downloaded_archive: | 1233 if not downloaded_archive: |
1234 # Get SVN revision for the given SHA. | 1234 # Get commit position for the given SHA. |
1235 svn_revision = self.source_control.SVNFindRev(revision) | 1235 commit_position = self.source_control.GetCommitPosition(revision) |
1236 if svn_revision: | 1236 if commit_position: |
1237 # Source archive file path on cloud storage using SVN revision. | 1237 # Source archive file path on cloud storage using SVN revision. |
1238 source_file = GetRemoteBuildPath( | 1238 source_file = GetRemoteBuildPath( |
1239 svn_revision, self.opts.target_platform, target_arch, patch_sha) | 1239 commit_position, self.opts.target_platform, target_arch, patch_sha) |
1240 return FetchFromCloudStorage(gs_bucket, source_file, out_dir) | 1240 return FetchFromCloudStorage(gs_bucket, source_file, out_dir) |
1241 return downloaded_archive | 1241 return downloaded_archive |
1242 | 1242 |
1243 def DownloadCurrentBuild(self, revision, build_type='Release', patch=None): | 1243 def DownloadCurrentBuild(self, revision, build_type='Release', patch=None): |
1244 """Downloads the build archive for the given revision. | 1244 """Downloads the build archive for the given revision. |
1245 | 1245 |
1246 Args: | 1246 Args: |
1247 revision: The Git revision to download or build. | 1247 revision: The Git revision to download or build. |
1248 build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) | 1248 build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) |
1249 patch: A DEPS patch (used while bisecting 3rd party repositories). | 1249 patch: A DEPS patch (used while bisecting 3rd party repositories). |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1400 | 1400 |
1401 Returns: | 1401 Returns: |
1402 Updated DEPS content as string if deps key is found, otherwise None. | 1402 Updated DEPS content as string if deps key is found, otherwise None. |
1403 """ | 1403 """ |
1404 # Check whether the depot and revision pattern in DEPS file vars | 1404 # Check whether the depot and revision pattern in DEPS file vars |
1405 # e.g. for webkit the format is "webkit_revision": "12345". | 1405 # e.g. for webkit the format is "webkit_revision": "12345". |
1406 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key, | 1406 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key, |
1407 re.MULTILINE) | 1407 re.MULTILINE) |
1408 new_data = None | 1408 new_data = None |
1409 if re.search(deps_revision, deps_contents): | 1409 if re.search(deps_revision, deps_contents): |
1410 svn_revision = self.source_control.SVNFindRev( | 1410 commit_position = self.source_control.GetCommitPosition( |
1411 git_revision, self._GetDepotDirectory(depot)) | 1411 git_revision, self._GetDepotDirectory(depot)) |
1412 if not svn_revision: | 1412 if not commit_position: |
1413 print 'Could not determine SVN revision for %s' % git_revision | 1413 print 'Could not determine commit position for %s' % git_revision |
1414 return None | 1414 return None |
1415 # Update the revision information for the given depot | 1415 # Update the revision information for the given depot |
1416 new_data = re.sub(deps_revision, str(svn_revision), deps_contents) | 1416 new_data = re.sub(deps_revision, str(commit_position), deps_contents) |
1417 else: | 1417 else: |
1418 # Check whether the depot and revision pattern in DEPS file vars | 1418 # Check whether the depot and revision pattern in DEPS file vars |
1419 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..". | 1419 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..". |
1420 deps_revision = re.compile( | 1420 deps_revision = re.compile( |
1421 r'(?<=["\']%s["\']: ["\'])([a-fA-F0-9]{40})(?=["\'])' % deps_key, | 1421 r'(?<=["\']%s["\']: ["\'])([a-fA-F0-9]{40})(?=["\'])' % deps_key, |
1422 re.MULTILINE) | 1422 re.MULTILINE) |
1423 if re.search(deps_revision, deps_contents): | 1423 if re.search(deps_revision, deps_contents): |
1424 new_data = re.sub(deps_revision, git_revision, deps_contents) | 1424 new_data = re.sub(deps_revision, git_revision, deps_contents) |
1425 if new_data: | 1425 if new_data: |
1426 # For v8_bleeding_edge revisions change V8 branch in order | 1426 # For v8_bleeding_edge revisions change V8 branch in order |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1571 # Prior to crrev.com/274857 *only* android-chromium-testshell | 1571 # Prior to crrev.com/274857 *only* android-chromium-testshell |
1572 # Then until crrev.com/276628 *both* (android-chromium-testshell and | 1572 # Then until crrev.com/276628 *both* (android-chromium-testshell and |
1573 # android-chrome-shell) work. After that rev 276628 *only* | 1573 # android-chrome-shell) work. After that rev 276628 *only* |
1574 # android-chrome-shell works. bisect-perf-regression.py script should | 1574 # android-chrome-shell works. bisect-perf-regression.py script should |
1575 # handle these cases and set appropriate browser type based on revision. | 1575 # handle these cases and set appropriate browser type based on revision. |
1576 if self.opts.target_platform in ['android']: | 1576 if self.opts.target_platform in ['android']: |
1577 # When its a third_party depot, get the chromium revision. | 1577 # When its a third_party depot, get the chromium revision. |
1578 if depot != 'chromium': | 1578 if depot != 'chromium': |
1579 revision = bisect_utils.CheckRunGit( | 1579 revision = bisect_utils.CheckRunGit( |
1580 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip() | 1580 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip() |
1581 svn_revision = self.source_control.SVNFindRev(revision, cwd=self.src_cwd) | 1581 commit_position = self.source_control.GetCommitPosition(revision, |
1582 if not svn_revision: | 1582 cwd=self.src_cwd) |
| 1583 if not commit_position: |
1583 return command_to_run | 1584 return command_to_run |
1584 cmd_re = re.compile('--browser=(?P<browser_type>\S+)') | 1585 cmd_re = re.compile('--browser=(?P<browser_type>\S+)') |
1585 matches = cmd_re.search(command_to_run) | 1586 matches = cmd_re.search(command_to_run) |
1586 if bisect_utils.IsStringInt(svn_revision) and matches: | 1587 if bisect_utils.IsStringInt(commit_position) and matches: |
1587 cmd_browser = matches.group('browser_type') | 1588 cmd_browser = matches.group('browser_type') |
1588 if svn_revision <= 274857 and cmd_browser == 'android-chrome-shell': | 1589 if commit_position <= 274857 and cmd_browser == 'android-chrome-shell': |
1589 return command_to_run.replace(cmd_browser, | 1590 return command_to_run.replace(cmd_browser, |
1590 'android-chromium-testshell') | 1591 'android-chromium-testshell') |
1591 elif (svn_revision >= 276628 and | 1592 elif (commit_position >= 276628 and |
1592 cmd_browser == 'android-chromium-testshell'): | 1593 cmd_browser == 'android-chromium-testshell'): |
1593 return command_to_run.replace(cmd_browser, | 1594 return command_to_run.replace(cmd_browser, |
1594 'android-chrome-shell') | 1595 'android-chrome-shell') |
1595 return command_to_run | 1596 return command_to_run |
1596 | 1597 |
1597 def RunPerformanceTestAndParseResults( | 1598 def RunPerformanceTestAndParseResults( |
1598 self, command_to_run, metric, reset_on_first_run=False, | 1599 self, command_to_run, metric, reset_on_first_run=False, |
1599 upload_on_last_run=False, results_label=None): | 1600 upload_on_last_run=False, results_label=None): |
1600 """Runs a performance test on the current revision and parses the results. | 1601 """Runs a performance test on the current revision and parses the results. |
1601 | 1602 |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1758 is_base = ((depot == 'chromium') or (depot == 'cros') or | 1759 is_base = ((depot == 'chromium') or (depot == 'cros') or |
1759 (depot == 'android-chrome')) | 1760 (depot == 'android-chrome')) |
1760 | 1761 |
1761 # Some SVN depots were split into multiple git depots, so we need to | 1762 # Some SVN depots were split into multiple git depots, so we need to |
1762 # figure out for each mirror which git revision to grab. There's no | 1763 # figure out for each mirror which git revision to grab. There's no |
1763 # guarantee that the SVN revision will exist for each of the dependent | 1764 # guarantee that the SVN revision will exist for each of the dependent |
1764 # depots, so we have to grep the git logs and grab the next earlier one. | 1765 # depots, so we have to grep the git logs and grab the next earlier one. |
1765 if (not is_base | 1766 if (not is_base |
1766 and DEPOT_DEPS_NAME[depot]['depends'] | 1767 and DEPOT_DEPS_NAME[depot]['depends'] |
1767 and self.source_control.IsGit()): | 1768 and self.source_control.IsGit()): |
1768 svn_rev = self.source_control.SVNFindRev(revision) | 1769 commit_position = self.source_control.GetCommitPosition(revision) |
1769 | 1770 |
1770 for d in DEPOT_DEPS_NAME[depot]['depends']: | 1771 for d in DEPOT_DEPS_NAME[depot]['depends']: |
1771 self.ChangeToDepotWorkingDirectory(d) | 1772 self.ChangeToDepotWorkingDirectory(d) |
1772 | 1773 |
1773 dependant_rev = self.source_control.ResolveToRevision( | 1774 dependant_rev = self.source_control.ResolveToRevision( |
1774 svn_rev, d, DEPOT_DEPS_NAME, -1000) | 1775 commit_position, d, DEPOT_DEPS_NAME, -1000) |
1775 | 1776 |
1776 if dependant_rev: | 1777 if dependant_rev: |
1777 revisions_to_sync.append([d, dependant_rev]) | 1778 revisions_to_sync.append([d, dependant_rev]) |
1778 | 1779 |
1779 num_resolved = len(revisions_to_sync) | 1780 num_resolved = len(revisions_to_sync) |
1780 num_needed = len(DEPOT_DEPS_NAME[depot]['depends']) | 1781 num_needed = len(DEPOT_DEPS_NAME[depot]['depends']) |
1781 | 1782 |
1782 self.ChangeToDepotWorkingDirectory(depot) | 1783 self.ChangeToDepotWorkingDirectory(depot) |
1783 | 1784 |
1784 if not ((num_resolved - 1) == num_needed): | 1785 if not ((num_resolved - 1) == num_needed): |
(...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2276 | 2277 |
2277 Args: | 2278 Args: |
2278 good_revision: Known good revision. | 2279 good_revision: Known good revision. |
2279 bad_revision: Known bad revision. | 2280 bad_revision: Known bad revision. |
2280 | 2281 |
2281 Returns: | 2282 Returns: |
2282 A dictionary indicating the result. If revision is not bisectable, | 2283 A dictionary indicating the result. If revision is not bisectable, |
2283 this will contain the field "error", otherwise None. | 2284 this will contain the field "error", otherwise None. |
2284 """ | 2285 """ |
2285 if self.opts.target_platform == 'android': | 2286 if self.opts.target_platform == 'android': |
2286 revision_to_check = self.source_control.SVNFindRev(good_revision) | 2287 revision_to_check = self.source_control.GetCommitPosition(good_revision) |
2287 if (bisect_utils.IsStringInt(good_revision) | 2288 if (bisect_utils.IsStringInt(good_revision) |
2288 and good_revision < 265549): | 2289 and good_revision < 265549): |
2289 return {'error': ( | 2290 return {'error': ( |
2290 'Bisect cannot continue for the given revision range.\n' | 2291 'Bisect cannot continue for the given revision range.\n' |
2291 'It is impossible to bisect Android regressions ' | 2292 'It is impossible to bisect Android regressions ' |
2292 'prior to r265549, which allows the bisect bot to ' | 2293 'prior to r265549, which allows the bisect bot to ' |
2293 'rely on Telemetry to do apk installation of the most recently ' | 2294 'rely on Telemetry to do apk installation of the most recently ' |
2294 'built local ChromeShell(refer to crbug.com/385324).\n' | 2295 'built local ChromeShell(refer to crbug.com/385324).\n' |
2295 'Please try bisecting revisions greater than or equal to r265549.')} | 2296 'Please try bisecting revisions greater than or equal to r265549.')} |
2296 | 2297 |
2297 if bisect_utils.IsWindowsHost(): | 2298 if bisect_utils.IsWindowsHost(): |
2298 good_revision = self.source_control.SVNFindRev(good_revision) | 2299 good_revision = self.source_control.GetCommitPosition(good_revision) |
2299 bad_revision = self.source_control.SVNFindRev(bad_revision) | 2300 bad_revision = self.source_control.GetCommitPosition(bad_revision) |
2300 if (bisect_utils.IsStringInt(good_revision) and | 2301 if (bisect_utils.IsStringInt(good_revision) and |
2301 bisect_utils.IsStringInt(bad_revision)): | 2302 bisect_utils.IsStringInt(bad_revision)): |
2302 if (289987 <= good_revision < 290716 or | 2303 if (289987 <= good_revision < 290716 or |
2303 289987 <= bad_revision < 290716): | 2304 289987 <= bad_revision < 290716): |
2304 return {'error': ('Oops! Revision between r289987 and r290716 are ' | 2305 return {'error': ('Oops! Revision between r289987 and r290716 are ' |
2305 'marked as dead zone for Windows due to ' | 2306 'marked as dead zone for Windows due to ' |
2306 'crbug.com/405274. Please try another range.')} | 2307 'crbug.com/405274. Please try another range.')} |
2307 | 2308 |
2308 return None | 2309 return None |
2309 | 2310 |
(...skipping 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3397 # bugs. If you change this, please update the perf dashboard as well. | 3398 # bugs. If you change this, please update the perf dashboard as well. |
3398 bisect_utils.OutputAnnotationStepStart('Results') | 3399 bisect_utils.OutputAnnotationStepStart('Results') |
3399 print 'Error: %s' % e.message | 3400 print 'Error: %s' % e.message |
3400 if opts.output_buildbot_annotations: | 3401 if opts.output_buildbot_annotations: |
3401 bisect_utils.OutputAnnotationStepClosed() | 3402 bisect_utils.OutputAnnotationStepClosed() |
3402 return 1 | 3403 return 1 |
3403 | 3404 |
3404 | 3405 |
3405 if __name__ == '__main__': | 3406 if __name__ == '__main__': |
3406 sys.exit(main()) | 3407 sys.exit(main()) |
OLD | NEW |