| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 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 """Chromium auto-bisect tool | 6 """Chromium auto-bisect tool |
| 7 | 7 |
| 8 This script bisects a range of commits using binary search. It starts by getting | 8 This script bisects a range of commits using binary search. It starts by getting |
| 9 reference values for the specified "good" and "bad" commits. Then, for revisions | 9 reference values for the specified "good" and "bad" commits. Then, for revisions |
| 10 in between, it will get builds, run tests and classify intermediate revisions as | 10 in between, it will get builds, run tests and classify intermediate revisions as |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 --good_revision 408222\ | 34 --good_revision 408222\ |
| 35 --bad_revision 408232\ | 35 --bad_revision 408232\ |
| 36 --bisect_mode return_code\ | 36 --bisect_mode return_code\ |
| 37 --builder_type full | 37 --builder_type full |
| 38 | 38 |
| 39 In practice, the auto-bisect tool is usually run on tryserver.chromium.perf | 39 In practice, the auto-bisect tool is usually run on tryserver.chromium.perf |
| 40 try bots, and is started by tools/run-bisect-perf-regression.py using | 40 try bots, and is started by tools/run-bisect-perf-regression.py using |
| 41 config parameters from tools/auto_bisect/bisect.cfg. | 41 config parameters from tools/auto_bisect/bisect.cfg. |
| 42 """ | 42 """ |
| 43 | 43 |
| 44 import argparse |
| 44 import copy | 45 import copy |
| 45 import errno | 46 import errno |
| 46 import hashlib | 47 import hashlib |
| 48 import json |
| 47 import logging | 49 import logging |
| 48 import argparse | |
| 49 import os | 50 import os |
| 50 import re | 51 import re |
| 51 import shlex | 52 import shlex |
| 52 import shutil | 53 import shutil |
| 53 import StringIO | 54 import StringIO |
| 54 import sys | 55 import sys |
| 55 import time | 56 import time |
| 57 import urllib2 |
| 56 | 58 |
| 57 sys.path.append(os.path.join( | 59 sys.path.append(os.path.join( |
| 58 os.path.dirname(__file__), os.path.pardir, 'telemetry')) | 60 os.path.dirname(__file__), os.path.pardir, 'telemetry')) |
| 59 | 61 |
| 60 from bisect_printer import BisectPrinter | 62 from bisect_printer import BisectPrinter |
| 61 from bisect_results import BisectResults | 63 from bisect_results import BisectResults |
| 64 import bisect_results_json |
| 62 from bisect_state import BisectState | 65 from bisect_state import BisectState |
| 63 import bisect_utils | 66 import bisect_utils |
| 64 import builder | 67 import builder |
| 65 import fetch_build | 68 import fetch_build |
| 66 import math_utils | 69 import math_utils |
| 67 import query_crbug | 70 import query_crbug |
| 68 import request_build | 71 import request_build |
| 69 import source_control | 72 import source_control |
| 70 | 73 |
| 71 # The script is in chromium/src/tools/auto_bisect. Throughout this script, | 74 # The script is in chromium/src/tools/auto_bisect. Throughout this script, |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 BISECT_TRYJOB_BRANCH = 'bisect-tryjob' | 120 BISECT_TRYJOB_BRANCH = 'bisect-tryjob' |
| 118 # Git master branch name. | 121 # Git master branch name. |
| 119 BISECT_MASTER_BRANCH = 'master' | 122 BISECT_MASTER_BRANCH = 'master' |
| 120 # File to store 'git diff' content. | 123 # File to store 'git diff' content. |
| 121 BISECT_PATCH_FILE = 'deps_patch.txt' | 124 BISECT_PATCH_FILE = 'deps_patch.txt' |
| 122 # SVN repo where the bisect try jobs are submitted. | 125 # SVN repo where the bisect try jobs are submitted. |
| 123 PERF_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try-perf' | 126 PERF_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try-perf' |
| 124 FULL_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try' | 127 FULL_SVN_REPO_URL = 'svn://svn.chromium.org/chrome-try/try' |
| 125 ANDROID_CHROME_SVN_REPO_URL = ('svn://svn.chromium.org/chrome-try-internal/' | 128 ANDROID_CHROME_SVN_REPO_URL = ('svn://svn.chromium.org/chrome-try-internal/' |
| 126 'try-perf') | 129 'try-perf') |
| 130 PERF_DASH_RESULTS_URL = 'https://chromeperf.appspot.com/post_bisect_results' |
| 127 | 131 |
| 128 | 132 |
| 129 class RunGitError(Exception): | 133 class RunGitError(Exception): |
| 130 | 134 |
| 131 def __str__(self): | 135 def __str__(self): |
| 132 return '%s\nError executing git command.' % self.args[0] | 136 return '%s\nError executing git command.' % self.args[0] |
| 133 | 137 |
| 134 | 138 |
| 135 def GetSHA1HexDigest(contents): | 139 def GetSHA1HexDigest(contents): |
| 136 """Returns SHA1 hex digest of the given string.""" | 140 """Returns SHA1 hex digest of the given string.""" |
| (...skipping 2361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2498 opts: The options parsed from the command line. | 2502 opts: The options parsed from the command line. |
| 2499 | 2503 |
| 2500 Returns: | 2504 Returns: |
| 2501 True if the platform and build system are supported. | 2505 True if the platform and build system are supported. |
| 2502 """ | 2506 """ |
| 2503 # Haven't tested the script out on any other platforms yet. | 2507 # Haven't tested the script out on any other platforms yet. |
| 2504 supported = ['posix', 'nt'] | 2508 supported = ['posix', 'nt'] |
| 2505 return os.name in supported | 2509 return os.name in supported |
| 2506 | 2510 |
| 2507 | 2511 |
| 2512 def _PostBisectResults(bisect_results, opts, src_cwd): |
| 2513 """Posts bisect results to Perf Dashboard.""" |
| 2514 bisect_utils.OutputAnnotationStepStart('Post Results') |
| 2515 |
| 2516 results = bisect_results_json.get( |
| 2517 bisect_results, opts, DepotDirectoryRegistry(src_cwd)) |
| 2518 data = {'data': results} |
| 2519 request = urllib2.Request(PERF_DASH_RESULTS_URL) |
| 2520 request.add_header('Content-Type', 'application/json') |
| 2521 try: |
| 2522 urllib2.urlopen(request, json.dumps(data)) |
| 2523 except urllib2.URLError as e: |
| 2524 print 'Failed to post bisect results. Error: %s.' % e |
| 2525 bisect_utils.OutputAnnotationStepWarning() |
| 2526 |
| 2527 bisect_utils.OutputAnnotationStepClosed() |
| 2528 |
| 2529 |
| 2508 def RemoveBuildFiles(build_type): | 2530 def RemoveBuildFiles(build_type): |
| 2509 """Removes build files from previous runs.""" | 2531 """Removes build files from previous runs.""" |
| 2510 out_dir = os.path.join('out', build_type) | 2532 out_dir = os.path.join('out', build_type) |
| 2511 build_dir = os.path.join('build', build_type) | 2533 build_dir = os.path.join('build', build_type) |
| 2512 logging.info('Removing build files in "%s" and "%s".', | 2534 logging.info('Removing build files in "%s" and "%s".', |
| 2513 os.path.abspath(out_dir), os.path.abspath(build_dir)) | 2535 os.path.abspath(out_dir), os.path.abspath(build_dir)) |
| 2514 try: | 2536 try: |
| 2515 RemakeDirectoryTree(out_dir) | 2537 RemakeDirectoryTree(out_dir) |
| 2516 RemakeDirectoryTree(build_dir) | 2538 RemakeDirectoryTree(build_dir) |
| 2517 except Exception as e: | 2539 except Exception as e: |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2577 self.debug_ignore_perf_test = None | 2599 self.debug_ignore_perf_test = None |
| 2578 self.debug_ignore_regression_confidence = None | 2600 self.debug_ignore_regression_confidence = None |
| 2579 self.debug_fake_first_test_mean = 0 | 2601 self.debug_fake_first_test_mean = 0 |
| 2580 self.target_arch = 'ia32' | 2602 self.target_arch = 'ia32' |
| 2581 self.target_build_type = 'Release' | 2603 self.target_build_type = 'Release' |
| 2582 self.builder_type = 'perf' | 2604 self.builder_type = 'perf' |
| 2583 self.bisect_mode = bisect_utils.BISECT_MODE_MEAN | 2605 self.bisect_mode = bisect_utils.BISECT_MODE_MEAN |
| 2584 self.improvement_direction = 0 | 2606 self.improvement_direction = 0 |
| 2585 self.bug_id = '' | 2607 self.bug_id = '' |
| 2586 self.required_initial_confidence = 80.0 | 2608 self.required_initial_confidence = 80.0 |
| 2609 self.try_job_id = None |
| 2587 | 2610 |
| 2588 @staticmethod | 2611 @staticmethod |
| 2589 def _AddBisectOptionsGroup(parser): | 2612 def _AddBisectOptionsGroup(parser): |
| 2590 group = parser.add_argument_group('Bisect options') | 2613 group = parser.add_argument_group('Bisect options') |
| 2591 group.add_argument('-c', '--command', required=True, | 2614 group.add_argument('-c', '--command', required=True, |
| 2592 help='A command to execute your performance test at ' | 2615 help='A command to execute your performance test at ' |
| 2593 'each point in the bisection.') | 2616 'each point in the bisection.') |
| 2594 group.add_argument('-b', '--bad_revision', required=True, | 2617 group.add_argument('-b', '--bad_revision', required=True, |
| 2595 help='A bad revision to start bisection. Must be later ' | 2618 help='A bad revision to start bisection. Must be later ' |
| 2596 'than good revision. May be either a git or svn ' | 2619 'than good revision. May be either a git or svn ' |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2851 not opts.debug_ignore_sync and | 2874 not opts.debug_ignore_sync and |
| 2852 not opts.working_directory): | 2875 not opts.working_directory): |
| 2853 raise RuntimeError('You must switch to master branch to run bisection.') | 2876 raise RuntimeError('You must switch to master branch to run bisection.') |
| 2854 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) | 2877 bisect_test = BisectPerformanceMetrics(opts, os.getcwd()) |
| 2855 try: | 2878 try: |
| 2856 results = bisect_test.Run(opts.command, opts.bad_revision, | 2879 results = bisect_test.Run(opts.command, opts.bad_revision, |
| 2857 opts.good_revision, opts.metric) | 2880 opts.good_revision, opts.metric) |
| 2858 if results.error: | 2881 if results.error: |
| 2859 raise RuntimeError(results.error) | 2882 raise RuntimeError(results.error) |
| 2860 bisect_test.printer.FormatAndPrintResults(results) | 2883 bisect_test.printer.FormatAndPrintResults(results) |
| 2884 _PostBisectResults(results, opts, os.getcwd()) |
| 2861 return 0 | 2885 return 0 |
| 2862 finally: | 2886 finally: |
| 2863 bisect_test.PerformCleanup() | 2887 bisect_test.PerformCleanup() |
| 2864 except RuntimeError as e: | 2888 except RuntimeError as e: |
| 2865 if opts.output_buildbot_annotations: | 2889 if opts.output_buildbot_annotations: |
| 2866 # The perf dashboard scrapes the "results" step in order to comment on | 2890 # The perf dashboard scrapes the "results" step in order to comment on |
| 2867 # bugs. If you change this, please update the perf dashboard as well. | 2891 # bugs. If you change this, please update the perf dashboard as well. |
| 2868 bisect_utils.OutputAnnotationStepStart('Results') | 2892 bisect_utils.OutputAnnotationStepStart('Results') |
| 2869 print 'Runtime Error: %s' % e | 2893 print 'Runtime Error: %s' % e |
| 2870 if opts.output_buildbot_annotations: | 2894 if opts.output_buildbot_annotations: |
| 2871 bisect_utils.OutputAnnotationStepClosed() | 2895 bisect_utils.OutputAnnotationStepClosed() |
| 2872 return 1 | 2896 return 1 |
| 2873 | 2897 |
| 2874 | 2898 |
| 2875 if __name__ == '__main__': | 2899 if __name__ == '__main__': |
| 2876 sys.exit(main()) | 2900 sys.exit(main()) |
| OLD | NEW |