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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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_printer import BisectPrinter | 52 from bisect_printer import BisectPrinter |
53 from bisect_results import BisectResults | 53 from bisect_results import BisectResults |
54 from bisect_state import BisectState | 54 from bisect_state import BisectState |
55 import bisect_utils | 55 import bisect_utils |
56 import builder | 56 import builder |
57 import query_crbug | |
57 import math_utils | 58 import math_utils |
58 import request_build | 59 import request_build |
59 import source_control | 60 import source_control |
60 from telemetry.util import cloud_storage | 61 from telemetry.util import cloud_storage |
61 | 62 |
62 # The script is in chromium/src/tools/auto_bisect. Throughout this script, | 63 # The script is in chromium/src/tools/auto_bisect. Throughout this script, |
63 # we use paths to other things in the chromium/src repository. | 64 # we use paths to other things in the chromium/src repository. |
64 | 65 |
65 # Possible return values from BisectPerformanceMetrics.RunTest. | 66 # Possible return values from BisectPerformanceMetrics.RunTest. |
66 BUILD_RESULT_SUCCEED = 0 | 67 BUILD_RESULT_SUCCEED = 0 |
(...skipping 2070 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2137 | 2138 |
2138 Args: | 2139 Args: |
2139 command_to_run: Specify the command to execute the performance test. | 2140 command_to_run: Specify the command to execute the performance test. |
2140 good_revision: Number/tag of the known good revision. | 2141 good_revision: Number/tag of the known good revision. |
2141 bad_revision: Number/tag of the known bad revision. | 2142 bad_revision: Number/tag of the known bad revision. |
2142 metric: The performance metric to monitor. | 2143 metric: The performance metric to monitor. |
2143 | 2144 |
2144 Returns: | 2145 Returns: |
2145 A BisectResults object. | 2146 A BisectResults object. |
2146 """ | 2147 """ |
2148 | |
2147 # Choose depot to bisect first | 2149 # Choose depot to bisect first |
2148 target_depot = 'chromium' | 2150 target_depot = 'chromium' |
2149 if self.opts.target_platform == 'android-chrome': | 2151 if self.opts.target_platform == 'android-chrome': |
2150 target_depot = 'android-chrome' | 2152 target_depot = 'android-chrome' |
2151 | 2153 |
2152 cwd = os.getcwd() | 2154 cwd = os.getcwd() |
2153 self.depot_registry.ChangeToDepotDir(target_depot) | 2155 self.depot_registry.ChangeToDepotDir(target_depot) |
2154 | 2156 |
2155 # If they passed SVN revisions, we can try match them to git SHA1 hashes. | 2157 # If they passed SVN revisions, we can try match them to git SHA1 hashes. |
2156 bad_revision = source_control.ResolveToRevision( | 2158 bad_revision = source_control.ResolveToRevision( |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2477 self.debug_ignore_perf_test = None | 2479 self.debug_ignore_perf_test = None |
2478 self.debug_ignore_regression_confidence = None | 2480 self.debug_ignore_regression_confidence = None |
2479 self.debug_fake_first_test_mean = 0 | 2481 self.debug_fake_first_test_mean = 0 |
2480 self.gs_bucket = None | 2482 self.gs_bucket = None |
2481 self.target_arch = 'ia32' | 2483 self.target_arch = 'ia32' |
2482 self.target_build_type = 'Release' | 2484 self.target_build_type = 'Release' |
2483 self.builder_host = None | 2485 self.builder_host = None |
2484 self.builder_port = None | 2486 self.builder_port = None |
2485 self.bisect_mode = bisect_utils.BISECT_MODE_MEAN | 2487 self.bisect_mode = bisect_utils.BISECT_MODE_MEAN |
2486 self.improvement_direction = 0 | 2488 self.improvement_direction = 0 |
2489 self.bug_id = '' | |
2487 | 2490 |
2488 @staticmethod | 2491 @staticmethod |
2489 def _AddBisectOptionsGroup(parser): | 2492 def _AddBisectOptionsGroup(parser): |
2490 group = parser.add_argument_group('Bisect options') | 2493 group = parser.add_argument_group('Bisect options') |
2491 group.add_argument('-c', '--command', required=True, | 2494 group.add_argument('-c', '--command', required=True, |
2492 help='A command to execute your performance test at ' | 2495 help='A command to execute your performance test at ' |
2493 'each point in the bisection.') | 2496 'each point in the bisection.') |
2494 group.add_argument('-b', '--bad_revision', required=True, | 2497 group.add_argument('-b', '--bad_revision', required=True, |
2495 help='A bad revision to start bisection. Must be later ' | 2498 help='A bad revision to start bisection. Must be later ' |
2496 'than good revision. May be either a git or svn ' | 2499 'than good revision. May be either a git or svn ' |
(...skipping 27 matching lines...) Expand all Loading... | |
2524 help='The highest/lowest % are discarded to form a ' | 2527 help='The highest/lowest % are discarded to form a ' |
2525 'truncated mean. Values will be clamped to range ' | 2528 'truncated mean. Values will be clamped to range ' |
2526 '[0, 25]. Default value is 25 (highest/lowest 25% ' | 2529 '[0, 25]. Default value is 25 (highest/lowest 25% ' |
2527 'will be discarded).') | 2530 'will be discarded).') |
2528 group.add_argument('--bisect_mode', default=bisect_utils.BISECT_MODE_MEAN, | 2531 group.add_argument('--bisect_mode', default=bisect_utils.BISECT_MODE_MEAN, |
2529 choices=[bisect_utils.BISECT_MODE_MEAN, | 2532 choices=[bisect_utils.BISECT_MODE_MEAN, |
2530 bisect_utils.BISECT_MODE_STD_DEV, | 2533 bisect_utils.BISECT_MODE_STD_DEV, |
2531 bisect_utils.BISECT_MODE_RETURN_CODE], | 2534 bisect_utils.BISECT_MODE_RETURN_CODE], |
2532 help='The bisect mode. Choices are to bisect on the ' | 2535 help='The bisect mode. Choices are to bisect on the ' |
2533 'difference in mean, std_dev, or return_code.') | 2536 'difference in mean, std_dev, or return_code.') |
2537 group.add_argument('--bug_id', type=str, default='', | |
Sergiy Byelozyorov
2014/11/03 13:42:00
No need for type=str and default=''. These are def
| |
2538 help='The id for the bug associated with this bisect. ' + | |
2539 'If this number is given, bisect will attempt to ' + | |
Sergiy Byelozyorov
2014/11/03 13:42:00
Please align with opening ' on the line before lik
| |
2540 ' verify that the bug is not closed before starting.') | |
Sergiy Byelozyorov
2014/11/03 13:42:00
Remove space in the beginning - it is already pres
| |
2534 | 2541 |
2535 @staticmethod | 2542 @staticmethod |
2536 def _AddBuildOptionsGroup(parser): | 2543 def _AddBuildOptionsGroup(parser): |
2537 group = parser.add_argument_group('Build options') | 2544 group = parser.add_argument_group('Build options') |
2538 group.add_argument('-w', '--working_directory', | 2545 group.add_argument('-w', '--working_directory', |
2539 help='Path to the working directory where the script ' | 2546 help='Path to the working directory where the script ' |
2540 'will do an initial checkout of the chromium depot. The ' | 2547 'will do an initial checkout of the chromium depot. The ' |
2541 'files will be placed in a subdirectory "bisect" under ' | 2548 'files will be placed in a subdirectory "bisect" under ' |
2542 'working_directory and that will be used to perform the ' | 2549 'working_directory and that will be used to perform the ' |
2543 'bisection. This parameter is optional, if it is not ' | 2550 'bisection. This parameter is optional, if it is not ' |
2544 'supplied, the script will work from the current depot.') | 2551 'supplied, the script will work from the current depot.') |
2545 group.add_argument('--build_preference', type='choice', | 2552 group.add_argument('--build_preference', type=str, |
Sergiy Byelozyorov
2014/11/03 13:42:00
Thanks for fixing it. Please remove type='str' arg
| |
2546 choices=['msvs', 'ninja', 'make'], | 2553 choices=['msvs', 'ninja', 'make'], |
2547 help='The preferred build system to use. On linux/mac ' | 2554 help='The preferred build system to use. On linux/mac ' |
2548 'the options are make/ninja. On Windows, the ' | 2555 'the options are make/ninja. On Windows, the ' |
2549 'options are msvs/ninja.') | 2556 'options are msvs/ninja.') |
2550 group.add_argument('--target_platform', type='choice', default='chromium', | 2557 group.add_argument('--target_platform', type=str, default='chromium', |
2551 choices=['chromium', 'android', 'android-chrome'], | 2558 choices=['chromium', 'android', 'android-chrome'], |
2552 help='The target platform. Choices are "chromium" ' | 2559 help='The target platform. Choices are "chromium" ' |
2553 '(current platform), or "android". If you specify ' | 2560 '(current platform), or "android". If you specify ' |
2554 'something other than "chromium", you must be ' | 2561 'something other than "chromium", you must be ' |
2555 'properly set up to build that platform.') | 2562 'properly set up to build that platform.') |
2556 group.add_argument('--no_custom_deps', dest='no_custom_deps', | 2563 group.add_argument('--no_custom_deps', dest='no_custom_deps', |
2557 action='store_true', default=False, | 2564 action='store_true', default=False, |
2558 help='Run the script with custom_deps or not.') | 2565 help='Run the script with custom_deps or not.') |
2559 group.add_argument('--extra_src', | 2566 group.add_argument('--extra_src', |
2560 help='Path to a script which can be used to modify the ' | 2567 help='Path to a script which can be used to modify the ' |
2561 'bisect script\'s behavior.') | 2568 'bisect script\'s behavior.') |
2562 group.add_argument('--use_goma', action='store_true', | 2569 group.add_argument('--use_goma', action='store_true', |
2563 help='Add a bunch of extra threads for goma, and enable ' | 2570 help='Add a bunch of extra threads for goma, and enable ' |
2564 'goma') | 2571 'goma') |
2565 group.add_argument('--goma_dir', | 2572 group.add_argument('--goma_dir', |
2566 help='Path to goma tools (or system default if not ' | 2573 help='Path to goma tools (or system default if not ' |
2567 'specified).') | 2574 'specified).') |
2568 group.add_argument('--goma_threads', type=int, default='64', | 2575 group.add_argument('--goma_threads', type=int, default='64', |
2569 help='Number of threads for goma, only if using goma.') | 2576 help='Number of threads for goma, only if using goma.') |
2570 group.add_argument('--output_buildbot_annotations', action='store_true', | 2577 group.add_argument('--output_buildbot_annotations', action='store_true', |
2571 help='Add extra annotation output for buildbot.') | 2578 help='Add extra annotation output for buildbot.') |
2572 group.add_argument('--gs_bucket', default='', dest='gs_bucket', | 2579 group.add_argument('--gs_bucket', default='', dest='gs_bucket', |
2573 help='Name of Google Storage bucket to upload or ' | 2580 help='Name of Google Storage bucket to upload or ' |
2574 'download build. e.g., chrome-perf') | 2581 'download build. e.g., chrome-perf') |
2575 group.add_argument('--target_arch', type='choice', default='ia32', | 2582 group.add_argument('--target_arch', type=str, default='ia32', |
2576 dest='target_arch', choices=['ia32', 'x64', 'arm'], | 2583 dest='target_arch', choices=['ia32', 'x64', 'arm'], |
2577 help='The target build architecture. Choices are "ia32" ' | 2584 help='The target build architecture. Choices are "ia32" ' |
2578 '(default), "x64" or "arm".') | 2585 '(default), "x64" or "arm".') |
2579 group.add_argument('--target_build_type', type='choice', default='Release', | 2586 group.add_argument('--target_build_type', type=str, default='Release', |
2580 choices=['Release', 'Debug'], | 2587 choices=['Release', 'Debug'], |
2581 help='The target build type. Choices are "Release" ' | 2588 help='The target build type. Choices are "Release" ' |
2582 '(default), or "Debug".') | 2589 '(default), or "Debug".') |
2583 group.add_argument('--builder_host', dest='builder_host', | 2590 group.add_argument('--builder_host', dest='builder_host', |
2584 help='Host address of server to produce build by ' | 2591 help='Host address of server to produce build by ' |
2585 'posting try job request.') | 2592 'posting try job request.') |
2586 group.add_argument('--builder_port', dest='builder_port', type='int', | 2593 group.add_argument('--builder_port', dest='builder_port', type=int, |
2587 help='HTTP port of the server to produce build by ' | 2594 help='HTTP port of the server to produce build by ' |
2588 'posting try job request.') | 2595 'posting try job request.') |
2589 | 2596 |
2590 @staticmethod | 2597 @staticmethod |
2591 def _AddDebugOptionsGroup(parser): | 2598 def _AddDebugOptionsGroup(parser): |
2592 group = parser.add_argument_group('Debug options') | 2599 group = parser.add_argument_group('Debug options') |
2593 group.add_argument('--debug_ignore_build', action='store_true', | 2600 group.add_argument('--debug_ignore_build', action='store_true', |
2594 help='DEBUG: Don\'t perform builds.') | 2601 help='DEBUG: Don\'t perform builds.') |
2595 group.add_argument('--debug_ignore_sync', action='store_true', | 2602 group.add_argument('--debug_ignore_sync', action='store_true', |
2596 help='DEBUG: Don\'t perform syncs.') | 2603 help='DEBUG: Don\'t perform syncs.') |
2597 group.add_argument('--debug_ignore_perf_test', action='store_true', | 2604 group.add_argument('--debug_ignore_perf_test', action='store_true', |
2598 help='DEBUG: Don\'t perform performance tests.') | 2605 help='DEBUG: Don\'t perform performance tests.') |
2599 group.add_argument('--debug_ignore_regression_confidence', | 2606 group.add_argument('--debug_ignore_regression_confidence', |
2600 action='store_true', | 2607 action='store_true', |
2601 help='DEBUG: Don\'t score the confidence of the initial ' | 2608 help='DEBUG: Don\'t score the confidence of the initial ' |
2602 'good and bad revisions\' test results.') | 2609 'good and bad revisions\' test results.') |
2603 group.add_argument('--debug_fake_first_test_mean', type='int', default='0', | 2610 group.add_argument('--debug_fake_first_test_mean', type=int, default='0', |
2604 help='DEBUG: When faking performance tests, return this ' | 2611 help='DEBUG: When faking performance tests, return this ' |
2605 'value as the mean of the first performance test, ' | 2612 'value as the mean of the first performance test, ' |
2606 'and return a mean of 0.0 for further tests.') | 2613 'and return a mean of 0.0 for further tests.') |
2607 return group | 2614 return group |
2608 | 2615 |
2609 @classmethod | 2616 @classmethod |
2610 def _CreateCommandLineParser(cls): | 2617 def _CreateCommandLineParser(cls): |
2611 """Creates a parser with bisect options. | 2618 """Creates a parser with bisect options. |
2612 | 2619 |
2613 Returns: | 2620 Returns: |
2614 An instance of optparse.OptionParser. | 2621 An instance of optparse.OptionParser. |
2615 """ | 2622 """ |
2616 usage = ('%prog [options] [-- chromium-options]\n' | 2623 usage = ('%prog [options] [-- chromium-options]\n' |
2617 'Perform binary search on revision history to find a minimal ' | 2624 'Perform binary search on revision history to find a minimal ' |
2618 'range of revisions where a performance metric regressed.\n') | 2625 'range of revisions where a performance metric regressed.\n') |
2619 | 2626 |
2620 parser = argparse.ArgumentParser(usage=usage) | 2627 parser = argparse.ArgumentParser(usage=usage) |
2621 cls._AddBisectOptionsGroup(parser) | 2628 cls._AddBisectOptionsGroup(parser) |
2622 cls._AddBuildOptionsGroup(parser) | 2629 cls._AddBuildOptionsGroup(parser) |
2623 cls._AddDebugOptionsGroup(parser) | 2630 cls._AddDebugOptionsGroup(parser) |
2624 return parser | 2631 return parser |
2625 | 2632 |
2626 def ParseCommandLine(self): | 2633 def ParseCommandLine(self): |
2627 """Parses the command line for bisect options.""" | 2634 """Parses the command line for bisect options.""" |
2628 parser = self._CreateCommandLineParser() | 2635 parser = self._CreateCommandLineParser() |
2629 opts, _ = parser.parse_args() | 2636 opts = parser.parse_args() |
2630 | 2637 |
2631 try: | 2638 try: |
2632 if (not opts.metric and | 2639 if (not opts.metric and |
2633 opts.bisect_mode != bisect_utils.BISECT_MODE_RETURN_CODE): | 2640 opts.bisect_mode != bisect_utils.BISECT_MODE_RETURN_CODE): |
2634 raise RuntimeError('missing required parameter: --metric') | 2641 raise RuntimeError('missing required parameter: --metric') |
2635 | 2642 |
2636 if opts.gs_bucket: | 2643 if opts.gs_bucket: |
2637 if not cloud_storage.List(opts.gs_bucket): | 2644 if not cloud_storage.List(opts.gs_bucket): |
2638 raise RuntimeError('Invalid Google Storage: gs://%s' % opts.gs_bucket) | 2645 raise RuntimeError('Invalid Google Storage: gs://%s' % opts.gs_bucket) |
2639 if not opts.builder_host: | 2646 if not opts.builder_host: |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2700 logging.basicConfig( | 2707 logging.basicConfig( |
2701 stream=logging.sys.stdout, level=logging.INFO, format=logging_format) | 2708 stream=logging.sys.stdout, level=logging.INFO, format=logging_format) |
2702 | 2709 |
2703 | 2710 |
2704 def main(): | 2711 def main(): |
2705 _ConfigureLogging() | 2712 _ConfigureLogging() |
2706 try: | 2713 try: |
2707 opts = BisectOptions() | 2714 opts = BisectOptions() |
2708 opts.ParseCommandLine() | 2715 opts.ParseCommandLine() |
2709 | 2716 |
2717 if opts.bug_id: | |
2718 if opts.output_buildbot_annotations: | |
2719 bisect_utils.OutputAnnotationStepStart('Checking Issue Tracker') | |
2720 issue_closed = query_crbug.CheckIssueClosed(opts.bug_id) | |
2721 if issue_closed: | |
2722 print 'Aborting bisect because bug is closed' | |
2723 else: | |
2724 print 'Could not confirm bug is closed, proceeding.' | |
2725 if opts.output_buildbot_annotations: | |
2726 bisect_utils.OutputAnnotationStepClosed() | |
2727 if issue_closed: | |
2728 results = BisectResults(abort_reason='the bug is closed.') | |
2729 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) | |
2730 bisect_test.printer.FormatAndPrintResults(results) | |
2731 return 0 | |
2732 | |
2733 | |
2710 if opts.extra_src: | 2734 if opts.extra_src: |
2711 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) | 2735 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) |
2712 if not extra_src: | 2736 if not extra_src: |
2713 raise RuntimeError('Invalid or missing --extra_src.') | 2737 raise RuntimeError('Invalid or missing --extra_src.') |
2714 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) | 2738 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) |
2715 | 2739 |
2716 if opts.working_directory: | 2740 if opts.working_directory: |
2717 custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS | 2741 custom_deps = bisect_utils.DEFAULT_GCLIENT_CUSTOM_DEPS |
2718 if opts.no_custom_deps: | 2742 if opts.no_custom_deps: |
2719 custom_deps = None | 2743 custom_deps = None |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2753 bisect_utils.OutputAnnotationStepStart('Results') | 2777 bisect_utils.OutputAnnotationStepStart('Results') |
2754 print 'Error: ', e.message | 2778 print 'Error: ', e.message |
2755 logging.warn('A RuntimeError was caught: %s', e.message) | 2779 logging.warn('A RuntimeError was caught: %s', e.message) |
2756 if opts.output_buildbot_annotations: | 2780 if opts.output_buildbot_annotations: |
2757 bisect_utils.OutputAnnotationStepClosed() | 2781 bisect_utils.OutputAnnotationStepClosed() |
2758 return 1 | 2782 return 1 |
2759 | 2783 |
2760 | 2784 |
2761 if __name__ == '__main__': | 2785 if __name__ == '__main__': |
2762 sys.exit(main()) | 2786 sys.exit(main()) |
OLD | NEW |