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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 import shlex | 45 import shlex |
46 import shutil | 46 import shutil |
47 import StringIO | 47 import StringIO |
48 import sys | 48 import sys |
49 import time | 49 import time |
50 import zipfile | 50 import zipfile |
51 | 51 |
52 sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry')) | 52 sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry')) |
53 | 53 |
54 from auto_bisect import bisect_utils | 54 from auto_bisect import bisect_utils |
| 55 from auto_bisect import builder |
55 from auto_bisect import math_utils | 56 from auto_bisect import math_utils |
56 from auto_bisect import post_perf_builder_job as bisect_builder | 57 from auto_bisect import post_perf_builder_job as bisect_builder |
57 from auto_bisect import source_control as source_control_module | 58 from auto_bisect import source_control as source_control_module |
58 from auto_bisect import ttest | 59 from auto_bisect import ttest |
59 from telemetry.util import cloud_storage | 60 from telemetry.util import cloud_storage |
60 | 61 |
61 # Below is the map of "depot" names to information about each depot. Each depot | 62 # Below is the map of "depot" names to information about each depot. Each depot |
62 # is a repository, and in the process of bisecting, revision ranges in these | 63 # is a repository, and in the process of bisecting, revision ranges in these |
63 # repositories may also be bisected. | 64 # repositories may also be bisected. |
64 # | 65 # |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 'svn': 'http://skia.googlecode.com/svn/trunk/gyp', | 145 'svn': 'http://skia.googlecode.com/svn/trunk/gyp', |
145 'depends': None, | 146 'depends': None, |
146 'from': ['chromium'], | 147 'from': ['chromium'], |
147 'viewvc': 'https://code.google.com/p/skia/source/detail?r=', | 148 'viewvc': 'https://code.google.com/p/skia/source/detail?r=', |
148 'deps_var': 'None' | 149 'deps_var': 'None' |
149 } | 150 } |
150 } | 151 } |
151 | 152 |
152 DEPOT_NAMES = DEPOT_DEPS_NAME.keys() | 153 DEPOT_NAMES = DEPOT_DEPS_NAME.keys() |
153 | 154 |
154 CROS_SDK_PATH = os.path.join('..', 'cros', 'chromite', 'bin', 'cros_sdk') | |
155 CROS_CHROMEOS_PATTERN = 'chromeos-base/chromeos-chrome' | 155 CROS_CHROMEOS_PATTERN = 'chromeos-base/chromeos-chrome' |
156 CROS_TEST_KEY_PATH = os.path.join('..', 'cros', 'chromite', 'ssh_keys', | |
157 'testing_rsa') | |
158 CROS_SCRIPT_KEY_PATH = os.path.join('..', 'cros', 'src', 'scripts', | |
159 'mod_for_test_scripts', 'ssh_keys', | |
160 'testing_rsa') | |
161 | 156 |
162 # Possible return values from BisectPerformanceMetrics.SyncBuildAndRunRevision. | 157 # Possible return values from BisectPerformanceMetrics.SyncBuildAndRunRevision. |
163 BUILD_RESULT_SUCCEED = 0 | 158 BUILD_RESULT_SUCCEED = 0 |
164 BUILD_RESULT_FAIL = 1 | 159 BUILD_RESULT_FAIL = 1 |
165 BUILD_RESULT_SKIPPED = 2 | 160 BUILD_RESULT_SKIPPED = 2 |
166 | 161 |
167 # Maximum time in seconds to wait after posting build request to tryserver. | 162 # Maximum time in seconds to wait after posting build request to tryserver. |
168 # TODO: Change these values based on the actual time taken by buildbots on | 163 # TODO: Change these values based on the actual time taken by buildbots on |
169 # the tryserver. | 164 # the tryserver. |
170 MAX_MAC_BUILD_TIME = 14400 | 165 MAX_MAC_BUILD_TIME = 14400 |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 for name in zf.namelist(): | 432 for name in zf.namelist(): |
438 if verbose: | 433 if verbose: |
439 print 'Extracting %s' % name | 434 print 'Extracting %s' % name |
440 zf.extract(name, output_dir) | 435 zf.extract(name, output_dir) |
441 if bisect_utils.IsMacHost(): | 436 if bisect_utils.IsMacHost(): |
442 # Restore permission bits. | 437 # Restore permission bits. |
443 os.chmod(os.path.join(output_dir, name), | 438 os.chmod(os.path.join(output_dir, name), |
444 zf.getinfo(name).external_attr >> 16L) | 439 zf.getinfo(name).external_attr >> 16L) |
445 | 440 |
446 | 441 |
447 def SetBuildSystemDefault(build_system, use_goma, goma_dir): | |
448 """Sets up any environment variables needed to build with the specified build | |
449 system. | |
450 | |
451 Args: | |
452 build_system: A string specifying build system. Currently only 'ninja' or | |
453 'make' are supported. | |
454 """ | |
455 if build_system == 'ninja': | |
456 gyp_var = os.getenv('GYP_GENERATORS', default='') | |
457 | |
458 if not gyp_var or not 'ninja' in gyp_var: | |
459 if gyp_var: | |
460 os.environ['GYP_GENERATORS'] = gyp_var + ',ninja' | |
461 else: | |
462 os.environ['GYP_GENERATORS'] = 'ninja' | |
463 | |
464 if bisect_utils.IsWindowsHost(): | |
465 os.environ['GYP_DEFINES'] = ('component=shared_library ' | |
466 'incremental_chrome_dll=1 ' | |
467 'disable_nacl=1 fastbuild=1 ' | |
468 'chromium_win_pch=0') | |
469 | |
470 elif build_system == 'make': | |
471 os.environ['GYP_GENERATORS'] = 'make' | |
472 else: | |
473 raise RuntimeError('%s build not supported.' % build_system) | |
474 | |
475 if use_goma: | |
476 os.environ['GYP_DEFINES'] = '%s %s' % (os.getenv('GYP_DEFINES', default=''), | |
477 'use_goma=1') | |
478 if goma_dir: | |
479 os.environ['GYP_DEFINES'] += ' gomadir=%s' % goma_dir | |
480 | |
481 | |
482 def BuildWithMake(threads, targets, build_type='Release'): | |
483 cmd = ['make', 'BUILDTYPE=%s' % build_type] | |
484 | |
485 if threads: | |
486 cmd.append('-j%d' % threads) | |
487 | |
488 cmd += targets | |
489 | |
490 return_code = bisect_utils.RunProcess(cmd) | |
491 | |
492 return not return_code | |
493 | |
494 | |
495 def BuildWithNinja(threads, targets, build_type='Release'): | |
496 cmd = ['ninja', '-C', os.path.join('out', build_type)] | |
497 | |
498 if threads: | |
499 cmd.append('-j%d' % threads) | |
500 | |
501 cmd += targets | |
502 | |
503 return_code = bisect_utils.RunProcess(cmd) | |
504 | |
505 return not return_code | |
506 | |
507 | |
508 def BuildWithVisualStudio(targets, build_type='Release'): | |
509 path_to_devenv = os.path.abspath( | |
510 os.path.join(os.environ['VS100COMNTOOLS'], '..', 'IDE', 'devenv.com')) | |
511 path_to_sln = os.path.join(os.getcwd(), 'chrome', 'chrome.sln') | |
512 cmd = [path_to_devenv, '/build', build_type, path_to_sln] | |
513 | |
514 for t in targets: | |
515 cmd.extend(['/Project', t]) | |
516 | |
517 return_code = bisect_utils.RunProcess(cmd) | |
518 | |
519 return not return_code | |
520 | |
521 | |
522 def WriteStringToFile(text, file_name): | 442 def WriteStringToFile(text, file_name): |
523 try: | 443 try: |
524 with open(file_name, 'wb') as f: | 444 with open(file_name, 'wb') as f: |
525 f.write(text) | 445 f.write(text) |
526 except IOError: | 446 except IOError: |
527 raise RuntimeError('Error writing to file [%s]' % file_name ) | 447 raise RuntimeError('Error writing to file [%s]' % file_name ) |
528 | 448 |
529 | 449 |
530 def ReadStringFromFile(file_name): | 450 def ReadStringFromFile(file_name): |
531 try: | 451 try: |
532 with open(file_name) as f: | 452 with open(file_name) as f: |
533 return f.read() | 453 return f.read() |
534 except IOError: | 454 except IOError: |
535 raise RuntimeError('Error reading file [%s]' % file_name ) | 455 raise RuntimeError('Error reading file [%s]' % file_name ) |
536 | 456 |
537 | 457 |
538 def ChangeBackslashToSlashInPatch(diff_text): | 458 def ChangeBackslashToSlashInPatch(diff_text): |
539 """Formats file paths in the given text to unix-style paths.""" | 459 """Formats file paths in the given text to unix-style paths.""" |
540 if diff_text: | 460 if diff_text: |
541 diff_lines = diff_text.split('\n') | 461 diff_lines = diff_text.split('\n') |
542 for i in range(len(diff_lines)): | 462 for i in range(len(diff_lines)): |
543 if (diff_lines[i].startswith('--- ') or | 463 if (diff_lines[i].startswith('--- ') or |
544 diff_lines[i].startswith('+++ ')): | 464 diff_lines[i].startswith('+++ ')): |
545 diff_lines[i] = diff_lines[i].replace('\\', '/') | 465 diff_lines[i] = diff_lines[i].replace('\\', '/') |
546 return '\n'.join(diff_lines) | 466 return '\n'.join(diff_lines) |
547 return None | 467 return None |
548 | 468 |
549 | 469 |
550 class Builder(object): | |
551 """Builder is used by the bisect script to build relevant targets and deploy. | |
552 """ | |
553 def __init__(self, opts): | |
554 """Performs setup for building with target build system. | |
555 | |
556 Args: | |
557 opts: Options parsed from command line. | |
558 """ | |
559 if bisect_utils.IsWindowsHost(): | |
560 if not opts.build_preference: | |
561 opts.build_preference = 'msvs' | |
562 | |
563 if opts.build_preference == 'msvs': | |
564 if not os.getenv('VS100COMNTOOLS'): | |
565 raise RuntimeError( | |
566 'Path to visual studio could not be determined.') | |
567 else: | |
568 SetBuildSystemDefault(opts.build_preference, opts.use_goma, | |
569 opts.goma_dir) | |
570 else: | |
571 if not opts.build_preference: | |
572 if 'ninja' in os.getenv('GYP_GENERATORS', default=''): | |
573 opts.build_preference = 'ninja' | |
574 else: | |
575 opts.build_preference = 'make' | |
576 | |
577 SetBuildSystemDefault(opts.build_preference, opts.use_goma, opts.goma_dir) | |
578 | |
579 if not bisect_utils.SetupPlatformBuildEnvironment(opts): | |
580 raise RuntimeError('Failed to set platform environment.') | |
581 | |
582 @staticmethod | |
583 def FromOpts(opts): | |
584 builder = None | |
585 if opts.target_platform == 'cros': | |
586 builder = CrosBuilder(opts) | |
587 elif opts.target_platform == 'android': | |
588 builder = AndroidBuilder(opts) | |
589 elif opts.target_platform == 'android-chrome': | |
590 builder = AndroidChromeBuilder(opts) | |
591 else: | |
592 builder = DesktopBuilder(opts) | |
593 return builder | |
594 | |
595 def Build(self, depot, opts): | |
596 raise NotImplementedError() | |
597 | |
598 def GetBuildOutputDirectory(self, opts, src_dir=None): | |
599 """Returns the path to the build directory, relative to the checkout root. | |
600 | |
601 Assumes that the current working directory is the checkout root. | |
602 """ | |
603 src_dir = src_dir or 'src' | |
604 if opts.build_preference == 'ninja' or bisect_utils.IsLinuxHost(): | |
605 return os.path.join(src_dir, 'out') | |
606 if bisect_utils.IsMacHost(): | |
607 return os.path.join(src_dir, 'xcodebuild') | |
608 if bisect_utils.IsWindowsHost(): | |
609 return os.path.join(src_dir, 'build') | |
610 raise NotImplementedError('Unexpected platform %s' % sys.platform) | |
611 | |
612 | |
613 class DesktopBuilder(Builder): | |
614 """DesktopBuilder is used to build Chromium on linux/mac/windows.""" | |
615 def __init__(self, opts): | |
616 super(DesktopBuilder, self).__init__(opts) | |
617 | |
618 def Build(self, depot, opts): | |
619 """Builds chromium_builder_perf target using options passed into | |
620 the script. | |
621 | |
622 Args: | |
623 depot: Current depot being bisected. | |
624 opts: The options parsed from the command line. | |
625 | |
626 Returns: | |
627 True if build was successful. | |
628 """ | |
629 targets = ['chromium_builder_perf'] | |
630 | |
631 threads = None | |
632 if opts.use_goma: | |
633 threads = 64 | |
634 | |
635 build_success = False | |
636 if opts.build_preference == 'make': | |
637 build_success = BuildWithMake(threads, targets, opts.target_build_type) | |
638 elif opts.build_preference == 'ninja': | |
639 build_success = BuildWithNinja(threads, targets, opts.target_build_type) | |
640 elif opts.build_preference == 'msvs': | |
641 assert bisect_utils.IsWindowsHost(), 'msvs is only supported on Windows.' | |
642 build_success = BuildWithVisualStudio(targets, opts.target_build_type) | |
643 else: | |
644 assert False, 'No build system defined.' | |
645 return build_success | |
646 | |
647 | |
648 class AndroidBuilder(Builder): | |
649 """AndroidBuilder is used to build on android.""" | |
650 def __init__(self, opts): | |
651 super(AndroidBuilder, self).__init__(opts) | |
652 | |
653 def _GetTargets(self): | |
654 return ['chrome_shell_apk', 'cc_perftests_apk', 'android_tools'] | |
655 | |
656 def Build(self, depot, opts): | |
657 """Builds the android content shell and other necessary tools using options | |
658 passed into the script. | |
659 | |
660 Args: | |
661 depot: Current depot being bisected. | |
662 opts: The options parsed from the command line. | |
663 | |
664 Returns: | |
665 True if build was successful. | |
666 """ | |
667 threads = None | |
668 if opts.use_goma: | |
669 threads = 64 | |
670 | |
671 build_success = False | |
672 if opts.build_preference == 'ninja': | |
673 build_success = BuildWithNinja( | |
674 threads, self._GetTargets(), opts.target_build_type) | |
675 else: | |
676 assert False, 'No build system defined.' | |
677 | |
678 return build_success | |
679 | |
680 | |
681 class AndroidChromeBuilder(AndroidBuilder): | |
682 """AndroidBuilder is used to build on android's chrome.""" | |
683 def __init__(self, opts): | |
684 super(AndroidChromeBuilder, self).__init__(opts) | |
685 | |
686 def _GetTargets(self): | |
687 return AndroidBuilder._GetTargets(self) + ['chrome_apk'] | |
688 | |
689 | |
690 class CrosBuilder(Builder): | |
691 """CrosBuilder is used to build and image ChromeOS/Chromium when cros is the | |
692 target platform.""" | |
693 def __init__(self, opts): | |
694 super(CrosBuilder, self).__init__(opts) | |
695 | |
696 def ImageToTarget(self, opts): | |
697 """Installs latest image to target specified by opts.cros_remote_ip. | |
698 | |
699 Args: | |
700 opts: Program options containing cros_board and cros_remote_ip. | |
701 | |
702 Returns: | |
703 True if successful. | |
704 """ | |
705 try: | |
706 # Keys will most likely be set to 0640 after wiping the chroot. | |
707 os.chmod(CROS_SCRIPT_KEY_PATH, 0600) | |
708 os.chmod(CROS_TEST_KEY_PATH, 0600) | |
709 cmd = [CROS_SDK_PATH, '--', './bin/cros_image_to_target.py', | |
710 '--remote=%s' % opts.cros_remote_ip, | |
711 '--board=%s' % opts.cros_board, '--test', '--verbose'] | |
712 | |
713 return_code = bisect_utils.RunProcess(cmd) | |
714 return not return_code | |
715 except OSError: | |
716 return False | |
717 | |
718 def BuildPackages(self, opts, depot): | |
719 """Builds packages for cros. | |
720 | |
721 Args: | |
722 opts: Program options containing cros_board. | |
723 depot: The depot being bisected. | |
724 | |
725 Returns: | |
726 True if successful. | |
727 """ | |
728 cmd = [CROS_SDK_PATH] | |
729 | |
730 if depot != 'cros': | |
731 path_to_chrome = os.path.join(os.getcwd(), '..') | |
732 cmd += ['--chrome_root=%s' % path_to_chrome] | |
733 | |
734 cmd += ['--'] | |
735 | |
736 if depot != 'cros': | |
737 cmd += ['CHROME_ORIGIN=LOCAL_SOURCE'] | |
738 | |
739 cmd += ['BUILDTYPE=%s' % opts.target_build_type, './build_packages', | |
740 '--board=%s' % opts.cros_board] | |
741 return_code = bisect_utils.RunProcess(cmd) | |
742 | |
743 return not return_code | |
744 | |
745 def BuildImage(self, opts, depot): | |
746 """Builds test image for cros. | |
747 | |
748 Args: | |
749 opts: Program options containing cros_board. | |
750 depot: The depot being bisected. | |
751 | |
752 Returns: | |
753 True if successful. | |
754 """ | |
755 cmd = [CROS_SDK_PATH] | |
756 | |
757 if depot != 'cros': | |
758 path_to_chrome = os.path.join(os.getcwd(), '..') | |
759 cmd += ['--chrome_root=%s' % path_to_chrome] | |
760 | |
761 cmd += ['--'] | |
762 | |
763 if depot != 'cros': | |
764 cmd += ['CHROME_ORIGIN=LOCAL_SOURCE'] | |
765 | |
766 cmd += ['BUILDTYPE=%s' % opts.target_build_type, '--', './build_image', | |
767 '--board=%s' % opts.cros_board, 'test'] | |
768 | |
769 return_code = bisect_utils.RunProcess(cmd) | |
770 | |
771 return not return_code | |
772 | |
773 def Build(self, depot, opts): | |
774 """Builds targets using options passed into the script. | |
775 | |
776 Args: | |
777 depot: Current depot being bisected. | |
778 opts: The options parsed from the command line. | |
779 | |
780 Returns: | |
781 True if build was successful. | |
782 """ | |
783 if self.BuildPackages(opts, depot): | |
784 if self.BuildImage(opts, depot): | |
785 return self.ImageToTarget(opts) | |
786 return False | |
787 | |
788 | |
789 def _ParseRevisionsFromDEPSFileManually(deps_file_contents): | 470 def _ParseRevisionsFromDEPSFileManually(deps_file_contents): |
790 """Parses the vars section of the DEPS file with regex. | 471 """Parses the vars section of the DEPS file with regex. |
791 | 472 |
792 Args: | 473 Args: |
793 deps_file_contents: The DEPS file contents as a string. | 474 deps_file_contents: The DEPS file contents as a string. |
794 | 475 |
795 Returns: | 476 Returns: |
796 A dict in the format {depot:revision} if successful, otherwise None. | 477 A dict in the format {depot:revision} if successful, otherwise None. |
797 """ | 478 """ |
798 # We'll parse the "vars" section of the DEPS file. | 479 # We'll parse the "vars" section of the DEPS file. |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1164 step_count += 1 | 845 step_count += 1 |
1165 if step_count: | 846 if step_count: |
1166 step_perf_time_avg = step_perf_time_avg / step_count | 847 step_perf_time_avg = step_perf_time_avg / step_count |
1167 step_build_time_avg = step_build_time_avg / step_count | 848 step_build_time_avg = step_build_time_avg / step_count |
1168 print | 849 print |
1169 print 'Average build time : %s' % datetime.timedelta( | 850 print 'Average build time : %s' % datetime.timedelta( |
1170 seconds=int(step_build_time_avg)) | 851 seconds=int(step_build_time_avg)) |
1171 print 'Average test time : %s' % datetime.timedelta( | 852 print 'Average test time : %s' % datetime.timedelta( |
1172 seconds=int(step_perf_time_avg)) | 853 seconds=int(step_perf_time_avg)) |
1173 | 854 |
| 855 |
1174 def _FindOtherRegressions(revision_data_sorted, bad_greater_than_good): | 856 def _FindOtherRegressions(revision_data_sorted, bad_greater_than_good): |
1175 """Compiles a list of other possible regressions from the revision data. | 857 """Compiles a list of other possible regressions from the revision data. |
1176 | 858 |
1177 Args: | 859 Args: |
1178 revision_data_sorted: Sorted list of (revision, revision data dict) pairs. | 860 revision_data_sorted: Sorted list of (revision, revision data dict) pairs. |
1179 bad_greater_than_good: Whether the result value at the "bad" revision is | 861 bad_greater_than_good: Whether the result value at the "bad" revision is |
1180 numerically greater than the result value at the "good" revision. | 862 numerically greater than the result value at the "good" revision. |
1181 | 863 |
1182 Returns: | 864 Returns: |
1183 A list of [current_rev, previous_rev, confidence] for other places where | 865 A list of [current_rev, previous_rev, confidence] for other places where |
(...skipping 19 matching lines...) Expand all Loading... |
1203 is_same_direction = (prev_less_than_current if | 885 is_same_direction = (prev_less_than_current if |
1204 bad_greater_than_good else not prev_less_than_current) | 886 bad_greater_than_good else not prev_less_than_current) |
1205 | 887 |
1206 # Only report potential regressions with high confidence. | 888 # Only report potential regressions with high confidence. |
1207 if is_same_direction and confidence > 50: | 889 if is_same_direction and confidence > 50: |
1208 other_regressions.append([current_id, previous_id, confidence]) | 890 other_regressions.append([current_id, previous_id, confidence]) |
1209 previous_values.append(current_values) | 891 previous_values.append(current_values) |
1210 previous_id = current_id | 892 previous_id = current_id |
1211 return other_regressions | 893 return other_regressions |
1212 | 894 |
| 895 |
1213 class BisectPerformanceMetrics(object): | 896 class BisectPerformanceMetrics(object): |
1214 """This class contains functionality to perform a bisection of a range of | 897 """This class contains functionality to perform a bisection of a range of |
1215 revisions to narrow down where performance regressions may have occurred. | 898 revisions to narrow down where performance regressions may have occurred. |
1216 | 899 |
1217 The main entry-point is the Run method. | 900 The main entry-point is the Run method. |
1218 """ | 901 """ |
1219 | 902 |
1220 def __init__(self, source_control, opts): | 903 def __init__(self, source_control, opts): |
1221 super(BisectPerformanceMetrics, self).__init__() | 904 super(BisectPerformanceMetrics, self).__init__() |
1222 | 905 |
1223 self.opts = opts | 906 self.opts = opts |
1224 self.source_control = source_control | 907 self.source_control = source_control |
1225 self.src_cwd = os.getcwd() | 908 self.src_cwd = os.getcwd() |
1226 self.cros_cwd = os.path.join(os.getcwd(), '..', 'cros') | 909 self.cros_cwd = os.path.join(os.getcwd(), '..', 'cros') |
1227 self.depot_cwd = {} | 910 self.depot_cwd = {} |
1228 self.cleanup_commands = [] | 911 self.cleanup_commands = [] |
1229 self.warnings = [] | 912 self.warnings = [] |
1230 self.builder = Builder.FromOpts(opts) | 913 self.builder = builder.Builder.FromOpts(opts) |
1231 | 914 |
1232 # This always starts true since the script grabs latest first. | 915 # This always starts true since the script grabs latest first. |
1233 self.was_blink = True | 916 self.was_blink = True |
1234 | 917 |
1235 for d in DEPOT_NAMES: | 918 for d in DEPOT_NAMES: |
1236 # The working directory of each depot is just the path to the depot, but | 919 # The working directory of each depot is just the path to the depot, but |
1237 # since we're already in 'src', we can skip that part. | 920 # since we're already in 'src', we can skip that part. |
1238 | 921 |
1239 self.depot_cwd[d] = os.path.join( | 922 self.depot_cwd[d] = os.path.join( |
1240 self.src_cwd, DEPOT_DEPS_NAME[d]['src'][4:]) | 923 self.src_cwd, DEPOT_DEPS_NAME[d]['src'][4:]) |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1433 A dict in the format {depot:revision} if successful, otherwise None. | 1116 A dict in the format {depot:revision} if successful, otherwise None. |
1434 """ | 1117 """ |
1435 cwd = os.getcwd() | 1118 cwd = os.getcwd() |
1436 self.ChangeToDepotWorkingDirectory(depot) | 1119 self.ChangeToDepotWorkingDirectory(depot) |
1437 | 1120 |
1438 results = {} | 1121 results = {} |
1439 | 1122 |
1440 if depot == 'chromium' or depot == 'android-chrome': | 1123 if depot == 'chromium' or depot == 'android-chrome': |
1441 results = self._ParseRevisionsFromDEPSFile(depot) | 1124 results = self._ParseRevisionsFromDEPSFile(depot) |
1442 os.chdir(cwd) | 1125 os.chdir(cwd) |
1443 elif depot == 'cros': | 1126 |
1444 cmd = [CROS_SDK_PATH, '--', 'portageq-%s' % self.opts.cros_board, | 1127 if depot == 'cros': |
1445 'best_visible', '/build/%s' % self.opts.cros_board, 'ebuild', | 1128 cmd = [ |
1446 CROS_CHROMEOS_PATTERN] | 1129 bisect_utils.CROS_SDK_PATH, |
| 1130 '--', |
| 1131 'portageq-%s' % self.opts.cros_board, |
| 1132 'best_visible', |
| 1133 '/build/%s' % self.opts.cros_board, |
| 1134 'ebuild', |
| 1135 CROS_CHROMEOS_PATTERN |
| 1136 ] |
1447 output, return_code = bisect_utils.RunProcessAndRetrieveOutput(cmd) | 1137 output, return_code = bisect_utils.RunProcessAndRetrieveOutput(cmd) |
1448 | 1138 |
1449 assert not return_code, ('An error occurred while running ' | 1139 assert not return_code, ('An error occurred while running ' |
1450 '"%s"' % ' '.join(cmd)) | 1140 '"%s"' % ' '.join(cmd)) |
1451 | 1141 |
1452 if len(output) > CROS_CHROMEOS_PATTERN: | 1142 if len(output) > CROS_CHROMEOS_PATTERN: |
1453 output = output[len(CROS_CHROMEOS_PATTERN):] | 1143 output = output[len(CROS_CHROMEOS_PATTERN):] |
1454 | 1144 |
1455 if len(output) > 1: | 1145 if len(output) > 1: |
1456 output = output.split('_')[0] | 1146 output = output.split('_')[0] |
(...skipping 11 matching lines...) Expand all Loading... |
1468 | 1158 |
1469 cwd = os.getcwd() | 1159 cwd = os.getcwd() |
1470 self.ChangeToDepotWorkingDirectory('chromium') | 1160 self.ChangeToDepotWorkingDirectory('chromium') |
1471 cmd = ['log', '-1', '--format=%H', | 1161 cmd = ['log', '-1', '--format=%H', |
1472 '--author=chrome-release@google.com', | 1162 '--author=chrome-release@google.com', |
1473 '--grep=to %s' % version, 'origin/master'] | 1163 '--grep=to %s' % version, 'origin/master'] |
1474 return_code = bisect_utils.CheckRunGit(cmd) | 1164 return_code = bisect_utils.CheckRunGit(cmd) |
1475 os.chdir(cwd) | 1165 os.chdir(cwd) |
1476 | 1166 |
1477 results['chromium'] = output.strip() | 1167 results['chromium'] = output.strip() |
1478 elif depot == 'v8': | 1168 |
| 1169 if depot == 'v8': |
1479 # We can't try to map the trunk revision to bleeding edge yet, because | 1170 # We can't try to map the trunk revision to bleeding edge yet, because |
1480 # we don't know which direction to try to search in. Have to wait until | 1171 # we don't know which direction to try to search in. Have to wait until |
1481 # the bisect has narrowed the results down to 2 v8 rolls. | 1172 # the bisect has narrowed the results down to 2 v8 rolls. |
1482 results['v8_bleeding_edge'] = None | 1173 results['v8_bleeding_edge'] = None |
1483 | 1174 |
1484 return results | 1175 return results |
1485 | 1176 |
1486 def BackupOrRestoreOutputdirectory(self, restore=False, build_type='Release'): | 1177 def BackupOrRestoreOutputdirectory(self, restore=False, build_type='Release'): |
1487 """Backs up or restores build output directory based on restore argument. | 1178 """Backs up or restores build output directory based on restore argument. |
1488 | 1179 |
1489 Args: | 1180 Args: |
1490 restore: Indicates whether to restore or backup. Default is False(Backup) | 1181 restore: Indicates whether to restore or backup. Default is False(Backup) |
1491 build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) | 1182 build_type: Target build type ('Release', 'Debug', 'Release_x64' etc.) |
1492 | 1183 |
1493 Returns: | 1184 Returns: |
1494 Path to backup or restored location as string. otherwise None if it fails. | 1185 Path to backup or restored location as string. otherwise None if it fails. |
1495 """ | 1186 """ |
1496 build_dir = os.path.abspath( | 1187 build_dir = os.path.abspath( |
1497 self.builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) | 1188 builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) |
1498 source_dir = os.path.join(build_dir, build_type) | 1189 source_dir = os.path.join(build_dir, build_type) |
1499 destination_dir = os.path.join(build_dir, '%s.bak' % build_type) | 1190 destination_dir = os.path.join(build_dir, '%s.bak' % build_type) |
1500 if restore: | 1191 if restore: |
1501 source_dir, destination_dir = destination_dir, source_dir | 1192 source_dir, destination_dir = destination_dir, source_dir |
1502 if os.path.exists(source_dir): | 1193 if os.path.exists(source_dir): |
1503 RmTreeAndMkDir(destination_dir, skip_makedir=True) | 1194 RmTreeAndMkDir(destination_dir, skip_makedir=True) |
1504 shutil.move(source_dir, destination_dir) | 1195 shutil.move(source_dir, destination_dir) |
1505 return destination_dir | 1196 return destination_dir |
1506 return None | 1197 return None |
1507 | 1198 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1551 if patch: | 1242 if patch: |
1552 # Get the SHA of the DEPS changes patch. | 1243 # Get the SHA of the DEPS changes patch. |
1553 patch_sha = GetSHA1HexDigest(patch) | 1244 patch_sha = GetSHA1HexDigest(patch) |
1554 | 1245 |
1555 # Update the DEPS changes patch with a patch to create a new file named | 1246 # Update the DEPS changes patch with a patch to create a new file named |
1556 # 'DEPS.sha' and add patch_sha evaluated above to it. | 1247 # 'DEPS.sha' and add patch_sha evaluated above to it. |
1557 patch = '%s\n%s' % (patch, DEPS_SHA_PATCH % {'deps_sha': patch_sha}) | 1248 patch = '%s\n%s' % (patch, DEPS_SHA_PATCH % {'deps_sha': patch_sha}) |
1558 | 1249 |
1559 # Get Build output directory | 1250 # Get Build output directory |
1560 abs_build_dir = os.path.abspath( | 1251 abs_build_dir = os.path.abspath( |
1561 self.builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) | 1252 builder.GetBuildOutputDirectory(self.opts, self.src_cwd)) |
1562 | 1253 |
1563 fetch_build_func = lambda: self.GetBuildArchiveForRevision( | 1254 fetch_build_func = lambda: self.GetBuildArchiveForRevision( |
1564 revision, self.opts.gs_bucket, self.opts.target_arch, | 1255 revision, self.opts.gs_bucket, self.opts.target_arch, |
1565 patch_sha, abs_build_dir) | 1256 patch_sha, abs_build_dir) |
1566 | 1257 |
1567 # Downloaded archive file path, downloads build archive for given revision. | 1258 # Downloaded archive file path, downloads build archive for given revision. |
1568 downloaded_file = fetch_build_func() | 1259 downloaded_file = fetch_build_func() |
1569 | 1260 |
1570 # When build archive doesn't exists, post a build request to tryserver | 1261 # When build archive doesn't exists, post a build request to tryserver |
1571 # and wait for the build to be produced. | 1262 # and wait for the build to be produced. |
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1909 | 1600 |
1910 if not _GenerateProfileIfNecessary(args): | 1601 if not _GenerateProfileIfNecessary(args): |
1911 err_text = 'Failed to generate profile for performance test.' | 1602 err_text = 'Failed to generate profile for performance test.' |
1912 return (err_text, failure_code) | 1603 return (err_text, failure_code) |
1913 | 1604 |
1914 # If running a Telemetry test for Chrome OS, insert the remote IP and | 1605 # If running a Telemetry test for Chrome OS, insert the remote IP and |
1915 # identity parameters. | 1606 # identity parameters. |
1916 is_telemetry = bisect_utils.IsTelemetryCommand(command_to_run) | 1607 is_telemetry = bisect_utils.IsTelemetryCommand(command_to_run) |
1917 if self.opts.target_platform == 'cros' and is_telemetry: | 1608 if self.opts.target_platform == 'cros' and is_telemetry: |
1918 args.append('--remote=%s' % self.opts.cros_remote_ip) | 1609 args.append('--remote=%s' % self.opts.cros_remote_ip) |
1919 args.append('--identity=%s' % CROS_TEST_KEY_PATH) | 1610 args.append('--identity=%s' % bisect_utils.CROS_TEST_KEY_PATH) |
1920 | 1611 |
1921 start_time = time.time() | 1612 start_time = time.time() |
1922 | 1613 |
1923 metric_values = [] | 1614 metric_values = [] |
1924 output_of_all_runs = '' | 1615 output_of_all_runs = '' |
1925 for i in xrange(self.opts.repeat_test_count): | 1616 for i in xrange(self.opts.repeat_test_count): |
1926 # Can ignore the return code since if the tests fail, it won't return 0. | 1617 # Can ignore the return code since if the tests fail, it won't return 0. |
1927 current_args = copy.copy(args) | 1618 current_args = copy.copy(args) |
1928 if is_telemetry: | 1619 if is_telemetry: |
1929 if i == 0 and reset_on_first_run: | 1620 if i == 0 and reset_on_first_run: |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2103 return True | 1794 return True |
2104 | 1795 |
2105 def PerformCrosChrootCleanup(self): | 1796 def PerformCrosChrootCleanup(self): |
2106 """Deletes the chroot. | 1797 """Deletes the chroot. |
2107 | 1798 |
2108 Returns: | 1799 Returns: |
2109 True if successful. | 1800 True if successful. |
2110 """ | 1801 """ |
2111 cwd = os.getcwd() | 1802 cwd = os.getcwd() |
2112 self.ChangeToDepotWorkingDirectory('cros') | 1803 self.ChangeToDepotWorkingDirectory('cros') |
2113 cmd = [CROS_SDK_PATH, '--delete'] | 1804 cmd = [bisect_utils.CROS_SDK_PATH, '--delete'] |
2114 return_code = bisect_utils.RunProcess(cmd) | 1805 return_code = bisect_utils.RunProcess(cmd) |
2115 os.chdir(cwd) | 1806 os.chdir(cwd) |
2116 return not return_code | 1807 return not return_code |
2117 | 1808 |
2118 def CreateCrosChroot(self): | 1809 def CreateCrosChroot(self): |
2119 """Creates a new chroot. | 1810 """Creates a new chroot. |
2120 | 1811 |
2121 Returns: | 1812 Returns: |
2122 True if successful. | 1813 True if successful. |
2123 """ | 1814 """ |
2124 cwd = os.getcwd() | 1815 cwd = os.getcwd() |
2125 self.ChangeToDepotWorkingDirectory('cros') | 1816 self.ChangeToDepotWorkingDirectory('cros') |
2126 cmd = [CROS_SDK_PATH, '--create'] | 1817 cmd = [bisect_utils.CROS_SDK_PATH, '--create'] |
2127 return_code = bisect_utils.RunProcess(cmd) | 1818 return_code = bisect_utils.RunProcess(cmd) |
2128 os.chdir(cwd) | 1819 os.chdir(cwd) |
2129 return not return_code | 1820 return not return_code |
2130 | 1821 |
2131 def PerformPreSyncCleanup(self, revision, depot): | 1822 def PerformPreSyncCleanup(self, revision, depot): |
2132 """Performs any necessary cleanup before syncing. | 1823 """Performs any necessary cleanup before syncing. |
2133 | 1824 |
2134 Returns: | 1825 Returns: |
2135 True if successful. | 1826 True if successful. |
2136 """ | 1827 """ |
(...skipping 1528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3665 # bugs. If you change this, please update the perf dashboard as well. | 3356 # bugs. If you change this, please update the perf dashboard as well. |
3666 bisect_utils.OutputAnnotationStepStart('Results') | 3357 bisect_utils.OutputAnnotationStepStart('Results') |
3667 print 'Error: %s' % e.message | 3358 print 'Error: %s' % e.message |
3668 if opts.output_buildbot_annotations: | 3359 if opts.output_buildbot_annotations: |
3669 bisect_utils.OutputAnnotationStepClosed() | 3360 bisect_utils.OutputAnnotationStepClosed() |
3670 return 1 | 3361 return 1 |
3671 | 3362 |
3672 | 3363 |
3673 if __name__ == '__main__': | 3364 if __name__ == '__main__': |
3674 sys.exit(main()) | 3365 sys.exit(main()) |
OLD | NEW |