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

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: 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
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 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
1397 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) 1395 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform)
1398 if not fetch_build: 1396 if not fetch_build:
1399 return False 1397 return False
1400 1398
1401 # Create a unique ID for each build request posted to try server builders. 1399 # Create a unique ID for each build request posted to try server builders.
1402 # This ID is added to "Reason" property of the build. 1400 # This ID is added to "Reason" property of the build.
1403 build_request_id = GetSHA1HexDigest( 1401 build_request_id = GetSHA1HexDigest(
1404 '%s-%s-%s' % (git_revision, patch, time.time())) 1402 '%s-%s-%s' % (git_revision, patch, time.time()))
1405 1403
1406 # Reverts any changes to DEPS file. 1404 # Reverts any changes to DEPS file.
1407 self.source_control.CheckoutFileAtRevision( 1405 source_control.CheckoutFileAtRevision(
1408 bisect_utils.FILE_DEPS, git_revision, cwd=self.src_cwd) 1406 bisect_utils.FILE_DEPS, git_revision, cwd=self.src_cwd)
1409 1407
1410 bot_name, build_timeout = GetBuilderNameAndBuildTime( 1408 bot_name, build_timeout = GetBuilderNameAndBuildTime(
1411 self.opts.target_platform, self.opts.target_arch) 1409 self.opts.target_platform, self.opts.target_arch)
1412 target_file = None 1410 target_file = None
1413 try: 1411 try:
1414 # Execute try job request to build revision with patch. 1412 # Execute try job request to build revision with patch.
1415 _BuilderTryjob(git_revision, bot_name, build_request_id, patch) 1413 _BuilderTryjob(git_revision, bot_name, build_request_id, patch)
1416 target_file, error_msg = _WaitUntilBuildIsReady( 1414 target_file, error_msg = _WaitUntilBuildIsReady(
1417 fetch_build, bot_name, self.opts.builder_host, 1415 fetch_build, bot_name, self.opts.builder_host,
(...skipping 26 matching lines...) Expand all
1444 1442
1445 Returns: 1443 Returns:
1446 Updated DEPS content as string if deps key is found, otherwise None. 1444 Updated DEPS content as string if deps key is found, otherwise None.
1447 """ 1445 """
1448 # Check whether the depot and revision pattern in DEPS file vars 1446 # Check whether the depot and revision pattern in DEPS file vars
1449 # e.g. for webkit the format is "webkit_revision": "12345". 1447 # e.g. for webkit the format is "webkit_revision": "12345".
1450 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key, 1448 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key,
1451 re.MULTILINE) 1449 re.MULTILINE)
1452 new_data = None 1450 new_data = None
1453 if re.search(deps_revision, deps_contents): 1451 if re.search(deps_revision, deps_contents):
1454 commit_position = self.source_control.GetCommitPosition( 1452 commit_position = source_control.GetCommitPosition(
1455 git_revision, self.depot_registry.GetDepotDir(depot)) 1453 git_revision, self.depot_registry.GetDepotDir(depot))
1456 if not commit_position: 1454 if not commit_position:
1457 print 'Could not determine commit position for %s' % git_revision 1455 print 'Could not determine commit position for %s' % git_revision
1458 return None 1456 return None
1459 # Update the revision information for the given depot 1457 # Update the revision information for the given depot
1460 new_data = re.sub(deps_revision, str(commit_position), deps_contents) 1458 new_data = re.sub(deps_revision, str(commit_position), deps_contents)
1461 else: 1459 else:
1462 # Check whether the depot and revision pattern in DEPS file vars 1460 # Check whether the depot and revision pattern in DEPS file vars
1463 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..". 1461 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..".
1464 deps_revision = re.compile( 1462 deps_revision = re.compile(
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
1535 raise RuntimeError('DEPS file does not exists.[%s]' % deps_file_path) 1533 raise RuntimeError('DEPS file does not exists.[%s]' % deps_file_path)
1536 # Get current chromium revision (git hash). 1534 # Get current chromium revision (git hash).
1537 cmd = ['rev-parse', 'HEAD'] 1535 cmd = ['rev-parse', 'HEAD']
1538 chromium_sha = bisect_utils.CheckRunGit(cmd).strip() 1536 chromium_sha = bisect_utils.CheckRunGit(cmd).strip()
1539 if not chromium_sha: 1537 if not chromium_sha:
1540 raise RuntimeError('Failed to determine Chromium revision for %s' % 1538 raise RuntimeError('Failed to determine Chromium revision for %s' %
1541 revision) 1539 revision)
1542 if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or 1540 if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or
1543 'v8' in DEPOT_DEPS_NAME[depot]['from']): 1541 'v8' in DEPOT_DEPS_NAME[depot]['from']):
1544 # Checkout DEPS file for the current chromium revision. 1542 # Checkout DEPS file for the current chromium revision.
1545 if self.source_control.CheckoutFileAtRevision( 1543 if source_control.CheckoutFileAtRevision(
1546 bisect_utils.FILE_DEPS, chromium_sha, cwd=self.src_cwd): 1544 bisect_utils.FILE_DEPS, chromium_sha, cwd=self.src_cwd):
1547 if self.UpdateDeps(revision, depot, deps_file_path): 1545 if self.UpdateDeps(revision, depot, deps_file_path):
1548 diff_command = [ 1546 diff_command = [
1549 'diff', 1547 'diff',
1550 '--src-prefix=', 1548 '--src-prefix=',
1551 '--dst-prefix=', 1549 '--dst-prefix=',
1552 '--no-ext-diff', 1550 '--no-ext-diff',
1553 bisect_utils.FILE_DEPS, 1551 bisect_utils.FILE_DEPS,
1554 ] 1552 ]
1555 diff_text = bisect_utils.CheckRunGit(diff_command, cwd=self.src_cwd) 1553 diff_text = bisect_utils.CheckRunGit(diff_command, cwd=self.src_cwd)
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1610 Then until crrev.com/276628 *both* (android-chromium-testshell and 1608 Then until crrev.com/276628 *both* (android-chromium-testshell and
1611 android-chrome-shell) work. After that rev 276628 *only* 1609 android-chrome-shell) work. After that rev 276628 *only*
1612 android-chrome-shell works. The bisect_perf_regression.py script should 1610 android-chrome-shell works. The bisect_perf_regression.py script should
1613 handle these cases and set appropriate browser type based on revision. 1611 handle these cases and set appropriate browser type based on revision.
1614 """ 1612 """
1615 if self.opts.target_platform in ['android']: 1613 if self.opts.target_platform in ['android']:
1616 # When its a third_party depot, get the chromium revision. 1614 # When its a third_party depot, get the chromium revision.
1617 if depot != 'chromium': 1615 if depot != 'chromium':
1618 revision = bisect_utils.CheckRunGit( 1616 revision = bisect_utils.CheckRunGit(
1619 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip() 1617 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip()
1620 commit_position = self.source_control.GetCommitPosition(revision, 1618 commit_position = source_control.GetCommitPosition(revision,
1621 cwd=self.src_cwd) 1619 cwd=self.src_cwd)
1622 if not commit_position: 1620 if not commit_position:
1623 return command_to_run 1621 return command_to_run
1624 cmd_re = re.compile('--browser=(?P<browser_type>\S+)') 1622 cmd_re = re.compile('--browser=(?P<browser_type>\S+)')
1625 matches = cmd_re.search(command_to_run) 1623 matches = cmd_re.search(command_to_run)
1626 if bisect_utils.IsStringInt(commit_position) and matches: 1624 if bisect_utils.IsStringInt(commit_position) and matches:
1627 cmd_browser = matches.group('browser_type') 1625 cmd_browser = matches.group('browser_type')
1628 if commit_position <= 274857 and cmd_browser == 'android-chrome-shell': 1626 if commit_position <= 274857 and cmd_browser == 'android-chrome-shell':
1629 return command_to_run.replace(cmd_browser, 1627 return command_to_run.replace(cmd_browser,
1630 'android-chromium-testshell') 1628 'android-chromium-testshell')
1631 elif (commit_position >= 276628 and 1629 elif (commit_position >= 276628 and
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
1795 """ 1793 """
1796 revisions_to_sync = [[depot, revision]] 1794 revisions_to_sync = [[depot, revision]]
1797 1795
1798 is_base = ((depot == 'chromium') or (depot == 'cros') or 1796 is_base = ((depot == 'chromium') or (depot == 'cros') or
1799 (depot == 'android-chrome')) 1797 (depot == 'android-chrome'))
1800 1798
1801 # Some SVN depots were split into multiple git depots, so we need to 1799 # Some SVN depots were split into multiple git depots, so we need to
1802 # figure out for each mirror which git revision to grab. There's no 1800 # figure out for each mirror which git revision to grab. There's no
1803 # guarantee that the SVN revision will exist for each of the dependent 1801 # guarantee that the SVN revision will exist for each of the dependent
1804 # depots, so we have to grep the git logs and grab the next earlier one. 1802 # depots, so we have to grep the git logs and grab the next earlier one.
1805 if (not is_base 1803 if not is_base and DEPOT_DEPS_NAME[depot]['depends']:
1806 and DEPOT_DEPS_NAME[depot]['depends'] 1804 commit_position = source_control.GetCommitPosition(revision)
1807 and self.source_control.IsGit()):
1808 commit_position = self.source_control.GetCommitPosition(revision)
1809 1805
1810 for d in DEPOT_DEPS_NAME[depot]['depends']: 1806 for d in DEPOT_DEPS_NAME[depot]['depends']:
1811 self.depot_registry.ChangeToDepotDir(d) 1807 self.depot_registry.ChangeToDepotDir(d)
1812 1808
1813 dependant_rev = self.source_control.ResolveToRevision( 1809 dependant_rev = source_control.ResolveToRevision(
1814 commit_position, d, DEPOT_DEPS_NAME, -1000) 1810 commit_position, d, DEPOT_DEPS_NAME, -1000)
1815 1811
1816 if dependant_rev: 1812 if dependant_rev:
1817 revisions_to_sync.append([d, dependant_rev]) 1813 revisions_to_sync.append([d, dependant_rev])
1818 1814
1819 num_resolved = len(revisions_to_sync) 1815 num_resolved = len(revisions_to_sync)
1820 num_needed = len(DEPOT_DEPS_NAME[depot]['depends']) 1816 num_needed = len(DEPOT_DEPS_NAME[depot]['depends'])
1821 1817
1822 self.depot_registry.ChangeToDepotDir(depot) 1818 self.depot_registry.ChangeToDepotDir(depot)
1823 1819
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1890 if not builder.SetupAndroidBuildEnvironment(self.opts, 1886 if not builder.SetupAndroidBuildEnvironment(self.opts,
1891 path_to_src=self.src_cwd): 1887 path_to_src=self.src_cwd):
1892 return False 1888 return False
1893 1889
1894 if depot == 'cros': 1890 if depot == 'cros':
1895 return self.CreateCrosChroot() 1891 return self.CreateCrosChroot()
1896 else: 1892 else:
1897 return self.RunGClientHooks() 1893 return self.RunGClientHooks()
1898 return True 1894 return True
1899 1895
1900 def ShouldSkipRevision(self, depot, revision): 1896 @staticmethod
1897 def ShouldSkipRevision(depot, revision):
1901 """Checks whether a particular revision can be safely skipped. 1898 """Checks whether a particular revision can be safely skipped.
1902 1899
1903 Some commits can be safely skipped (such as a DEPS roll), since the tool 1900 Some commits can be safely skipped (such as a DEPS roll), since the tool
1904 is git based those changes would have no effect. 1901 is git based those changes would have no effect.
1905 1902
1906 Args: 1903 Args:
1907 depot: The depot being bisected. 1904 depot: The depot being bisected.
1908 revision: Current revision we're synced to. 1905 revision: Current revision we're synced to.
1909 1906
1910 Returns: 1907 Returns:
1911 True if we should skip building/testing this revision. 1908 True if we should skip building/testing this revision.
1912 """ 1909 """
1913 if depot == 'chromium': 1910 if depot == 'chromium':
1914 if self.source_control.IsGit(): 1911 cmd = ['diff-tree', '--no-commit-id', '--name-only', '-r', revision]
1915 cmd = ['diff-tree', '--no-commit-id', '--name-only', '-r', revision] 1912 output = bisect_utils.CheckRunGit(cmd)
1916 output = bisect_utils.CheckRunGit(cmd)
1917 1913
1918 files = output.splitlines() 1914 files = output.splitlines()
1919 1915
1920 if len(files) == 1 and files[0] == 'DEPS': 1916 if len(files) == 1 and files[0] == 'DEPS':
1921 return True 1917 return True
1922 1918
1923 return False 1919 return False
1924 1920
1925 def RunTest(self, revision, depot, command, metric, skippable=False): 1921 def RunTest(self, revision, depot, command, metric, skippable=False):
1926 """Performs a full sync/build/run of the specified revision. 1922 """Performs a full sync/build/run of the specified revision.
1927 1923
1928 Args: 1924 Args:
1929 revision: The revision to sync to. 1925 revision: The revision to sync to.
1930 depot: The depot that's being used at the moment (src, webkit, etc.) 1926 depot: The depot that's being used at the moment (src, webkit, etc.)
1931 command: The command to execute the performance test. 1927 command: The command to execute the performance test.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
2014 2010
2015 if sync_client: 2011 if sync_client:
2016 self.PerformPreBuildCleanup() 2012 self.PerformPreBuildCleanup()
2017 2013
2018 # When using gclient to sync, you need to specify the depot you 2014 # When using gclient to sync, you need to specify the depot you
2019 # want so that all the dependencies sync properly as well. 2015 # want so that all the dependencies sync properly as well.
2020 # i.e. gclient sync src@<SHA1> 2016 # i.e. gclient sync src@<SHA1>
2021 if sync_client == 'gclient': 2017 if sync_client == 'gclient':
2022 revision = '%s@%s' % (DEPOT_DEPS_NAME[depot]['src'], revision) 2018 revision = '%s@%s' % (DEPOT_DEPS_NAME[depot]['src'], revision)
2023 2019
2024 sync_success = self.source_control.SyncToRevision(revision, sync_client) 2020 sync_success = source_control.SyncToRevision(revision, sync_client)
2025 if not sync_success: 2021 if not sync_success:
2026 return False 2022 return False
2027 2023
2028 return True 2024 return True
2029 2025
2030 def _CheckIfRunPassed(self, current_value, known_good_value, known_bad_value): 2026 def _CheckIfRunPassed(self, current_value, known_good_value, known_bad_value):
2031 """Given known good and bad values, decide if the current_value passed 2027 """Given known good and bad values, decide if the current_value passed
2032 or failed. 2028 or failed.
2033 2029
2034 Args: 2030 Args:
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
2212 good_svn_revision: Last known good svn revision. 2208 good_svn_revision: Last known good svn revision.
2213 2209
2214 Returns: 2210 Returns:
2215 A tuple with the new bad and good revisions. 2211 A tuple with the new bad and good revisions.
2216 """ 2212 """
2217 # DONOT perform nudge because at revision 291563 .DEPS.git was removed 2213 # DONOT perform nudge because at revision 291563 .DEPS.git was removed
2218 # and source contain only DEPS file for dependency changes. 2214 # and source contain only DEPS file for dependency changes.
2219 if good_svn_revision >= 291563: 2215 if good_svn_revision >= 291563:
2220 return (bad_revision, good_revision) 2216 return (bad_revision, good_revision)
2221 2217
2222 if self.source_control.IsGit() and self.opts.target_platform == 'chromium': 2218 if self.opts.target_platform == 'chromium':
2223 changes_to_deps = self.source_control.QueryFileRevisionHistory( 2219 changes_to_deps = source_control.QueryFileRevisionHistory(
2224 bisect_utils.FILE_DEPS, good_revision, bad_revision) 2220 bisect_utils.FILE_DEPS, good_revision, bad_revision)
2225 2221
2226 if changes_to_deps: 2222 if changes_to_deps:
2227 # DEPS file was changed, search from the oldest change to DEPS file to 2223 # DEPS file was changed, search from the oldest change to DEPS file to
2228 # bad_revision to see if there are matching .DEPS.git changes. 2224 # bad_revision to see if there are matching .DEPS.git changes.
2229 oldest_deps_change = changes_to_deps[-1] 2225 oldest_deps_change = changes_to_deps[-1]
2230 changes_to_gitdeps = self.source_control.QueryFileRevisionHistory( 2226 changes_to_gitdeps = source_control.QueryFileRevisionHistory(
2231 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) 2227 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision)
2232 2228
2233 if len(changes_to_deps) != len(changes_to_gitdeps): 2229 if len(changes_to_deps) != len(changes_to_gitdeps):
2234 # Grab the timestamp of the last DEPS change 2230 # Grab the timestamp of the last DEPS change
2235 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] 2231 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]]
2236 output = bisect_utils.CheckRunGit(cmd) 2232 output = bisect_utils.CheckRunGit(cmd)
2237 commit_time = int(output) 2233 commit_time = int(output)
2238 2234
2239 # Try looking for a commit that touches the .DEPS.git file in the 2235 # Try looking for a commit that touches the .DEPS.git file in the
2240 # next 15 minutes after the DEPS file change. 2236 # next 15 minutes after the DEPS file change.
(...skipping 15 matching lines...) Expand all
2256 self, target_depot, good_revision, bad_revision): 2252 self, target_depot, good_revision, bad_revision):
2257 """Checks that |good_revision| is an earlier revision than |bad_revision|. 2253 """Checks that |good_revision| is an earlier revision than |bad_revision|.
2258 2254
2259 Args: 2255 Args:
2260 good_revision: Number/tag of the known good revision. 2256 good_revision: Number/tag of the known good revision.
2261 bad_revision: Number/tag of the known bad revision. 2257 bad_revision: Number/tag of the known bad revision.
2262 2258
2263 Returns: 2259 Returns:
2264 True if the revisions are in the proper order (good earlier than bad). 2260 True if the revisions are in the proper order (good earlier than bad).
2265 """ 2261 """
2266 if self.source_control.IsGit() and target_depot != 'cros': 2262 if target_depot != 'cros':
2267 cwd = self.depot_registry.GetDepotDir(target_depot) 2263 cwd = self.depot_registry.GetDepotDir(target_depot)
2268 good_position = self.source_control.GetCommitPosition(good_revision, cwd) 2264 good_position = source_control.GetCommitPosition(good_revision, cwd)
2269 bad_position = self.source_control.GetCommitPosition(bad_revision, cwd) 2265 bad_position = source_control.GetCommitPosition(bad_revision, cwd)
2270 else: 2266 else:
2271 # CrOS and SVN use integers. 2267 # CrOS and SVN use integers.
2272 good_position = int(good_revision) 2268 good_position = int(good_revision)
2273 bad_position = int(bad_revision) 2269 bad_position = int(bad_revision)
2274 2270
2275 return good_position <= bad_position 2271 return good_position <= bad_position
2276 2272
2277 def CanPerformBisect(self, good_revision, bad_revision): 2273 def CanPerformBisect(self, good_revision, bad_revision):
2278 """Checks whether a given revision is bisectable. 2274 """Checks whether a given revision is bisectable.
2279 2275
2280 Checks for following: 2276 Checks for following:
2281 1. Non-bisectable revsions for android bots (refer to crbug.com/385324). 2277 1. Non-bisectable revsions for android bots (refer to crbug.com/385324).
2282 2. Non-bisectable revsions for Windows bots (refer to crbug.com/405274). 2278 2. Non-bisectable revsions for Windows bots (refer to crbug.com/405274).
2283 2279
2284 Args: 2280 Args:
2285 good_revision: Known good revision. 2281 good_revision: Known good revision.
2286 bad_revision: Known bad revision. 2282 bad_revision: Known bad revision.
2287 2283
2288 Returns: 2284 Returns:
2289 A dictionary indicating the result. If revision is not bisectable, 2285 A dictionary indicating the result. If revision is not bisectable,
2290 this will contain the field "error", otherwise None. 2286 this will contain the field "error", otherwise None.
2291 """ 2287 """
2292 if self.opts.target_platform == 'android': 2288 if self.opts.target_platform == 'android':
2293 good_revision = self.source_control.GetCommitPosition(good_revision) 2289 good_revision = source_control.GetCommitPosition(good_revision)
2294 if (bisect_utils.IsStringInt(good_revision) 2290 if (bisect_utils.IsStringInt(good_revision)
2295 and good_revision < 265549): 2291 and good_revision < 265549):
2296 return {'error': ( 2292 return {'error': (
2297 'Bisect cannot continue for the given revision range.\n' 2293 'Bisect cannot continue for the given revision range.\n'
2298 'It is impossible to bisect Android regressions ' 2294 'It is impossible to bisect Android regressions '
2299 'prior to r265549, which allows the bisect bot to ' 2295 'prior to r265549, which allows the bisect bot to '
2300 'rely on Telemetry to do apk installation of the most recently ' 2296 'rely on Telemetry to do apk installation of the most recently '
2301 'built local ChromeShell(refer to crbug.com/385324).\n' 2297 'built local ChromeShell(refer to crbug.com/385324).\n'
2302 'Please try bisecting revisions greater than or equal to r265549.')} 2298 'Please try bisecting revisions greater than or equal to r265549.')}
2303 2299
2304 if bisect_utils.IsWindowsHost(): 2300 if bisect_utils.IsWindowsHost():
2305 good_revision = self.source_control.GetCommitPosition(good_revision) 2301 good_revision = source_control.GetCommitPosition(good_revision)
2306 bad_revision = self.source_control.GetCommitPosition(bad_revision) 2302 bad_revision = source_control.GetCommitPosition(bad_revision)
2307 if (bisect_utils.IsStringInt(good_revision) and 2303 if (bisect_utils.IsStringInt(good_revision) and
2308 bisect_utils.IsStringInt(bad_revision)): 2304 bisect_utils.IsStringInt(bad_revision)):
2309 if (289987 <= good_revision < 290716 or 2305 if (289987 <= good_revision < 290716 or
2310 289987 <= bad_revision < 290716): 2306 289987 <= bad_revision < 290716):
2311 return {'error': ('Oops! Revision between r289987 and r290716 are ' 2307 return {'error': ('Oops! Revision between r289987 and r290716 are '
2312 'marked as dead zone for Windows due to ' 2308 'marked as dead zone for Windows due to '
2313 'crbug.com/405274. Please try another range.')} 2309 'crbug.com/405274. Please try another range.')}
2314 2310
2315 return None 2311 return None
2316 2312
2317 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): 2313 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric):
2318 """Given known good and bad revisions, run a binary search on all 2314 """Given known good and bad revisions, run a binary search on all
2319 intermediate revisions to determine the CL where the performance regression 2315 intermediate revisions to determine the CL where the performance regression
2320 occurred. 2316 occurred.
2321 2317
2322 Args: 2318 Args:
2323 command_to_run: Specify the command to execute the performance test. 2319 command_to_run: Specify the command to execute the performance test.
2324 good_revision: Number/tag of the known good revision. 2320 good_revision: Number/tag of the known good revision.
2325 bad_revision: Number/tag of the known bad revision. 2321 bad_revision: Number/tag of the known bad revision.
2326 metric: The performance metric to monitor. 2322 metric: The performance metric to monitor.
2327 2323
2328 Returns: 2324 Returns:
2329 A BisectResults object. 2325 A BisectResults object.
2330 """ 2326 """
2331 results = BisectResults(self.depot_registry, self.source_control) 2327 results = BisectResults(self.depot_registry)
2332 2328
2333 # Choose depot to bisect first 2329 # Choose depot to bisect first
2334 target_depot = 'chromium' 2330 target_depot = 'chromium'
2335 if self.opts.target_platform == 'cros': 2331 if self.opts.target_platform == 'cros':
2336 target_depot = 'cros' 2332 target_depot = 'cros'
2337 elif self.opts.target_platform == 'android-chrome': 2333 elif self.opts.target_platform == 'android-chrome':
2338 target_depot = 'android-chrome' 2334 target_depot = 'android-chrome'
2339 2335
2340 cwd = os.getcwd() 2336 cwd = os.getcwd()
2341 self.depot_registry.ChangeToDepotDir(target_depot) 2337 self.depot_registry.ChangeToDepotDir(target_depot)
2342 2338
2343 # If they passed SVN revisions, we can try match them to git SHA1 hashes. 2339 # If they passed SVN revisions, we can try match them to git SHA1 hashes.
2344 bad_revision = self.source_control.ResolveToRevision( 2340 bad_revision = source_control.ResolveToRevision(
2345 bad_revision_in, target_depot, DEPOT_DEPS_NAME, 100) 2341 bad_revision_in, target_depot, DEPOT_DEPS_NAME, 100)
2346 good_revision = self.source_control.ResolveToRevision( 2342 good_revision = source_control.ResolveToRevision(
2347 good_revision_in, target_depot, DEPOT_DEPS_NAME, -100) 2343 good_revision_in, target_depot, DEPOT_DEPS_NAME, -100)
2348 2344
2349 os.chdir(cwd) 2345 os.chdir(cwd)
2350 if bad_revision is None: 2346 if bad_revision is None:
2351 results.error = 'Couldn\'t resolve [%s] to SHA1.' % bad_revision_in 2347 results.error = 'Couldn\'t resolve [%s] to SHA1.' % bad_revision_in
2352 return results 2348 return results
2353 2349
2354 if good_revision is None: 2350 if good_revision is None:
2355 results.error = 'Couldn\'t resolve [%s] to SHA1.' % good_revision_in 2351 results.error = 'Couldn\'t resolve [%s] to SHA1.' % good_revision_in
2356 return results 2352 return results
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
2602 level = 'high' 2598 level = 'high'
2603 else: 2599 else:
2604 level = 'low' 2600 level = 'low'
2605 warning = ' and warnings' 2601 warning = ' and warnings'
2606 if not self.warnings: 2602 if not self.warnings:
2607 warning = '' 2603 warning = ''
2608 return confidence_status % {'level': level, 'warning': warning} 2604 return confidence_status % {'level': level, 'warning': warning}
2609 2605
2610 def _GetViewVCLinkFromDepotAndHash(self, revision_id, depot): 2606 def _GetViewVCLinkFromDepotAndHash(self, revision_id, depot):
2611 """Gets link to the repository browser.""" 2607 """Gets link to the repository browser."""
2612 info = self.source_control.QueryRevisionInfo(revision_id, 2608 info = source_control.QueryRevisionInfo(revision_id,
2613 self.depot_registry.GetDepotDir(depot)) 2609 self.depot_registry.GetDepotDir(depot))
2614 if depot and DEPOT_DEPS_NAME[depot].has_key('viewvc'): 2610 if depot and DEPOT_DEPS_NAME[depot].has_key('viewvc'):
2615 try: 2611 try:
2616 # Format is "git-svn-id: svn://....@123456 <other data>" 2612 # Format is "git-svn-id: svn://....@123456 <other data>"
2617 svn_line = [i for i in info['body'].splitlines() if 'git-svn-id:' in i] 2613 svn_line = [i for i in info['body'].splitlines() if 'git-svn-id:' in i]
2618 svn_revision = svn_line[0].split('@') 2614 svn_revision = svn_line[0].split('@')
2619 svn_revision = svn_revision[1].split(' ')[0] 2615 svn_revision = svn_revision[1].split(' ')[0]
2620 return DEPOT_DEPS_NAME[depot]['viewvc'] + svn_revision 2616 return DEPOT_DEPS_NAME[depot]['viewvc'] + svn_revision
2621 except IndexError: 2617 except IndexError:
2622 return '' 2618 return ''
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2711 2707
2712 # If confidence is too low, don't bother outputting good/bad. 2708 # If confidence is too low, don't bother outputting good/bad.
2713 if not confidence: 2709 if not confidence:
2714 state_str = '' 2710 state_str = ''
2715 state_str = state_str.center(13, ' ') 2711 state_str = state_str.center(13, ' ')
2716 2712
2717 cl_link = self._GetViewVCLinkFromDepotAndHash(current_id, 2713 cl_link = self._GetViewVCLinkFromDepotAndHash(current_id,
2718 current_data['depot']) 2714 current_data['depot'])
2719 if not cl_link: 2715 if not cl_link:
2720 cl_link = current_id 2716 cl_link = current_id
2721 commit_position = self.source_control.GetCommitPosition( 2717 commit_position = source_control.GetCommitPosition(
2722 current_id, self.depot_registry.GetDepotDir(current_data['depot'])) 2718 current_id, self.depot_registry.GetDepotDir(current_data['depot']))
2723 commit_position = str(commit_position) 2719 commit_position = str(commit_position)
2724 if not commit_position: 2720 if not commit_position:
2725 commit_position = '' 2721 commit_position = ''
2726 self._PrintTestedCommitsEntry(current_data, commit_position, cl_link, 2722 self._PrintTestedCommitsEntry(current_data, commit_position, cl_link,
2727 state_str) 2723 state_str)
2728 2724
2729 def _PrintReproSteps(self): 2725 def _PrintReproSteps(self):
2730 """Prints out a section of the results explaining how to run the test. 2726 """Prints out a section of the results explaining how to run the test.
2731 2727
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after
3219 bisect_utils.CreateBisectDirectoryAndSetupDepot(opts, custom_deps) 3215 bisect_utils.CreateBisectDirectoryAndSetupDepot(opts, custom_deps)
3220 3216
3221 os.chdir(os.path.join(os.getcwd(), 'src')) 3217 os.chdir(os.path.join(os.getcwd(), 'src'))
3222 3218
3223 if not RemoveBuildFiles(opts.target_build_type): 3219 if not RemoveBuildFiles(opts.target_build_type):
3224 raise RuntimeError('Something went wrong removing the build files.') 3220 raise RuntimeError('Something went wrong removing the build files.')
3225 3221
3226 if not _IsPlatformSupported(): 3222 if not _IsPlatformSupported():
3227 raise RuntimeError('Sorry, this platform isn\'t supported yet.') 3223 raise RuntimeError('Sorry, this platform isn\'t supported yet.')
3228 3224
3229 # Check what source control method is being used, and create a 3225 if not source_control.IsInGitRepository():
3230 # SourceControl object if possible.
3231 source_control = source_control_module.DetermineAndCreateSourceControl(opts)
3232
3233 if not source_control:
3234 raise RuntimeError( 3226 raise RuntimeError(
3235 'Sorry, only the git workflow is supported at the moment.') 3227 'Sorry, only the git workflow is supported at the moment.')
3236 3228
3237 # gClient sync seems to fail if you're not in master branch. 3229 # gClient sync seems to fail if you're not in master branch.
3238 if (not source_control.IsInProperBranch() and 3230 if (not source_control.IsInProperBranch() and
3239 not opts.debug_ignore_sync and 3231 not opts.debug_ignore_sync and
3240 not opts.working_directory): 3232 not opts.working_directory):
3241 raise RuntimeError('You must switch to master branch to run bisection.') 3233 raise RuntimeError('You must switch to master branch to run bisection.')
3242 bisect_test = BisectPerformanceMetrics(source_control, opts) 3234 bisect_test = BisectPerformanceMetrics(opts)
3243 try: 3235 try:
3244 bisect_results = bisect_test.Run(opts.command, 3236 bisect_results = bisect_test.Run(opts.command,
3245 opts.bad_revision, 3237 opts.bad_revision,
3246 opts.good_revision, 3238 opts.good_revision,
3247 opts.metric) 3239 opts.metric)
3248 if bisect_results.error: 3240 if bisect_results.error:
3249 raise RuntimeError(bisect_results.error) 3241 raise RuntimeError(bisect_results.error)
3250 bisect_test.FormatAndPrintResults(bisect_results) 3242 bisect_test.FormatAndPrintResults(bisect_results)
3251 return 0 3243 return 0
3252 finally: 3244 finally:
3253 bisect_test.PerformCleanup() 3245 bisect_test.PerformCleanup()
3254 except RuntimeError, e: 3246 except RuntimeError, e:
3255 if opts.output_buildbot_annotations: 3247 if opts.output_buildbot_annotations:
3256 # The perf dashboard scrapes the "results" step in order to comment on 3248 # The perf dashboard scrapes the "results" step in order to comment on
3257 # bugs. If you change this, please update the perf dashboard as well. 3249 # bugs. If you change this, please update the perf dashboard as well.
3258 bisect_utils.OutputAnnotationStepStart('Results') 3250 bisect_utils.OutputAnnotationStepStart('Results')
3259 print 'Error: %s' % e.message 3251 print 'Error: %s' % e.message
3260 if opts.output_buildbot_annotations: 3252 if opts.output_buildbot_annotations:
3261 bisect_utils.OutputAnnotationStepClosed() 3253 bisect_utils.OutputAnnotationStepClosed()
3262 return 1 3254 return 1
3263 3255
3264 3256
3265 if __name__ == '__main__': 3257 if __name__ == '__main__':
3266 sys.exit(main()) 3258 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/auto_bisect/bisect_perf_regression_test.py » ('j') | tools/auto_bisect/source_control.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698