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