Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(40)

Side by Side Diff: tools/auto_bisect/bisect_perf_regression.py

Issue 650223005: Refactor source_control.py and add a test. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tools/auto_bisect/bisect_perf_regression_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 import zipfile 47 import zipfile
48 48
49 sys.path.append(os.path.join( 49 sys.path.append(os.path.join(
50 os.path.dirname(__file__), os.path.pardir, 'telemetry')) 50 os.path.dirname(__file__), os.path.pardir, 'telemetry'))
51 51
52 from bisect_results import BisectResults 52 from bisect_results import BisectResults
53 import bisect_utils 53 import bisect_utils
54 import builder 54 import builder
55 import math_utils 55 import math_utils
56 import request_build 56 import request_build
57 import source_control as source_control_module 57 import source_control
58 from telemetry.util import cloud_storage 58 from telemetry.util import cloud_storage
59 59
60 # Below is the map of "depot" names to information about each depot. Each depot 60 # Below is the map of "depot" names to information about each depot. Each depot
61 # is a repository, and in the process of bisecting, revision ranges in these 61 # is a repository, and in the process of bisecting, revision ranges in these
62 # repositories may also be bisected. 62 # repositories may also be bisected.
63 # 63 #
64 # Each depot information dictionary may contain: 64 # Each depot information dictionary may contain:
65 # src: Path to the working directory. 65 # src: Path to the working directory.
66 # recurse: True if this repository will get bisected. 66 # recurse: True if this repository will get bisected.
67 # depends: A list of other repositories that are actually part of the same 67 # depends: A list of other repositories that are actually part of the same
(...skipping 882 matching lines...) Expand 10 before | Expand all | Expand 10 after
950 bisect_utils.RunGit(['branch', '-D', BISECT_TRYJOB_BRANCH]) 950 bisect_utils.RunGit(['branch', '-D', BISECT_TRYJOB_BRANCH])
951 951
952 952
953 class BisectPerformanceMetrics(object): 953 class BisectPerformanceMetrics(object):
954 """This class contains functionality to perform a bisection of a range of 954 """This class contains functionality to perform a bisection of a range of
955 revisions to narrow down where performance regressions may have occurred. 955 revisions to narrow down where performance regressions may have occurred.
956 956
957 The main entry-point is the Run method. 957 The main entry-point is the Run method.
958 """ 958 """
959 959
960 def __init__(self, source_control, opts): 960 def __init__(self, opts):
961 super(BisectPerformanceMetrics, self).__init__() 961 super(BisectPerformanceMetrics, self).__init__()
962 962
963 self.opts = opts 963 self.opts = opts
964 self.source_control = source_control
965 964
966 # The src directory here is NOT the src/ directory for the repository 965 # The src directory here is NOT the src/ directory for the repository
967 # where the bisect script is running from. Instead, it's the src/ directory 966 # where the bisect script is running from. Instead, it's the src/ directory
968 # inside the bisect/ directory which is created before running. 967 # inside the bisect/ directory which is created before running.
969 self.src_cwd = os.getcwd() 968 self.src_cwd = os.getcwd()
970 969
971 self.depot_registry = DepotDirectoryRegistry(self.src_cwd) 970 self.depot_registry = DepotDirectoryRegistry(self.src_cwd)
972 self.cleanup_commands = [] 971 self.cleanup_commands = []
973 self.warnings = [] 972 self.warnings = []
974 self.builder = builder.Builder.FromOpts(opts) 973 self.builder = builder.Builder.FromOpts(opts)
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 assert not return_code, ('An error occurred while running ' 1006 assert not return_code, ('An error occurred while running '
1008 '"%s"' % ' '.join(cmd)) 1007 '"%s"' % ' '.join(cmd))
1009 1008
1010 os.chdir(cwd) 1009 os.chdir(cwd)
1011 1010
1012 revision_work_list = list(set( 1011 revision_work_list = list(set(
1013 [int(o) for o in output.split('\n') if bisect_utils.IsStringInt(o)])) 1012 [int(o) for o in output.split('\n') if bisect_utils.IsStringInt(o)]))
1014 revision_work_list = sorted(revision_work_list, reverse=True) 1013 revision_work_list = sorted(revision_work_list, reverse=True)
1015 else: 1014 else:
1016 cwd = self.depot_registry.GetDepotDir(depot) 1015 cwd = self.depot_registry.GetDepotDir(depot)
1017 revision_work_list = self.source_control.GetRevisionList(bad_revision, 1016 revision_work_list = source_control.GetRevisionList(bad_revision,
1018 good_revision, cwd=cwd) 1017 good_revision, cwd=cwd)
1019 1018
1020 return revision_work_list 1019 return revision_work_list
1021 1020
1022 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision): 1021 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision):
1023 commit_position = self.source_control.GetCommitPosition(revision) 1022 commit_position = source_control.GetCommitPosition(revision)
1024 1023
1025 if bisect_utils.IsStringInt(commit_position): 1024 if bisect_utils.IsStringInt(commit_position):
1026 # V8 is tricky to bisect, in that there are only a few instances when 1025 # V8 is tricky to bisect, in that there are only a few instances when
1027 # we can dive into bleeding_edge and get back a meaningful result. 1026 # we can dive into bleeding_edge and get back a meaningful result.
1028 # Try to detect a V8 "business as usual" case, which is when: 1027 # Try to detect a V8 "business as usual" case, which is when:
1029 # 1. trunk revision N has description "Version X.Y.Z" 1028 # 1. trunk revision N has description "Version X.Y.Z"
1030 # 2. bleeding_edge revision (N-1) has description "Prepare push to 1029 # 2. bleeding_edge revision (N-1) has description "Prepare push to
1031 # trunk. Now working on X.Y.(Z+1)." 1030 # trunk. Now working on X.Y.(Z+1)."
1032 # 1031 #
1033 # As of 01/24/2014, V8 trunk descriptions are formatted: 1032 # As of 01/24/2014, V8 trunk descriptions are formatted:
1034 # "Version 3.X.Y (based on bleeding_edge revision rZ)" 1033 # "Version 3.X.Y (based on bleeding_edge revision rZ)"
1035 # So we can just try parsing that out first and fall back to the old way. 1034 # So we can just try parsing that out first and fall back to the old way.
1036 v8_dir = self.depot_registry.GetDepotDir('v8') 1035 v8_dir = self.depot_registry.GetDepotDir('v8')
1037 v8_bleeding_edge_dir = self.depot_registry.GetDepotDir('v8_bleeding_edge') 1036 v8_bleeding_edge_dir = self.depot_registry.GetDepotDir('v8_bleeding_edge')
1038 1037
1039 revision_info = self.source_control.QueryRevisionInfo(revision, 1038 revision_info = source_control.QueryRevisionInfo(revision, cwd=v8_dir)
1040 cwd=v8_dir)
1041 1039
1042 version_re = re.compile("Version (?P<values>[0-9,.]+)") 1040 version_re = re.compile("Version (?P<values>[0-9,.]+)")
1043 1041
1044 regex_results = version_re.search(revision_info['subject']) 1042 regex_results = version_re.search(revision_info['subject'])
1045 1043
1046 if regex_results: 1044 if regex_results:
1047 git_revision = None 1045 git_revision = None
1048 1046
1049 # Look for "based on bleeding_edge" and parse out revision 1047 # Look for "based on bleeding_edge" and parse out revision
1050 if 'based on bleeding_edge' in revision_info['subject']: 1048 if 'based on bleeding_edge' in revision_info['subject']:
1051 try: 1049 try:
1052 bleeding_edge_revision = revision_info['subject'].split( 1050 bleeding_edge_revision = revision_info['subject'].split(
1053 'bleeding_edge revision r')[1] 1051 'bleeding_edge revision r')[1]
1054 bleeding_edge_revision = int(bleeding_edge_revision.split(')')[0]) 1052 bleeding_edge_revision = int(bleeding_edge_revision.split(')')[0])
1055 git_revision = self.source_control.ResolveToRevision( 1053 git_revision = source_control.ResolveToRevision(
1056 bleeding_edge_revision, 'v8_bleeding_edge', DEPOT_DEPS_NAME, 1, 1054 bleeding_edge_revision, 'v8_bleeding_edge', DEPOT_DEPS_NAME, 1,
1057 cwd=v8_bleeding_edge_dir) 1055 cwd=v8_bleeding_edge_dir)
1058 return git_revision 1056 return git_revision
1059 except (IndexError, ValueError): 1057 except (IndexError, ValueError):
1060 pass 1058 pass
1061 1059
1062 if not git_revision: 1060 if not git_revision:
1063 # Wasn't successful, try the old way of looking for "Prepare push to" 1061 # Wasn't successful, try the old way of looking for "Prepare push to"
1064 git_revision = self.source_control.ResolveToRevision( 1062 git_revision = source_control.ResolveToRevision(
1065 int(commit_position) - 1, 'v8_bleeding_edge', DEPOT_DEPS_NAME, -1, 1063 int(commit_position) - 1, 'v8_bleeding_edge', DEPOT_DEPS_NAME, -1,
1066 cwd=v8_bleeding_edge_dir) 1064 cwd=v8_bleeding_edge_dir)
1067 1065
1068 if git_revision: 1066 if git_revision:
1069 revision_info = self.source_control.QueryRevisionInfo(git_revision, 1067 revision_info = source_control.QueryRevisionInfo(git_revision,
1070 cwd=v8_bleeding_edge_dir) 1068 cwd=v8_bleeding_edge_dir)
1071 1069
1072 if 'Prepare push to trunk' in revision_info['subject']: 1070 if 'Prepare push to trunk' in revision_info['subject']:
1073 return git_revision 1071 return git_revision
1074 return None 1072 return None
1075 1073
1076 def _GetNearestV8BleedingEdgeFromTrunk(self, revision, search_forward=True): 1074 def _GetNearestV8BleedingEdgeFromTrunk(self, revision, search_forward=True):
1077 cwd = self.depot_registry.GetDepotDir('v8') 1075 cwd = self.depot_registry.GetDepotDir('v8')
1078 cmd = ['log', '--format=%ct', '-1', revision] 1076 cmd = ['log', '--format=%ct', '-1', revision]
1079 output = bisect_utils.CheckRunGit(cmd, cwd=cwd) 1077 output = bisect_utils.CheckRunGit(cmd, cwd=cwd)
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
1270 1268
1271 Returns: 1269 Returns:
1272 Downloaded archive file path if exists, otherwise None. 1270 Downloaded archive file path if exists, otherwise None.
1273 """ 1271 """
1274 # Source archive file path on cloud storage using Git revision. 1272 # Source archive file path on cloud storage using Git revision.
1275 source_file = GetRemoteBuildPath( 1273 source_file = GetRemoteBuildPath(
1276 revision, self.opts.target_platform, target_arch, patch_sha) 1274 revision, self.opts.target_platform, target_arch, patch_sha)
1277 downloaded_archive = FetchFromCloudStorage(gs_bucket, source_file, out_dir) 1275 downloaded_archive = FetchFromCloudStorage(gs_bucket, source_file, out_dir)
1278 if not downloaded_archive: 1276 if not downloaded_archive:
1279 # Get commit position for the given SHA. 1277 # Get commit position for the given SHA.
1280 commit_position = self.source_control.GetCommitPosition(revision) 1278 commit_position = source_control.GetCommitPosition(revision)
1281 if commit_position: 1279 if commit_position:
1282 # Source archive file path on cloud storage using SVN revision. 1280 # Source archive file path on cloud storage using SVN revision.
1283 source_file = GetRemoteBuildPath( 1281 source_file = GetRemoteBuildPath(
1284 commit_position, self.opts.target_platform, target_arch, patch_sha) 1282 commit_position, self.opts.target_platform, target_arch, patch_sha)
1285 return FetchFromCloudStorage(gs_bucket, source_file, out_dir) 1283 return FetchFromCloudStorage(gs_bucket, source_file, out_dir)
1286 return downloaded_archive 1284 return downloaded_archive
1287 1285
1288 def DownloadCurrentBuild(self, revision, depot, build_type='Release'): 1286 def DownloadCurrentBuild(self, revision, depot, build_type='Release'):
1289 """Downloads the build archive for the given revision. 1287 """Downloads the build archive for the given revision.
1290 1288
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1398 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) 1396 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform)
1399 if not fetch_build: 1397 if not fetch_build:
1400 return False 1398 return False
1401 1399
1402 # Create a unique ID for each build request posted to try server builders. 1400 # Create a unique ID for each build request posted to try server builders.
1403 # This ID is added to "Reason" property of the build. 1401 # This ID is added to "Reason" property of the build.
1404 build_request_id = GetSHA1HexDigest( 1402 build_request_id = GetSHA1HexDigest(
1405 '%s-%s-%s' % (git_revision, patch, time.time())) 1403 '%s-%s-%s' % (git_revision, patch, time.time()))
1406 1404
1407 # Reverts any changes to DEPS file. 1405 # Reverts any changes to DEPS file.
1408 self.source_control.CheckoutFileAtRevision( 1406 source_control.CheckoutFileAtRevision(
1409 bisect_utils.FILE_DEPS, git_revision, cwd=self.src_cwd) 1407 bisect_utils.FILE_DEPS, git_revision, cwd=self.src_cwd)
1410 1408
1411 bot_name, build_timeout = GetBuilderNameAndBuildTime( 1409 bot_name, build_timeout = GetBuilderNameAndBuildTime(
1412 self.opts.target_platform, self.opts.target_arch) 1410 self.opts.target_platform, self.opts.target_arch)
1413 target_file = None 1411 target_file = None
1414 try: 1412 try:
1415 # Execute try job request to build revision with patch. 1413 # Execute try job request to build revision with patch.
1416 _BuilderTryjob(git_revision, bot_name, build_request_id, patch) 1414 _BuilderTryjob(git_revision, bot_name, build_request_id, patch)
1417 target_file, error_msg = _WaitUntilBuildIsReady( 1415 target_file, error_msg = _WaitUntilBuildIsReady(
1418 fetch_build, bot_name, self.opts.builder_host, 1416 fetch_build, bot_name, self.opts.builder_host,
(...skipping 26 matching lines...) Expand all
1445 1443
1446 Returns: 1444 Returns:
1447 Updated DEPS content as string if deps key is found, otherwise None. 1445 Updated DEPS content as string if deps key is found, otherwise None.
1448 """ 1446 """
1449 # Check whether the depot and revision pattern in DEPS file vars 1447 # Check whether the depot and revision pattern in DEPS file vars
1450 # e.g. for webkit the format is "webkit_revision": "12345". 1448 # e.g. for webkit the format is "webkit_revision": "12345".
1451 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key, 1449 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key,
1452 re.MULTILINE) 1450 re.MULTILINE)
1453 new_data = None 1451 new_data = None
1454 if re.search(deps_revision, deps_contents): 1452 if re.search(deps_revision, deps_contents):
1455 commit_position = self.source_control.GetCommitPosition( 1453 commit_position = source_control.GetCommitPosition(
1456 git_revision, self.depot_registry.GetDepotDir(depot)) 1454 git_revision, self.depot_registry.GetDepotDir(depot))
1457 if not commit_position: 1455 if not commit_position:
1458 print 'Could not determine commit position for %s' % git_revision 1456 print 'Could not determine commit position for %s' % git_revision
1459 return None 1457 return None
1460 # Update the revision information for the given depot 1458 # Update the revision information for the given depot
1461 new_data = re.sub(deps_revision, str(commit_position), deps_contents) 1459 new_data = re.sub(deps_revision, str(commit_position), deps_contents)
1462 else: 1460 else:
1463 # Check whether the depot and revision pattern in DEPS file vars 1461 # Check whether the depot and revision pattern in DEPS file vars
1464 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..". 1462 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..".
1465 deps_revision = re.compile( 1463 deps_revision = re.compile(
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1536 raise RuntimeError('DEPS file does not exists.[%s]' % deps_file_path) 1534 raise RuntimeError('DEPS file does not exists.[%s]' % deps_file_path)
1537 # Get current chromium revision (git hash). 1535 # Get current chromium revision (git hash).
1538 cmd = ['rev-parse', 'HEAD'] 1536 cmd = ['rev-parse', 'HEAD']
1539 chromium_sha = bisect_utils.CheckRunGit(cmd).strip() 1537 chromium_sha = bisect_utils.CheckRunGit(cmd).strip()
1540 if not chromium_sha: 1538 if not chromium_sha:
1541 raise RuntimeError('Failed to determine Chromium revision for %s' % 1539 raise RuntimeError('Failed to determine Chromium revision for %s' %
1542 revision) 1540 revision)
1543 if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or 1541 if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or
1544 'v8' in DEPOT_DEPS_NAME[depot]['from']): 1542 'v8' in DEPOT_DEPS_NAME[depot]['from']):
1545 # Checkout DEPS file for the current chromium revision. 1543 # Checkout DEPS file for the current chromium revision.
1546 if self.source_control.CheckoutFileAtRevision( 1544 if source_control.CheckoutFileAtRevision(
1547 bisect_utils.FILE_DEPS, chromium_sha, cwd=self.src_cwd): 1545 bisect_utils.FILE_DEPS, chromium_sha, cwd=self.src_cwd):
1548 if self.UpdateDeps(revision, depot, deps_file_path): 1546 if self.UpdateDeps(revision, depot, deps_file_path):
1549 diff_command = [ 1547 diff_command = [
1550 'diff', 1548 'diff',
1551 '--src-prefix=', 1549 '--src-prefix=',
1552 '--dst-prefix=', 1550 '--dst-prefix=',
1553 '--no-ext-diff', 1551 '--no-ext-diff',
1554 bisect_utils.FILE_DEPS, 1552 bisect_utils.FILE_DEPS,
1555 ] 1553 ]
1556 diff_text = bisect_utils.CheckRunGit(diff_command, cwd=self.src_cwd) 1554 diff_text = bisect_utils.CheckRunGit(diff_command, cwd=self.src_cwd)
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1611 Then until crrev.com/276628 *both* (android-chromium-testshell and 1609 Then until crrev.com/276628 *both* (android-chromium-testshell and
1612 android-chrome-shell) work. After that rev 276628 *only* 1610 android-chrome-shell) work. After that rev 276628 *only*
1613 android-chrome-shell works. The bisect_perf_regression.py script should 1611 android-chrome-shell works. The bisect_perf_regression.py script should
1614 handle these cases and set appropriate browser type based on revision. 1612 handle these cases and set appropriate browser type based on revision.
1615 """ 1613 """
1616 if self.opts.target_platform in ['android']: 1614 if self.opts.target_platform in ['android']:
1617 # When its a third_party depot, get the chromium revision. 1615 # When its a third_party depot, get the chromium revision.
1618 if depot != 'chromium': 1616 if depot != 'chromium':
1619 revision = bisect_utils.CheckRunGit( 1617 revision = bisect_utils.CheckRunGit(
1620 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip() 1618 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip()
1621 commit_position = self.source_control.GetCommitPosition(revision, 1619 commit_position = source_control.GetCommitPosition(revision,
1622 cwd=self.src_cwd) 1620 cwd=self.src_cwd)
1623 if not commit_position: 1621 if not commit_position:
1624 return command_to_run 1622 return command_to_run
1625 cmd_re = re.compile('--browser=(?P<browser_type>\S+)') 1623 cmd_re = re.compile('--browser=(?P<browser_type>\S+)')
1626 matches = cmd_re.search(command_to_run) 1624 matches = cmd_re.search(command_to_run)
1627 if bisect_utils.IsStringInt(commit_position) and matches: 1625 if bisect_utils.IsStringInt(commit_position) and matches:
1628 cmd_browser = matches.group('browser_type') 1626 cmd_browser = matches.group('browser_type')
1629 if commit_position <= 274857 and cmd_browser == 'android-chrome-shell': 1627 if commit_position <= 274857 and cmd_browser == 'android-chrome-shell':
1630 return command_to_run.replace(cmd_browser, 1628 return command_to_run.replace(cmd_browser,
1631 'android-chromium-testshell') 1629 'android-chromium-testshell')
1632 elif (commit_position >= 276628 and 1630 elif (commit_position >= 276628 and
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
1796 """ 1794 """
1797 revisions_to_sync = [[depot, revision]] 1795 revisions_to_sync = [[depot, revision]]
1798 1796
1799 is_base = ((depot == 'chromium') or (depot == 'cros') or 1797 is_base = ((depot == 'chromium') or (depot == 'cros') or
1800 (depot == 'android-chrome')) 1798 (depot == 'android-chrome'))
1801 1799
1802 # Some SVN depots were split into multiple git depots, so we need to 1800 # Some SVN depots were split into multiple git depots, so we need to
1803 # figure out for each mirror which git revision to grab. There's no 1801 # figure out for each mirror which git revision to grab. There's no
1804 # guarantee that the SVN revision will exist for each of the dependent 1802 # guarantee that the SVN revision will exist for each of the dependent
1805 # depots, so we have to grep the git logs and grab the next earlier one. 1803 # depots, so we have to grep the git logs and grab the next earlier one.
1806 if (not is_base 1804 if not is_base and DEPOT_DEPS_NAME[depot]['depends']:
1807 and DEPOT_DEPS_NAME[depot]['depends'] 1805 commit_position = source_control.GetCommitPosition(revision)
1808 and self.source_control.IsGit()):
1809 commit_position = self.source_control.GetCommitPosition(revision)
1810 1806
1811 for d in DEPOT_DEPS_NAME[depot]['depends']: 1807 for d in DEPOT_DEPS_NAME[depot]['depends']:
1812 self.depot_registry.ChangeToDepotDir(d) 1808 self.depot_registry.ChangeToDepotDir(d)
1813 1809
1814 dependant_rev = self.source_control.ResolveToRevision( 1810 dependant_rev = source_control.ResolveToRevision(
1815 commit_position, d, DEPOT_DEPS_NAME, -1000) 1811 commit_position, d, DEPOT_DEPS_NAME, -1000)
1816 1812
1817 if dependant_rev: 1813 if dependant_rev:
1818 revisions_to_sync.append([d, dependant_rev]) 1814 revisions_to_sync.append([d, dependant_rev])
1819 1815
1820 num_resolved = len(revisions_to_sync) 1816 num_resolved = len(revisions_to_sync)
1821 num_needed = len(DEPOT_DEPS_NAME[depot]['depends']) 1817 num_needed = len(DEPOT_DEPS_NAME[depot]['depends'])
1822 1818
1823 self.depot_registry.ChangeToDepotDir(depot) 1819 self.depot_registry.ChangeToDepotDir(depot)
1824 1820
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1891 if not builder.SetupAndroidBuildEnvironment(self.opts, 1887 if not builder.SetupAndroidBuildEnvironment(self.opts,
1892 path_to_src=self.src_cwd): 1888 path_to_src=self.src_cwd):
1893 return False 1889 return False
1894 1890
1895 if depot == 'cros': 1891 if depot == 'cros':
1896 return self.CreateCrosChroot() 1892 return self.CreateCrosChroot()
1897 else: 1893 else:
1898 return self.RunGClientHooks() 1894 return self.RunGClientHooks()
1899 return True 1895 return True
1900 1896
1901 def ShouldSkipRevision(self, depot, revision): 1897 @staticmethod
1898 def ShouldSkipRevision(depot, revision):
1902 """Checks whether a particular revision can be safely skipped. 1899 """Checks whether a particular revision can be safely skipped.
1903 1900
1904 Some commits can be safely skipped (such as a DEPS roll), since the tool 1901 Some commits can be safely skipped (such as a DEPS roll), since the tool
1905 is git based those changes would have no effect. 1902 is git based those changes would have no effect.
1906 1903
1907 Args: 1904 Args:
1908 depot: The depot being bisected. 1905 depot: The depot being bisected.
1909 revision: Current revision we're synced to. 1906 revision: Current revision we're synced to.
1910 1907
1911 Returns: 1908 Returns:
1912 True if we should skip building/testing this revision. 1909 True if we should skip building/testing this revision.
1913 """ 1910 """
1914 if depot == 'chromium': 1911 if depot == 'chromium':
1915 if self.source_control.IsGit(): 1912 cmd = ['diff-tree', '--no-commit-id', '--name-only', '-r', revision]
1916 cmd = ['diff-tree', '--no-commit-id', '--name-only', '-r', revision] 1913 output = bisect_utils.CheckRunGit(cmd)
1917 output = bisect_utils.CheckRunGit(cmd)
1918 1914
1919 files = output.splitlines() 1915 files = output.splitlines()
1920 1916
1921 if len(files) == 1 and files[0] == 'DEPS': 1917 if len(files) == 1 and files[0] == 'DEPS':
1922 return True 1918 return True
1923 1919
1924 return False 1920 return False
1925 1921
1926 def RunTest(self, revision, depot, command, metric, skippable=False): 1922 def RunTest(self, revision, depot, command, metric, skippable=False):
1927 """Performs a full sync/build/run of the specified revision. 1923 """Performs a full sync/build/run of the specified revision.
1928 1924
1929 Args: 1925 Args:
1930 revision: The revision to sync to. 1926 revision: The revision to sync to.
1931 depot: The depot that's being used at the moment (src, webkit, etc.) 1927 depot: The depot that's being used at the moment (src, webkit, etc.)
1932 command: The command to execute the performance test. 1928 command: The command to execute the performance test.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
2015 2011
2016 if sync_client: 2012 if sync_client:
2017 self.PerformPreBuildCleanup() 2013 self.PerformPreBuildCleanup()
2018 2014
2019 # When using gclient to sync, you need to specify the depot you 2015 # When using gclient to sync, you need to specify the depot you
2020 # want so that all the dependencies sync properly as well. 2016 # want so that all the dependencies sync properly as well.
2021 # i.e. gclient sync src@<SHA1> 2017 # i.e. gclient sync src@<SHA1>
2022 if sync_client == 'gclient': 2018 if sync_client == 'gclient':
2023 revision = '%s@%s' % (DEPOT_DEPS_NAME[depot]['src'], revision) 2019 revision = '%s@%s' % (DEPOT_DEPS_NAME[depot]['src'], revision)
2024 2020
2025 sync_success = self.source_control.SyncToRevision(revision, sync_client) 2021 sync_success = source_control.SyncToRevision(revision, sync_client)
2026 if not sync_success: 2022 if not sync_success:
2027 return False 2023 return False
2028 2024
2029 return True 2025 return True
2030 2026
2031 def _CheckIfRunPassed(self, current_value, known_good_value, known_bad_value): 2027 def _CheckIfRunPassed(self, current_value, known_good_value, known_bad_value):
2032 """Given known good and bad values, decide if the current_value passed 2028 """Given known good and bad values, decide if the current_value passed
2033 or failed. 2029 or failed.
2034 2030
2035 Args: 2031 Args:
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
2213 good_svn_revision: Last known good svn revision. 2209 good_svn_revision: Last known good svn revision.
2214 2210
2215 Returns: 2211 Returns:
2216 A tuple with the new bad and good revisions. 2212 A tuple with the new bad and good revisions.
2217 """ 2213 """
2218 # DONOT perform nudge because at revision 291563 .DEPS.git was removed 2214 # DONOT perform nudge because at revision 291563 .DEPS.git was removed
2219 # and source contain only DEPS file for dependency changes. 2215 # and source contain only DEPS file for dependency changes.
2220 if good_svn_revision >= 291563: 2216 if good_svn_revision >= 291563:
2221 return (bad_revision, good_revision) 2217 return (bad_revision, good_revision)
2222 2218
2223 if self.source_control.IsGit() and self.opts.target_platform == 'chromium': 2219 if self.opts.target_platform == 'chromium':
2224 changes_to_deps = self.source_control.QueryFileRevisionHistory( 2220 changes_to_deps = source_control.QueryFileRevisionHistory(
2225 bisect_utils.FILE_DEPS, good_revision, bad_revision) 2221 bisect_utils.FILE_DEPS, good_revision, bad_revision)
2226 2222
2227 if changes_to_deps: 2223 if changes_to_deps:
2228 # DEPS file was changed, search from the oldest change to DEPS file to 2224 # DEPS file was changed, search from the oldest change to DEPS file to
2229 # bad_revision to see if there are matching .DEPS.git changes. 2225 # bad_revision to see if there are matching .DEPS.git changes.
2230 oldest_deps_change = changes_to_deps[-1] 2226 oldest_deps_change = changes_to_deps[-1]
2231 changes_to_gitdeps = self.source_control.QueryFileRevisionHistory( 2227 changes_to_gitdeps = source_control.QueryFileRevisionHistory(
2232 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) 2228 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision)
2233 2229
2234 if len(changes_to_deps) != len(changes_to_gitdeps): 2230 if len(changes_to_deps) != len(changes_to_gitdeps):
2235 # Grab the timestamp of the last DEPS change 2231 # Grab the timestamp of the last DEPS change
2236 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] 2232 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]]
2237 output = bisect_utils.CheckRunGit(cmd) 2233 output = bisect_utils.CheckRunGit(cmd)
2238 commit_time = int(output) 2234 commit_time = int(output)
2239 2235
2240 # Try looking for a commit that touches the .DEPS.git file in the 2236 # Try looking for a commit that touches the .DEPS.git file in the
2241 # next 15 minutes after the DEPS file change. 2237 # next 15 minutes after the DEPS file change.
(...skipping 15 matching lines...) Expand all
2257 self, target_depot, good_revision, bad_revision): 2253 self, target_depot, good_revision, bad_revision):
2258 """Checks that |good_revision| is an earlier revision than |bad_revision|. 2254 """Checks that |good_revision| is an earlier revision than |bad_revision|.
2259 2255
2260 Args: 2256 Args:
2261 good_revision: Number/tag of the known good revision. 2257 good_revision: Number/tag of the known good revision.
2262 bad_revision: Number/tag of the known bad revision. 2258 bad_revision: Number/tag of the known bad revision.
2263 2259
2264 Returns: 2260 Returns:
2265 True if the revisions are in the proper order (good earlier than bad). 2261 True if the revisions are in the proper order (good earlier than bad).
2266 """ 2262 """
2267 if self.source_control.IsGit() and target_depot != 'cros': 2263 if target_depot != 'cros':
2268 cwd = self.depot_registry.GetDepotDir(target_depot) 2264 cwd = self.depot_registry.GetDepotDir(target_depot)
2269 good_position = self.source_control.GetCommitPosition(good_revision, cwd) 2265 good_position = source_control.GetCommitPosition(good_revision, cwd)
2270 bad_position = self.source_control.GetCommitPosition(bad_revision, cwd) 2266 bad_position = source_control.GetCommitPosition(bad_revision, cwd)
2271 else: 2267 else:
2272 # CrOS and SVN use integers. 2268 # CrOS and SVN use integers.
2273 good_position = int(good_revision) 2269 good_position = int(good_revision)
2274 bad_position = int(bad_revision) 2270 bad_position = int(bad_revision)
2275 2271
2276 return good_position <= bad_position 2272 return good_position <= bad_position
2277 2273
2278 def CanPerformBisect(self, good_revision, bad_revision): 2274 def CanPerformBisect(self, good_revision, bad_revision):
2279 """Checks whether a given revision is bisectable. 2275 """Checks whether a given revision is bisectable.
2280 2276
2281 Checks for following: 2277 Checks for following:
2282 1. Non-bisectable revsions for android bots (refer to crbug.com/385324). 2278 1. Non-bisectable revsions for android bots (refer to crbug.com/385324).
2283 2. Non-bisectable revsions for Windows bots (refer to crbug.com/405274). 2279 2. Non-bisectable revsions for Windows bots (refer to crbug.com/405274).
2284 2280
2285 Args: 2281 Args:
2286 good_revision: Known good revision. 2282 good_revision: Known good revision.
2287 bad_revision: Known bad revision. 2283 bad_revision: Known bad revision.
2288 2284
2289 Returns: 2285 Returns:
2290 A dictionary indicating the result. If revision is not bisectable, 2286 A dictionary indicating the result. If revision is not bisectable,
2291 this will contain the field "error", otherwise None. 2287 this will contain the field "error", otherwise None.
2292 """ 2288 """
2293 if self.opts.target_platform == 'android': 2289 if self.opts.target_platform == 'android':
2294 good_revision = self.source_control.GetCommitPosition(good_revision) 2290 good_revision = source_control.GetCommitPosition(good_revision)
2295 if (bisect_utils.IsStringInt(good_revision) 2291 if (bisect_utils.IsStringInt(good_revision)
2296 and good_revision < 265549): 2292 and good_revision < 265549):
2297 return {'error': ( 2293 return {'error': (
2298 'Bisect cannot continue for the given revision range.\n' 2294 'Bisect cannot continue for the given revision range.\n'
2299 'It is impossible to bisect Android regressions ' 2295 'It is impossible to bisect Android regressions '
2300 'prior to r265549, which allows the bisect bot to ' 2296 'prior to r265549, which allows the bisect bot to '
2301 'rely on Telemetry to do apk installation of the most recently ' 2297 'rely on Telemetry to do apk installation of the most recently '
2302 'built local ChromeShell(refer to crbug.com/385324).\n' 2298 'built local ChromeShell(refer to crbug.com/385324).\n'
2303 'Please try bisecting revisions greater than or equal to r265549.')} 2299 'Please try bisecting revisions greater than or equal to r265549.')}
2304 2300
2305 if bisect_utils.IsWindowsHost(): 2301 if bisect_utils.IsWindowsHost():
2306 good_revision = self.source_control.GetCommitPosition(good_revision) 2302 good_revision = source_control.GetCommitPosition(good_revision)
2307 bad_revision = self.source_control.GetCommitPosition(bad_revision) 2303 bad_revision = source_control.GetCommitPosition(bad_revision)
2308 if (bisect_utils.IsStringInt(good_revision) and 2304 if (bisect_utils.IsStringInt(good_revision) and
2309 bisect_utils.IsStringInt(bad_revision)): 2305 bisect_utils.IsStringInt(bad_revision)):
2310 if (289987 <= good_revision < 290716 or 2306 if (289987 <= good_revision < 290716 or
2311 289987 <= bad_revision < 290716): 2307 289987 <= bad_revision < 290716):
2312 return {'error': ('Oops! Revision between r289987 and r290716 are ' 2308 return {'error': ('Oops! Revision between r289987 and r290716 are '
2313 'marked as dead zone for Windows due to ' 2309 'marked as dead zone for Windows due to '
2314 'crbug.com/405274. Please try another range.')} 2310 'crbug.com/405274. Please try another range.')}
2315 2311
2316 return None 2312 return None
2317 2313
2318 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): 2314 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric):
2319 """Given known good and bad revisions, run a binary search on all 2315 """Given known good and bad revisions, run a binary search on all
2320 intermediate revisions to determine the CL where the performance regression 2316 intermediate revisions to determine the CL where the performance regression
2321 occurred. 2317 occurred.
2322 2318
2323 Args: 2319 Args:
2324 command_to_run: Specify the command to execute the performance test. 2320 command_to_run: Specify the command to execute the performance test.
2325 good_revision: Number/tag of the known good revision. 2321 good_revision: Number/tag of the known good revision.
2326 bad_revision: Number/tag of the known bad revision. 2322 bad_revision: Number/tag of the known bad revision.
2327 metric: The performance metric to monitor. 2323 metric: The performance metric to monitor.
2328 2324
2329 Returns: 2325 Returns:
2330 A BisectResults object. 2326 A BisectResults object.
2331 """ 2327 """
2332 results = BisectResults(self.depot_registry, self.source_control) 2328 results = BisectResults(self.depot_registry)
2333 2329
2334 # Choose depot to bisect first 2330 # Choose depot to bisect first
2335 target_depot = 'chromium' 2331 target_depot = 'chromium'
2336 if self.opts.target_platform == 'cros': 2332 if self.opts.target_platform == 'cros':
2337 target_depot = 'cros' 2333 target_depot = 'cros'
2338 elif self.opts.target_platform == 'android-chrome': 2334 elif self.opts.target_platform == 'android-chrome':
2339 target_depot = 'android-chrome' 2335 target_depot = 'android-chrome'
2340 2336
2341 cwd = os.getcwd() 2337 cwd = os.getcwd()
2342 self.depot_registry.ChangeToDepotDir(target_depot) 2338 self.depot_registry.ChangeToDepotDir(target_depot)
2343 2339
2344 # If they passed SVN revisions, we can try match them to git SHA1 hashes. 2340 # If they passed SVN revisions, we can try match them to git SHA1 hashes.
2345 bad_revision = self.source_control.ResolveToRevision( 2341 bad_revision = source_control.ResolveToRevision(
2346 bad_revision_in, target_depot, DEPOT_DEPS_NAME, 100) 2342 bad_revision_in, target_depot, DEPOT_DEPS_NAME, 100)
2347 good_revision = self.source_control.ResolveToRevision( 2343 good_revision = source_control.ResolveToRevision(
2348 good_revision_in, target_depot, DEPOT_DEPS_NAME, -100) 2344 good_revision_in, target_depot, DEPOT_DEPS_NAME, -100)
2349 2345
2350 os.chdir(cwd) 2346 os.chdir(cwd)
2351 if bad_revision is None: 2347 if bad_revision is None:
2352 results.error = 'Couldn\'t resolve [%s] to SHA1.' % bad_revision_in 2348 results.error = 'Couldn\'t resolve [%s] to SHA1.' % bad_revision_in
2353 return results 2349 return results
2354 2350
2355 if good_revision is None: 2351 if good_revision is None:
2356 results.error = 'Couldn\'t resolve [%s] to SHA1.' % good_revision_in 2352 results.error = 'Couldn\'t resolve [%s] to SHA1.' % good_revision_in
2357 return results 2353 return results
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
2603 level = 'high' 2599 level = 'high'
2604 else: 2600 else:
2605 level = 'low' 2601 level = 'low'
2606 warning = ' and warnings' 2602 warning = ' and warnings'
2607 if not self.warnings: 2603 if not self.warnings:
2608 warning = '' 2604 warning = ''
2609 return confidence_status % {'level': level, 'warning': warning} 2605 return confidence_status % {'level': level, 'warning': warning}
2610 2606
2611 def _GetViewVCLinkFromDepotAndHash(self, revision_id, depot): 2607 def _GetViewVCLinkFromDepotAndHash(self, revision_id, depot):
2612 """Gets link to the repository browser.""" 2608 """Gets link to the repository browser."""
2613 info = self.source_control.QueryRevisionInfo(revision_id, 2609 info = source_control.QueryRevisionInfo(revision_id,
2614 self.depot_registry.GetDepotDir(depot)) 2610 self.depot_registry.GetDepotDir(depot))
2615 if depot and DEPOT_DEPS_NAME[depot].has_key('viewvc'): 2611 if depot and DEPOT_DEPS_NAME[depot].has_key('viewvc'):
2616 try: 2612 try:
2617 # Format is "git-svn-id: svn://....@123456 <other data>" 2613 # Format is "git-svn-id: svn://....@123456 <other data>"
2618 svn_line = [i for i in info['body'].splitlines() if 'git-svn-id:' in i] 2614 svn_line = [i for i in info['body'].splitlines() if 'git-svn-id:' in i]
2619 svn_revision = svn_line[0].split('@') 2615 svn_revision = svn_line[0].split('@')
2620 svn_revision = svn_revision[1].split(' ')[0] 2616 svn_revision = svn_revision[1].split(' ')[0]
2621 return DEPOT_DEPS_NAME[depot]['viewvc'] + svn_revision 2617 return DEPOT_DEPS_NAME[depot]['viewvc'] + svn_revision
2622 except IndexError: 2618 except IndexError:
2623 return '' 2619 return ''
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2712 2708
2713 # If confidence is too low, don't bother outputting good/bad. 2709 # If confidence is too low, don't bother outputting good/bad.
2714 if not confidence: 2710 if not confidence:
2715 state_str = '' 2711 state_str = ''
2716 state_str = state_str.center(13, ' ') 2712 state_str = state_str.center(13, ' ')
2717 2713
2718 cl_link = self._GetViewVCLinkFromDepotAndHash(current_id, 2714 cl_link = self._GetViewVCLinkFromDepotAndHash(current_id,
2719 current_data['depot']) 2715 current_data['depot'])
2720 if not cl_link: 2716 if not cl_link:
2721 cl_link = current_id 2717 cl_link = current_id
2722 commit_position = self.source_control.GetCommitPosition( 2718 commit_position = source_control.GetCommitPosition(
2723 current_id, self.depot_registry.GetDepotDir(current_data['depot'])) 2719 current_id, self.depot_registry.GetDepotDir(current_data['depot']))
2724 commit_position = str(commit_position) 2720 commit_position = str(commit_position)
2725 if not commit_position: 2721 if not commit_position:
2726 commit_position = '' 2722 commit_position = ''
2727 self._PrintTestedCommitsEntry(current_data, commit_position, cl_link, 2723 self._PrintTestedCommitsEntry(current_data, commit_position, cl_link,
2728 state_str) 2724 state_str)
2729 2725
2730 def _PrintReproSteps(self): 2726 def _PrintReproSteps(self):
2731 """Prints out a section of the results explaining how to run the test. 2727 """Prints out a section of the results explaining how to run the test.
2732 2728
(...skipping 483 matching lines...) Expand 10 before | Expand all | Expand 10 after
3216 bisect_utils.CreateBisectDirectoryAndSetupDepot(opts, custom_deps) 3212 bisect_utils.CreateBisectDirectoryAndSetupDepot(opts, custom_deps)
3217 3213
3218 os.chdir(os.path.join(os.getcwd(), 'src')) 3214 os.chdir(os.path.join(os.getcwd(), 'src'))
3219 3215
3220 if not RemoveBuildFiles(opts.target_build_type): 3216 if not RemoveBuildFiles(opts.target_build_type):
3221 raise RuntimeError('Something went wrong removing the build files.') 3217 raise RuntimeError('Something went wrong removing the build files.')
3222 3218
3223 if not _IsPlatformSupported(): 3219 if not _IsPlatformSupported():
3224 raise RuntimeError('Sorry, this platform isn\'t supported yet.') 3220 raise RuntimeError('Sorry, this platform isn\'t supported yet.')
3225 3221
3226 # Check what source control method is being used, and create a 3222 if not source_control.IsInGitRepository():
3227 # SourceControl object if possible.
3228 source_control = source_control_module.DetermineAndCreateSourceControl(opts)
3229
3230 if not source_control:
3231 raise RuntimeError( 3223 raise RuntimeError(
3232 'Sorry, only the git workflow is supported at the moment.') 3224 'Sorry, only the git workflow is supported at the moment.')
3233 3225
3234 # gClient sync seems to fail if you're not in master branch. 3226 # gClient sync seems to fail if you're not in master branch.
3235 if (not source_control.IsInProperBranch() and 3227 if (not source_control.IsInProperBranch() and
3236 not opts.debug_ignore_sync and 3228 not opts.debug_ignore_sync and
3237 not opts.working_directory): 3229 not opts.working_directory):
3238 raise RuntimeError('You must switch to master branch to run bisection.') 3230 raise RuntimeError('You must switch to master branch to run bisection.')
3239 bisect_test = BisectPerformanceMetrics(source_control, opts) 3231 bisect_test = BisectPerformanceMetrics(opts)
3240 try: 3232 try:
3241 bisect_results = bisect_test.Run(opts.command, 3233 bisect_results = bisect_test.Run(opts.command,
3242 opts.bad_revision, 3234 opts.bad_revision,
3243 opts.good_revision, 3235 opts.good_revision,
3244 opts.metric) 3236 opts.metric)
3245 if bisect_results.error: 3237 if bisect_results.error:
3246 raise RuntimeError(bisect_results.error) 3238 raise RuntimeError(bisect_results.error)
3247 bisect_test.FormatAndPrintResults(bisect_results) 3239 bisect_test.FormatAndPrintResults(bisect_results)
3248 return 0 3240 return 0
3249 finally: 3241 finally:
3250 bisect_test.PerformCleanup() 3242 bisect_test.PerformCleanup()
3251 except RuntimeError, e: 3243 except RuntimeError, e:
3252 if opts.output_buildbot_annotations: 3244 if opts.output_buildbot_annotations:
3253 # The perf dashboard scrapes the "results" step in order to comment on 3245 # The perf dashboard scrapes the "results" step in order to comment on
3254 # bugs. If you change this, please update the perf dashboard as well. 3246 # bugs. If you change this, please update the perf dashboard as well.
3255 bisect_utils.OutputAnnotationStepStart('Results') 3247 bisect_utils.OutputAnnotationStepStart('Results')
3256 print 'Error: %s' % e.message 3248 print 'Error: %s' % e.message
3257 if opts.output_buildbot_annotations: 3249 if opts.output_buildbot_annotations:
3258 bisect_utils.OutputAnnotationStepClosed() 3250 bisect_utils.OutputAnnotationStepClosed()
3259 return 1 3251 return 1
3260 3252
3261 3253
3262 if __name__ == '__main__': 3254 if __name__ == '__main__':
3263 sys.exit(main()) 3255 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/auto_bisect/bisect_perf_regression_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698