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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 # svn: Needed for git workflow to resolve hashes to svn revisions. | 69 # svn: Needed for git workflow to resolve hashes to svn revisions. |
70 # from: Parent depot that must be bisected before this is bisected. | 70 # from: Parent depot that must be bisected before this is bisected. |
71 # deps_var: Key name in vars varible in DEPS file that has revision information. | 71 # deps_var: Key name in vars varible in DEPS file that has revision information. |
72 DEPOT_DEPS_NAME = { | 72 DEPOT_DEPS_NAME = { |
73 'chromium' : { | 73 'chromium' : { |
74 "src" : "src", | 74 "src" : "src", |
75 "recurse" : True, | 75 "recurse" : True, |
76 "depends" : None, | 76 "depends" : None, |
77 "from" : ['cros', 'android-chrome'], | 77 "from" : ['cros', 'android-chrome'], |
78 'viewvc': 'http://src.chromium.org/viewvc/chrome?view=revision&revision=', | 78 'viewvc': 'http://src.chromium.org/viewvc/chrome?view=revision&revision=', |
79 'deps_var': None | 79 'deps_var': 'chromium_rev' |
80 }, | 80 }, |
81 'webkit' : { | 81 'webkit' : { |
82 "src" : "src/third_party/WebKit", | 82 "src" : "src/third_party/WebKit", |
83 "recurse" : True, | 83 "recurse" : True, |
84 "depends" : None, | 84 "depends" : None, |
85 "from" : ['chromium'], | 85 "from" : ['chromium'], |
86 'viewvc': 'http://src.chromium.org/viewvc/blink?view=revision&revision=', | 86 'viewvc': 'http://src.chromium.org/viewvc/blink?view=revision&revision=', |
87 'deps_var': 'webkit_revision' | 87 'deps_var': 'webkit_revision' |
88 }, | 88 }, |
89 'angle' : { | 89 'angle' : { |
(...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 | 681 |
682 for t in targets: | 682 for t in targets: |
683 cmd.extend(['/Project', t]) | 683 cmd.extend(['/Project', t]) |
684 | 684 |
685 return_code = RunProcess(cmd) | 685 return_code = RunProcess(cmd) |
686 | 686 |
687 return not return_code | 687 return not return_code |
688 | 688 |
689 | 689 |
690 def WriteStringToFile(text, file_name): | 690 def WriteStringToFile(text, file_name): |
691 with open(file_name, "w") as f: | 691 try: |
692 f.write(text) | 692 with open(file_name, "w") as f: |
| 693 f.write(text) |
| 694 except IOError as e: |
| 695 raise RuntimeError('Error writing to file [%s]' % file_name ) |
693 | 696 |
694 | 697 |
695 def ReadStringFromFile(file_name): | 698 def ReadStringFromFile(file_name): |
696 with open(file_name) as f: | 699 try: |
697 return f.read() | 700 with open(file_name) as f: |
| 701 return f.read() |
| 702 except IOError as e: |
| 703 raise RuntimeError('Error reading file [%s]' % file_name ) |
698 | 704 |
699 | 705 |
700 def ChangeBackslashToSlashInPatch(diff_text): | 706 def ChangeBackslashToSlashInPatch(diff_text): |
701 """Formats file paths in the given text to unix-style paths.""" | 707 """Formats file paths in the given text to unix-style paths.""" |
702 if diff_text: | 708 if diff_text: |
703 diff_lines = diff_text.split('\n') | 709 diff_lines = diff_text.split('\n') |
704 for i in range(len(diff_lines)): | 710 for i in range(len(diff_lines)): |
705 if (diff_lines[i].startswith('--- ') or | 711 if (diff_lines[i].startswith('--- ') or |
706 diff_lines[i].startswith('+++ ')): | 712 diff_lines[i].startswith('+++ ')): |
707 diff_lines[i] = diff_lines[i].replace('\\', '/') | 713 diff_lines[i] = diff_lines[i].replace('\\', '/') |
(...skipping 25 matching lines...) Expand all Loading... |
733 if 'ninja' in os.getenv('GYP_GENERATORS'): | 739 if 'ninja' in os.getenv('GYP_GENERATORS'): |
734 opts.build_preference = 'ninja' | 740 opts.build_preference = 'ninja' |
735 else: | 741 else: |
736 opts.build_preference = 'make' | 742 opts.build_preference = 'make' |
737 | 743 |
738 SetBuildSystemDefault(opts.build_preference) | 744 SetBuildSystemDefault(opts.build_preference) |
739 | 745 |
740 if not bisect_utils.SetupPlatformBuildEnvironment(opts): | 746 if not bisect_utils.SetupPlatformBuildEnvironment(opts): |
741 raise RuntimeError('Failed to set platform environment.') | 747 raise RuntimeError('Failed to set platform environment.') |
742 | 748 |
743 bisect_utils.RunGClient(['runhooks']) | |
744 | |
745 @staticmethod | 749 @staticmethod |
746 def FromOpts(opts): | 750 def FromOpts(opts): |
747 builder = None | 751 builder = None |
748 if opts.target_platform == 'cros': | 752 if opts.target_platform == 'cros': |
749 builder = CrosBuilder(opts) | 753 builder = CrosBuilder(opts) |
750 elif opts.target_platform == 'android': | 754 elif opts.target_platform == 'android': |
751 builder = AndroidBuilder(opts) | 755 builder = AndroidBuilder(opts) |
752 elif opts.target_platform == 'android-chrome': | 756 elif opts.target_platform == 'android-chrome': |
753 builder = AndroidChromeBuilder(opts) | 757 builder = AndroidChromeBuilder(opts) |
754 else: | 758 else: |
(...skipping 605 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1360 | 1364 |
1361 bleeding_edge_revision = None | 1365 bleeding_edge_revision = None |
1362 | 1366 |
1363 for c in commits: | 1367 for c in commits: |
1364 bleeding_edge_revision = self._GetV8BleedingEdgeFromV8TrunkIfMappable(c) | 1368 bleeding_edge_revision = self._GetV8BleedingEdgeFromV8TrunkIfMappable(c) |
1365 if bleeding_edge_revision: | 1369 if bleeding_edge_revision: |
1366 break | 1370 break |
1367 | 1371 |
1368 return bleeding_edge_revision | 1372 return bleeding_edge_revision |
1369 | 1373 |
1370 def Get3rdPartyRevisionsFromCurrentRevision(self, depot, revision): | 1374 def _ParseRevisionsFromDEPSFileManually(self, deps_file_contents): |
1371 """Parses the DEPS file to determine WebKit/v8/etc... versions. | 1375 """Manually parses the vars section of the DEPS file to determine |
| 1376 chromium/blink/etc... revisions. |
1372 | 1377 |
1373 Returns: | 1378 Returns: |
1374 A dict in the format {depot:revision} if successful, otherwise None. | 1379 A dict in the format {depot:revision} if successful, otherwise None. |
1375 """ | 1380 """ |
1376 cwd = os.getcwd() | 1381 # We'll parse the "vars" section of the DEPS file. |
1377 self.ChangeToDepotWorkingDirectory(depot) | 1382 rxp = re.compile('vars = {(?P<vars_body>[^}]+)', re.MULTILINE) |
| 1383 re_results = rxp.search(deps_file_contents) |
| 1384 locals = {} |
1378 | 1385 |
1379 results = {} | 1386 if not re_results: |
| 1387 return None |
1380 | 1388 |
1381 if depot == 'chromium' or depot == 'android-chrome': | 1389 # We should be left with a series of entries in the vars component of |
| 1390 # the DEPS file with the following format: |
| 1391 # 'depot_name': 'revision', |
| 1392 vars_body = re_results.group('vars_body') |
| 1393 rxp = re.compile("'(?P<depot_body>[\w_-]+)':[\s]+'(?P<rev_body>[\w@]+)'", |
| 1394 re.MULTILINE) |
| 1395 re_results = rxp.findall(vars_body) |
| 1396 |
| 1397 return dict(re_results) |
| 1398 |
| 1399 def _ParseRevisionsFromDEPSFile(self, depot): |
| 1400 """Parses the local DEPS file to determine blink/skia/v8 revisions which may |
| 1401 be needed if the bisect recurses into those depots later. |
| 1402 |
| 1403 Args: |
| 1404 depot: Depot being bisected. |
| 1405 |
| 1406 Returns: |
| 1407 A dict in the format {depot:revision} if successful, otherwise None. |
| 1408 """ |
| 1409 try: |
1382 locals = {'Var': lambda _: locals["vars"][_], | 1410 locals = {'Var': lambda _: locals["vars"][_], |
1383 'From': lambda *args: None} | 1411 'From': lambda *args: None} |
1384 execfile(bisect_utils.FILE_DEPS_GIT, {}, locals) | 1412 execfile(bisect_utils.FILE_DEPS_GIT, {}, locals) |
1385 | 1413 locals = locals['deps'] |
1386 os.chdir(cwd) | 1414 results = {} |
1387 | 1415 |
1388 rxp = re.compile(".git@(?P<revision>[a-fA-F0-9]+)") | 1416 rxp = re.compile(".git@(?P<revision>[a-fA-F0-9]+)") |
1389 | 1417 |
1390 for d in DEPOT_NAMES: | 1418 for d in DEPOT_NAMES: |
1391 if DEPOT_DEPS_NAME[d].has_key('platform'): | 1419 if DEPOT_DEPS_NAME[d].has_key('platform'): |
1392 if DEPOT_DEPS_NAME[d]['platform'] != os.name: | 1420 if DEPOT_DEPS_NAME[d]['platform'] != os.name: |
1393 continue | 1421 continue |
1394 | 1422 |
1395 if (DEPOT_DEPS_NAME[d]['recurse'] and | 1423 if (DEPOT_DEPS_NAME[d]['recurse'] and |
1396 depot in DEPOT_DEPS_NAME[d]['from']): | 1424 depot in DEPOT_DEPS_NAME[d]['from']): |
1397 if (locals['deps'].has_key(DEPOT_DEPS_NAME[d]['src']) or | 1425 if (locals.has_key(DEPOT_DEPS_NAME[d]['src']) or |
1398 locals['deps'].has_key(DEPOT_DEPS_NAME[d]['src_old'])): | 1426 locals.has_key(DEPOT_DEPS_NAME[d]['src_old'])): |
1399 if locals['deps'].has_key(DEPOT_DEPS_NAME[d]['src']): | 1427 if locals.has_key(DEPOT_DEPS_NAME[d]['src']): |
1400 re_results = rxp.search(locals['deps'][DEPOT_DEPS_NAME[d]['src']]) | 1428 re_results = rxp.search(locals[DEPOT_DEPS_NAME[d]['src']]) |
1401 self.depot_cwd[d] = \ | 1429 self.depot_cwd[d] = \ |
1402 os.path.join(self.src_cwd, DEPOT_DEPS_NAME[d]['src'][4:]) | 1430 os.path.join(self.src_cwd, DEPOT_DEPS_NAME[d]['src'][4:]) |
1403 elif locals['deps'].has_key(DEPOT_DEPS_NAME[d]['src_old']): | 1431 elif (DEPOT_DEPS_NAME[d].has_key('src_old') and |
| 1432 locals.has_key(DEPOT_DEPS_NAME[d]['src_old'])): |
1404 re_results = \ | 1433 re_results = \ |
1405 rxp.search(locals['deps'][DEPOT_DEPS_NAME[d]['src_old']]) | 1434 rxp.search(locals[DEPOT_DEPS_NAME[d]['src_old']]) |
1406 self.depot_cwd[d] = \ | 1435 self.depot_cwd[d] = \ |
1407 os.path.join(self.src_cwd, DEPOT_DEPS_NAME[d]['src_old'][4:]) | 1436 os.path.join(self.src_cwd, DEPOT_DEPS_NAME[d]['src_old'][4:]) |
1408 | 1437 |
1409 if re_results: | 1438 if re_results: |
1410 results[d] = re_results.group('revision') | 1439 results[d] = re_results.group('revision') |
1411 else: | 1440 else: |
1412 print 'Couldn\'t parse revision for %s.' % d | 1441 warning_text = ('Couldn\'t parse revision for %s while bisecting ' |
1413 print | 1442 '%s' % (d, depot)) |
1414 return None | 1443 if not warningText in self.warnings: |
| 1444 self.warnings.append(warningText) |
1415 else: | 1445 else: |
1416 print 'Couldn\'t find %s while parsing .DEPS.git.' % d | 1446 print 'Couldn\'t find %s while parsing .DEPS.git.' % d |
1417 print | 1447 print |
1418 return None | 1448 return None |
| 1449 return results |
| 1450 except ImportError: |
| 1451 deps_file_contents = ReadStringFromFile(bisect_utils.FILE_DEPS_GIT) |
| 1452 parse_results = self._ParseRevisionsFromDEPSFileManually( |
| 1453 deps_file_contents) |
| 1454 results = {} |
| 1455 for depot_name, depot_revision in parse_results.iteritems(): |
| 1456 depot_revision = depot_revision.strip('@') |
| 1457 print depot_name, depot_revision |
| 1458 for current_name, current_data in DEPOT_DEPS_NAME.iteritems(): |
| 1459 if (current_data.has_key('deps_var') and |
| 1460 current_data['deps_var'] == depot_name): |
| 1461 src_name = current_name |
| 1462 results[src_name] = depot_revision |
| 1463 break |
| 1464 return results |
| 1465 |
| 1466 def Get3rdPartyRevisionsFromCurrentRevision(self, depot, revision): |
| 1467 """Parses the DEPS file to determine WebKit/v8/etc... versions. |
| 1468 |
| 1469 Returns: |
| 1470 A dict in the format {depot:revision} if successful, otherwise None. |
| 1471 """ |
| 1472 cwd = os.getcwd() |
| 1473 self.ChangeToDepotWorkingDirectory(depot) |
| 1474 |
| 1475 results = {} |
| 1476 |
| 1477 if depot == 'chromium' or depot == 'android-chrome': |
| 1478 results = self._ParseRevisionsFromDEPSFile(depot) |
| 1479 os.chdir(cwd) |
1419 elif depot == 'cros': | 1480 elif depot == 'cros': |
1420 cmd = [CROS_SDK_PATH, '--', 'portageq-%s' % self.opts.cros_board, | 1481 cmd = [CROS_SDK_PATH, '--', 'portageq-%s' % self.opts.cros_board, |
1421 'best_visible', '/build/%s' % self.opts.cros_board, 'ebuild', | 1482 'best_visible', '/build/%s' % self.opts.cros_board, 'ebuild', |
1422 CROS_CHROMEOS_PATTERN] | 1483 CROS_CHROMEOS_PATTERN] |
1423 (output, return_code) = RunProcessAndRetrieveOutput(cmd) | 1484 (output, return_code) = RunProcessAndRetrieveOutput(cmd) |
1424 | 1485 |
1425 assert not return_code, 'An error occurred while running' \ | 1486 assert not return_code, 'An error occurred while running' \ |
1426 ' "%s"' % ' '.join(cmd) | 1487 ' "%s"' % ' '.join(cmd) |
1427 | 1488 |
1428 if len(output) > CROS_CHROMEOS_PATTERN: | 1489 if len(output) > CROS_CHROMEOS_PATTERN: |
(...skipping 2290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3719 # The perf dashboard scrapes the "results" step in order to comment on | 3780 # The perf dashboard scrapes the "results" step in order to comment on |
3720 # bugs. If you change this, please update the perf dashboard as well. | 3781 # bugs. If you change this, please update the perf dashboard as well. |
3721 bisect_utils.OutputAnnotationStepStart('Results') | 3782 bisect_utils.OutputAnnotationStepStart('Results') |
3722 print 'Error: %s' % e.message | 3783 print 'Error: %s' % e.message |
3723 if opts.output_buildbot_annotations: | 3784 if opts.output_buildbot_annotations: |
3724 bisect_utils.OutputAnnotationStepClosed() | 3785 bisect_utils.OutputAnnotationStepClosed() |
3725 return 1 | 3786 return 1 |
3726 | 3787 |
3727 if __name__ == '__main__': | 3788 if __name__ == '__main__': |
3728 sys.exit(main()) | 3789 sys.exit(main()) |
OLD | NEW |