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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 # the DEPS file with the following format: | 181 # the DEPS file with the following format: |
182 # 'depot_name': 'revision', | 182 # 'depot_name': 'revision', |
183 vars_body = re_results.group('vars_body') | 183 vars_body = re_results.group('vars_body') |
184 rxp = re.compile(r"'(?P<depot_body>[\w_-]+)':[\s]+'(?P<rev_body>[\w@]+)'", | 184 rxp = re.compile(r"'(?P<depot_body>[\w_-]+)':[\s]+'(?P<rev_body>[\w@]+)'", |
185 re.MULTILINE) | 185 re.MULTILINE) |
186 re_results = rxp.findall(vars_body) | 186 re_results = rxp.findall(vars_body) |
187 | 187 |
188 return dict(re_results) | 188 return dict(re_results) |
189 | 189 |
190 | 190 |
191 def _WaitUntilBuildIsReady(fetch_build_func, bot_name, builder_host, | 191 def _WaitUntilBuildIsReady(fetch_build_func, bot_name, builder_type, |
192 builder_port, build_request_id, max_timeout): | 192 build_request_id, max_timeout): |
193 """Waits until build is produced by bisect builder on try server. | 193 """Waits until build is produced by bisect builder on try server. |
194 | 194 |
195 Args: | 195 Args: |
196 fetch_build_func: Function to check and download build from cloud storage. | 196 fetch_build_func: Function to check and download build from cloud storage. |
197 bot_name: Builder bot name on try server. | 197 bot_name: Builder bot name on try server. |
198 builder_host Try server host name. | 198 builder_type: Builder type, e.g. "perf". |
RobertoCN
2015/01/09 23:02:06
Nit:
Will the list of acceptable builder_types be
| |
199 builder_port: Try server port. | |
200 build_request_id: A unique ID of the build request posted to try server. | 199 build_request_id: A unique ID of the build request posted to try server. |
201 max_timeout: Maximum time to wait for the build. | 200 max_timeout: Maximum time to wait for the build. |
202 | 201 |
203 Returns: | 202 Returns: |
204 Downloaded archive file path if exists, otherwise None. | 203 Downloaded archive file path if exists, otherwise None. |
205 """ | 204 """ |
206 # Build number on the try server. | 205 # Build number on the try server. |
207 build_num = None | 206 build_num = None |
208 # Interval to check build on cloud storage. | 207 # Interval to check build on cloud storage. |
209 poll_interval = 60 | 208 poll_interval = 60 |
210 # Interval to check build status on try server in seconds. | 209 # Interval to check build status on try server in seconds. |
211 status_check_interval = 600 | 210 status_check_interval = 600 |
212 last_status_check = time.time() | 211 last_status_check = time.time() |
213 start_time = time.time() | 212 start_time = time.time() |
214 while True: | 213 while True: |
215 # Checks for build on gs://chrome-perf and download if exists. | 214 # Checks for build on gs://chrome-perf and download if exists. |
216 res = fetch_build_func() | 215 res = fetch_build_func() |
217 if res: | 216 if res: |
218 return (res, 'Build successfully found') | 217 return (res, 'Build successfully found') |
219 elapsed_status_check = time.time() - last_status_check | 218 elapsed_status_check = time.time() - last_status_check |
220 # To avoid overloading try server with status check requests, we check | 219 # To avoid overloading try server with status check requests, we check |
221 # build status for every 10 minutes. | 220 # build status for every 10 minutes. |
222 if elapsed_status_check > status_check_interval: | 221 if elapsed_status_check > status_check_interval: |
223 last_status_check = time.time() | 222 last_status_check = time.time() |
224 if not build_num: | 223 if not build_num: |
225 # Get the build number on try server for the current build. | 224 # Get the build number on try server for the current build. |
226 build_num = request_build.GetBuildNumFromBuilder( | 225 build_num = request_build.GetBuildNumFromBuilder( |
227 build_request_id, bot_name, builder_host, builder_port) | 226 build_request_id, bot_name, builder_type) |
228 # Check the status of build using the build number. | 227 # Check the status of build using the build number. |
229 # Note: Build is treated as PENDING if build number is not found | 228 # Note: Build is treated as PENDING if build number is not found |
230 # on the the try server. | 229 # on the the try server. |
231 build_status, status_link = request_build.GetBuildStatus( | 230 build_status, status_link = request_build.GetBuildStatus( |
232 build_num, bot_name, builder_host, builder_port) | 231 build_num, bot_name, builder_type) |
233 if build_status == request_build.FAILED: | 232 if build_status == request_build.FAILED: |
234 return (None, 'Failed to produce build, log: %s' % status_link) | 233 return (None, 'Failed to produce build, log: %s' % status_link) |
235 elapsed_time = time.time() - start_time | 234 elapsed_time = time.time() - start_time |
236 if elapsed_time > max_timeout: | 235 if elapsed_time > max_timeout: |
237 return (None, 'Timed out: %ss without build' % max_timeout) | 236 return (None, 'Timed out: %ss without build' % max_timeout) |
238 | 237 |
239 logging.info('Time elapsed: %ss without build.', elapsed_time) | 238 logging.info('Time elapsed: %ss without build.', elapsed_time) |
240 time.sleep(poll_interval) | 239 time.sleep(poll_interval) |
241 # For some reason, mac bisect bots were not flushing stdout periodically. | 240 # For some reason, mac bisect bots were not flushing stdout periodically. |
242 # As a result buildbot command is timed-out. Flush stdout on all platforms | 241 # As a result buildbot command is timed-out. Flush stdout on all platforms |
(...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
896 build_timeout = self._GetBuilderBuildTime() | 895 build_timeout = self._GetBuilderBuildTime() |
897 | 896 |
898 try: | 897 try: |
899 _BuilderTryjob(git_revision, bot_name, build_request_id, deps_patch) | 898 _BuilderTryjob(git_revision, bot_name, build_request_id, deps_patch) |
900 except RunGitError as e: | 899 except RunGitError as e: |
901 logging.warn('Failed to post builder try job for revision: [%s].\n' | 900 logging.warn('Failed to post builder try job for revision: [%s].\n' |
902 'Error: %s', git_revision, e) | 901 'Error: %s', git_revision, e) |
903 return None | 902 return None |
904 | 903 |
905 archive_filename, error_msg = _WaitUntilBuildIsReady( | 904 archive_filename, error_msg = _WaitUntilBuildIsReady( |
906 fetch_build_func, bot_name, self.opts.builder_host, | 905 fetch_build_func, bot_name, self.opts.builder_type, build_request_id, |
907 self.opts.builder_port, build_request_id, build_timeout) | 906 build_timeout) |
908 if not archive_filename: | 907 if not archive_filename: |
909 logging.warn('%s [revision: %s]', error_msg, git_revision) | 908 logging.warn('%s [revision: %s]', error_msg, git_revision) |
910 return archive_filename | 909 return archive_filename |
911 | 910 |
912 @staticmethod | 911 @staticmethod |
913 def _GetBuilderName(target_platform, builder_type=fetch_build.PERF_BUILDER): | 912 def _GetBuilderName(target_platform, builder_type=fetch_build.PERF_BUILDER): |
914 """Gets builder bot name and build time in seconds based on platform.""" | 913 """Gets builder bot name and build time in seconds based on platform.""" |
915 if builder_type != fetch_build.PERF_BUILDER: | 914 if builder_type != fetch_build.PERF_BUILDER: |
916 raise NotImplementedError('No builder names for non-perf builds yet.') | 915 raise NotImplementedError('No builder names for non-perf builds yet.') |
917 if bisect_utils.IsWindowsHost(): | 916 if bisect_utils.IsWindowsHost(): |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1009 if bisect_utils.IsWindowsHost(): | 1008 if bisect_utils.IsWindowsHost(): |
1010 return 'full-build-win32' | 1009 return 'full-build-win32' |
1011 if bisect_utils.IsLinuxHost(): | 1010 if bisect_utils.IsLinuxHost(): |
1012 return 'full-build-linux' | 1011 return 'full-build-linux' |
1013 if bisect_utils.IsMacHost(): | 1012 if bisect_utils.IsMacHost(): |
1014 return 'full-build-mac' | 1013 return 'full-build-mac' |
1015 raise NotImplementedError('Unknown platform "%s".' % sys.platform) | 1014 raise NotImplementedError('Unknown platform "%s".' % sys.platform) |
1016 | 1015 |
1017 def IsDownloadable(self, depot): | 1016 def IsDownloadable(self, depot): |
1018 """Checks if build can be downloaded based on target platform and depot.""" | 1017 """Checks if build can be downloaded based on target platform and depot.""" |
1019 if self.opts.target_platform in ['chromium', 'android']: | 1018 if (self.opts.target_platform in ['chromium', 'android'] |
1019 and self.opts.builder_type == fetch_build.PERF_BUILDER): | |
1020 return (depot == 'chromium' or | 1020 return (depot == 'chromium' or |
1021 'chromium' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'] or | 1021 'chromium' in bisect_utils.DEPOT_DEPS_NAME[depot]['from'] or |
1022 'v8' in bisect_utils.DEPOT_DEPS_NAME[depot]['from']) | 1022 'v8' in bisect_utils.DEPOT_DEPS_NAME[depot]['from']) |
1023 return False | 1023 return False |
1024 | 1024 |
1025 def UpdateDepsContents(self, deps_contents, depot, git_revision, deps_key): | 1025 def UpdateDepsContents(self, deps_contents, depot, git_revision, deps_key): |
1026 """Returns modified version of DEPS file contents. | 1026 """Returns modified version of DEPS file contents. |
1027 | 1027 |
1028 Args: | 1028 Args: |
1029 deps_contents: DEPS file content. | 1029 deps_contents: DEPS file content. |
(...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2505 self.no_custom_deps = False | 2505 self.no_custom_deps = False |
2506 self.working_directory = None | 2506 self.working_directory = None |
2507 self.extra_src = None | 2507 self.extra_src = None |
2508 self.debug_ignore_build = None | 2508 self.debug_ignore_build = None |
2509 self.debug_ignore_sync = None | 2509 self.debug_ignore_sync = None |
2510 self.debug_ignore_perf_test = None | 2510 self.debug_ignore_perf_test = None |
2511 self.debug_ignore_regression_confidence = None | 2511 self.debug_ignore_regression_confidence = None |
2512 self.debug_fake_first_test_mean = 0 | 2512 self.debug_fake_first_test_mean = 0 |
2513 self.target_arch = 'ia32' | 2513 self.target_arch = 'ia32' |
2514 self.target_build_type = 'Release' | 2514 self.target_build_type = 'Release' |
2515 self.builder_host = None | 2515 self.builder_type = 'perf' |
2516 self.builder_port = None | |
2517 self.bisect_mode = bisect_utils.BISECT_MODE_MEAN | 2516 self.bisect_mode = bisect_utils.BISECT_MODE_MEAN |
2518 self.improvement_direction = 0 | 2517 self.improvement_direction = 0 |
2519 self.bug_id = '' | 2518 self.bug_id = '' |
2520 | 2519 |
2521 @staticmethod | 2520 @staticmethod |
2522 def _AddBisectOptionsGroup(parser): | 2521 def _AddBisectOptionsGroup(parser): |
2523 group = parser.add_argument_group('Bisect options') | 2522 group = parser.add_argument_group('Bisect options') |
2524 group.add_argument('-c', '--command', required=True, | 2523 group.add_argument('-c', '--command', required=True, |
2525 help='A command to execute your performance test at ' | 2524 help='A command to execute your performance test at ' |
2526 'each point in the bisection.') | 2525 'each point in the bisection.') |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2608 group.add_argument('--output_buildbot_annotations', action='store_true', | 2607 group.add_argument('--output_buildbot_annotations', action='store_true', |
2609 help='Add extra annotation output for buildbot.') | 2608 help='Add extra annotation output for buildbot.') |
2610 group.add_argument('--target_arch', default='ia32', | 2609 group.add_argument('--target_arch', default='ia32', |
2611 dest='target_arch', choices=['ia32', 'x64', 'arm'], | 2610 dest='target_arch', choices=['ia32', 'x64', 'arm'], |
2612 help='The target build architecture. Choices are "ia32" ' | 2611 help='The target build architecture. Choices are "ia32" ' |
2613 '(default), "x64" or "arm".') | 2612 '(default), "x64" or "arm".') |
2614 group.add_argument('--target_build_type', default='Release', | 2613 group.add_argument('--target_build_type', default='Release', |
2615 choices=['Release', 'Debug'], | 2614 choices=['Release', 'Debug'], |
2616 help='The target build type. Choices are "Release" ' | 2615 help='The target build type. Choices are "Release" ' |
2617 '(default), or "Debug".') | 2616 '(default), or "Debug".') |
2618 group.add_argument('--builder_host', dest='builder_host', | 2617 group.add_argument('--builder_type', default=fetch_build.PERF_BUILDER, |
2619 help='Host address of server to produce build by ' | 2618 choices=[fetch_build.PERF_BUILDER, |
2620 'posting try job request.') | 2619 fetch_build.FULL_BUILDER], |
2621 group.add_argument('--builder_port', dest='builder_port', type=int, | 2620 help='Type of builder to get build from. This ' |
2622 help='HTTP port of the server to produce build by ' | 2621 'determines both the bot that builds and the ' |
2623 'posting try job request.') | 2622 'place where archived builds are downloaded from.') |
2624 | 2623 |
2625 @staticmethod | 2624 @staticmethod |
2626 def _AddDebugOptionsGroup(parser): | 2625 def _AddDebugOptionsGroup(parser): |
2627 group = parser.add_argument_group('Debug options') | 2626 group = parser.add_argument_group('Debug options') |
2628 group.add_argument('--debug_ignore_build', action='store_true', | 2627 group.add_argument('--debug_ignore_build', action='store_true', |
2629 help='DEBUG: Don\'t perform builds.') | 2628 help='DEBUG: Don\'t perform builds.') |
2630 group.add_argument('--debug_ignore_sync', action='store_true', | 2629 group.add_argument('--debug_ignore_sync', action='store_true', |
2631 help='DEBUG: Don\'t perform syncs.') | 2630 help='DEBUG: Don\'t perform syncs.') |
2632 group.add_argument('--debug_ignore_perf_test', action='store_true', | 2631 group.add_argument('--debug_ignore_perf_test', action='store_true', |
2633 help='DEBUG: Don\'t perform performance tests.') | 2632 help='DEBUG: Don\'t perform performance tests.') |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2792 # bugs. If you change this, please update the perf dashboard as well. | 2791 # bugs. If you change this, please update the perf dashboard as well. |
2793 bisect_utils.OutputAnnotationStepStart('Results') | 2792 bisect_utils.OutputAnnotationStepStart('Results') |
2794 print 'Runtime Error: %s' % e | 2793 print 'Runtime Error: %s' % e |
2795 if opts.output_buildbot_annotations: | 2794 if opts.output_buildbot_annotations: |
2796 bisect_utils.OutputAnnotationStepClosed() | 2795 bisect_utils.OutputAnnotationStepClosed() |
2797 return 1 | 2796 return 1 |
2798 | 2797 |
2799 | 2798 |
2800 if __name__ == '__main__': | 2799 if __name__ == '__main__': |
2801 sys.exit(main()) | 2800 sys.exit(main()) |
OLD | NEW |