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 17 matching lines...) Expand all Loading... |
28 ./tools/bisect_perf_regression.py -c\ | 28 ./tools/bisect_perf_regression.py -c\ |
29 "out/Release/performance_ui_tests --gtest_filter=ShutdownTest.SimpleUserQuit"\ | 29 "out/Release/performance_ui_tests --gtest_filter=ShutdownTest.SimpleUserQuit"\ |
30 -g 1f6e67861535121c5c819c16a666f2436c207e7b\ | 30 -g 1f6e67861535121c5c819c16a666f2436c207e7b\ |
31 -b b732f23b4f81c382db0b23b9035f3dadc7d925bb\ | 31 -b b732f23b4f81c382db0b23b9035f3dadc7d925bb\ |
32 -m shutdown/simple-user-quit | 32 -m shutdown/simple-user-quit |
33 """ | 33 """ |
34 | 34 |
35 import copy | 35 import copy |
36 import errno | 36 import errno |
37 import hashlib | 37 import hashlib |
| 38 import logging |
38 import optparse | 39 import optparse |
39 import os | 40 import os |
40 import re | 41 import re |
41 import shlex | 42 import shlex |
42 import shutil | 43 import shutil |
43 import StringIO | 44 import StringIO |
44 import sys | 45 import sys |
45 import time | 46 import time |
46 import zipfile | 47 import zipfile |
47 | 48 |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 bucket_name: Google Storage bucket name. | 186 bucket_name: Google Storage bucket name. |
186 source_path: Source file path. | 187 source_path: Source file path. |
187 destination_path: Destination file path. | 188 destination_path: Destination file path. |
188 | 189 |
189 Returns: | 190 Returns: |
190 Downloaded file path if exists, otherwise None. | 191 Downloaded file path if exists, otherwise None. |
191 """ | 192 """ |
192 target_file = os.path.join(destination_path, os.path.basename(source_path)) | 193 target_file = os.path.join(destination_path, os.path.basename(source_path)) |
193 try: | 194 try: |
194 if cloud_storage.Exists(bucket_name, source_path): | 195 if cloud_storage.Exists(bucket_name, source_path): |
195 print 'Fetching file from gs//%s/%s ...' % (bucket_name, source_path) | 196 logging.info('Fetching file from gs//%s/%s ...', |
| 197 bucket_name, source_path) |
196 cloud_storage.Get(bucket_name, source_path, destination_path) | 198 cloud_storage.Get(bucket_name, source_path, destination_path) |
197 if os.path.exists(target_file): | 199 if os.path.exists(target_file): |
198 return target_file | 200 return target_file |
199 else: | 201 else: |
200 print ('File gs://%s/%s not found in cloud storage.' % ( | 202 logging.info('File gs://%s/%s not found in cloud storage.', |
201 bucket_name, source_path)) | 203 bucket_name, source_path) |
202 except Exception as e: | 204 except Exception as e: |
203 print 'Something went wrong while fetching file from cloud: %s' % e | 205 logging.warn('Something went wrong while fetching file from cloud: %s', e) |
204 if os.path.exists(target_file): | 206 if os.path.exists(target_file): |
205 os.remove(target_file) | 207 os.remove(target_file) |
206 return None | 208 return None |
207 | 209 |
208 | 210 |
209 # This is copied from build/scripts/common/chromium_utils.py. | 211 # This is copied from build/scripts/common/chromium_utils.py. |
210 def MaybeMakeDirectory(*path): | 212 def MaybeMakeDirectory(*path): |
211 """Creates an entire path, if it doesn't already exist.""" | 213 """Creates an entire path, if it doesn't already exist.""" |
212 file_path = os.path.join(*path) | 214 file_path = os.path.join(*path) |
213 try: | 215 try: |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 command = unzip_cmd + [filepath] | 252 command = unzip_cmd + [filepath] |
251 result = bisect_utils.RunProcess(command) | 253 result = bisect_utils.RunProcess(command) |
252 os.chdir(saved_dir) | 254 os.chdir(saved_dir) |
253 if result: | 255 if result: |
254 raise IOError('unzip failed: %s => %s' % (str(command), result)) | 256 raise IOError('unzip failed: %s => %s' % (str(command), result)) |
255 else: | 257 else: |
256 assert bisect_utils.IsWindowsHost() or bisect_utils.IsMacHost() | 258 assert bisect_utils.IsWindowsHost() or bisect_utils.IsMacHost() |
257 zf = zipfile.ZipFile(filename) | 259 zf = zipfile.ZipFile(filename) |
258 for name in zf.namelist(): | 260 for name in zf.namelist(): |
259 if verbose: | 261 if verbose: |
260 print 'Extracting %s' % name | 262 logging.info('Extracting %s', name) |
261 zf.extract(name, output_dir) | 263 zf.extract(name, output_dir) |
262 if bisect_utils.IsMacHost(): | 264 if bisect_utils.IsMacHost(): |
263 # Restore permission bits. | 265 # Restore permission bits. |
264 os.chmod(os.path.join(output_dir, name), | 266 os.chmod(os.path.join(output_dir, name), |
265 zf.getinfo(name).external_attr >> 16L) | 267 zf.getinfo(name).external_attr >> 16L) |
266 | 268 |
267 | 269 |
268 def WriteStringToFile(text, file_name): | 270 def WriteStringToFile(text, file_name): |
269 """Writes text to a file, raising an RuntimeError on failure.""" | 271 """Writes text to a file, raising an RuntimeError on failure.""" |
270 try: | 272 try: |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 # Note: Build is treated as PENDING if build number is not found | 366 # Note: Build is treated as PENDING if build number is not found |
365 # on the the try server. | 367 # on the the try server. |
366 build_status, status_link = request_build.GetBuildStatus( | 368 build_status, status_link = request_build.GetBuildStatus( |
367 build_num, bot_name, builder_host, builder_port) | 369 build_num, bot_name, builder_host, builder_port) |
368 if build_status == request_build.FAILED: | 370 if build_status == request_build.FAILED: |
369 return (None, 'Failed to produce build, log: %s' % status_link) | 371 return (None, 'Failed to produce build, log: %s' % status_link) |
370 elapsed_time = time.time() - start_time | 372 elapsed_time = time.time() - start_time |
371 if elapsed_time > max_timeout: | 373 if elapsed_time > max_timeout: |
372 return (None, 'Timed out: %ss without build' % max_timeout) | 374 return (None, 'Timed out: %ss without build' % max_timeout) |
373 | 375 |
374 print 'Time elapsed: %ss without build.' % elapsed_time | 376 logging.info('Time elapsed: %ss without build.', elapsed_time) |
375 time.sleep(poll_interval) | 377 time.sleep(poll_interval) |
376 # For some reason, mac bisect bots were not flushing stdout periodically. | 378 # For some reason, mac bisect bots were not flushing stdout periodically. |
377 # As a result buildbot command is timed-out. Flush stdout on all platforms | 379 # As a result buildbot command is timed-out. Flush stdout on all platforms |
378 # while waiting for build. | 380 # while waiting for build. |
379 sys.stdout.flush() | 381 sys.stdout.flush() |
380 | 382 |
381 | 383 |
382 def _UpdateV8Branch(deps_content): | 384 def _UpdateV8Branch(deps_content): |
383 """Updates V8 branch in DEPS file to process v8_bleeding_edge. | 385 """Updates V8 branch in DEPS file to process v8_bleeding_edge. |
384 | 386 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
435 new_data = re.sub(angle_rev_pattern, revision, deps_contents) | 437 new_data = re.sub(angle_rev_pattern, revision, deps_contents) |
436 else: | 438 else: |
437 # Check whether the depot and revision pattern in DEPS file deps | 439 # Check whether the depot and revision pattern in DEPS file deps |
438 # variable. e.g., | 440 # variable. e.g., |
439 # "src/third_party/angle": Var("chromium_git") + | 441 # "src/third_party/angle": Var("chromium_git") + |
440 # "/angle/angle.git@fa63e947cb3eccf463648d21a05d5002c9b8adfa",. | 442 # "/angle/angle.git@fa63e947cb3eccf463648d21a05d5002c9b8adfa",. |
441 angle_rev_pattern = re.compile( | 443 angle_rev_pattern = re.compile( |
442 r'(?<=angle\.git@)([a-fA-F0-9]{40})(?=")', re.MULTILINE) | 444 r'(?<=angle\.git@)([a-fA-F0-9]{40})(?=")', re.MULTILINE) |
443 match = re.search(angle_rev_pattern, deps_contents) | 445 match = re.search(angle_rev_pattern, deps_contents) |
444 if not match: | 446 if not match: |
445 print 'Could not find angle revision information in DEPS file.' | 447 logging.info('Could not find angle revision information in DEPS file.') |
446 return False | 448 return False |
447 new_data = re.sub(angle_rev_pattern, revision, deps_contents) | 449 new_data = re.sub(angle_rev_pattern, revision, deps_contents) |
448 # Write changes to DEPS file | 450 # Write changes to DEPS file |
449 WriteStringToFile(new_data, deps_file) | 451 WriteStringToFile(new_data, deps_file) |
450 return True | 452 return True |
451 except IOError, e: | 453 except IOError, e: |
452 print 'Something went wrong while updating DEPS file, %s' % e | 454 logging.warn('Something went wrong while updating DEPS file, %s', e) |
453 return False | 455 return False |
454 | 456 |
455 | 457 |
456 def _TryParseHistogramValuesFromOutput(metric, text): | 458 def _TryParseHistogramValuesFromOutput(metric, text): |
457 """Attempts to parse a metric in the format HISTOGRAM <graph: <trace>. | 459 """Attempts to parse a metric in the format HISTOGRAM <graph: <trace>. |
458 | 460 |
459 Args: | 461 Args: |
460 metric: The metric as a list of [<trace>, <value>] strings. | 462 metric: The metric as a list of [<trace>, <value>] strings. |
461 text: The text to parse the metric values from. | 463 text: The text to parse the metric values from. |
462 | 464 |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
750 '-n', bisect_job_name, | 752 '-n', bisect_job_name, |
751 '--svn_repo=%s' % SVN_REPO_URL, | 753 '--svn_repo=%s' % SVN_REPO_URL, |
752 '--diff=%s' % patch_content | 754 '--diff=%s' % patch_content |
753 ] | 755 ] |
754 # Execute try job to build revision. | 756 # Execute try job to build revision. |
755 output, returncode = bisect_utils.RunGit(try_cmd) | 757 output, returncode = bisect_utils.RunGit(try_cmd) |
756 | 758 |
757 if returncode: | 759 if returncode: |
758 raise RunGitError('Could not execute tryjob: %s.\n Error: %s' % ( | 760 raise RunGitError('Could not execute tryjob: %s.\n Error: %s' % ( |
759 'git %s' % ' '.join(try_cmd), output)) | 761 'git %s' % ' '.join(try_cmd), output)) |
760 print ('Try job successfully submitted.\n TryJob Details: %s\n%s' % ( | 762 logging.info('Try job successfully submitted.\n TryJob Details: %s\n%s', |
761 'git %s' % ' '.join(try_cmd), output)) | 763 'git %s' % ' '.join(try_cmd), output) |
762 finally: | 764 finally: |
763 # Delete patch file if exists | 765 # Delete patch file if exists |
764 try: | 766 try: |
765 os.remove(BISECT_PATCH_FILE) | 767 os.remove(BISECT_PATCH_FILE) |
766 except OSError as e: | 768 except OSError as e: |
767 if e.errno != errno.ENOENT: | 769 if e.errno != errno.ENOENT: |
768 raise | 770 raise |
769 # Checkout master branch and delete bisect-tryjob branch. | 771 # Checkout master branch and delete bisect-tryjob branch. |
770 bisect_utils.RunGit(['checkout', '-f', BISECT_MASTER_BRANCH]) | 772 bisect_utils.RunGit(['checkout', '-f', BISECT_MASTER_BRANCH]) |
771 bisect_utils.RunGit(['branch', '-D', BISECT_TRYJOB_BRANCH]) | 773 bisect_utils.RunGit(['branch', '-D', BISECT_TRYJOB_BRANCH]) |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 self.warnings.append(warning_text) | 969 self.warnings.append(warning_text) |
968 else: | 970 else: |
969 results[depot_name] = None | 971 results[depot_name] = None |
970 return results | 972 return results |
971 except ImportError: | 973 except ImportError: |
972 deps_file_contents = ReadStringFromFile(deps_file) | 974 deps_file_contents = ReadStringFromFile(deps_file) |
973 parse_results = _ParseRevisionsFromDEPSFileManually(deps_file_contents) | 975 parse_results = _ParseRevisionsFromDEPSFileManually(deps_file_contents) |
974 results = {} | 976 results = {} |
975 for depot_name, depot_revision in parse_results.iteritems(): | 977 for depot_name, depot_revision in parse_results.iteritems(): |
976 depot_revision = depot_revision.strip('@') | 978 depot_revision = depot_revision.strip('@') |
977 print depot_name, depot_revision | 979 logging.warn(depot_name, depot_revision) |
978 for cur_name, cur_data in bisect_utils.DEPOT_DEPS_NAME.iteritems(): | 980 for cur_name, cur_data in bisect_utils.DEPOT_DEPS_NAME.iteritems(): |
979 if (cur_data.has_key('deps_var') and | 981 if (cur_data.has_key('deps_var') and |
980 cur_data['deps_var'] == depot_name): | 982 cur_data['deps_var'] == depot_name): |
981 src_name = cur_name | 983 src_name = cur_name |
982 results[src_name] = depot_revision | 984 results[src_name] = depot_revision |
983 break | 985 break |
984 return results | 986 return results |
985 | 987 |
986 def _Get3rdPartyRevisions(self, depot): | 988 def _Get3rdPartyRevisions(self, depot): |
987 """Parses the DEPS file to determine WebKit/v8/etc... versions. | 989 """Parses the DEPS file to determine WebKit/v8/etc... versions. |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1160 target_build_output_dir = os.path.join(abs_build_dir, build_type) | 1162 target_build_output_dir = os.path.join(abs_build_dir, build_type) |
1161 ExtractZip(downloaded_file, abs_build_dir) | 1163 ExtractZip(downloaded_file, abs_build_dir) |
1162 if not os.path.exists(output_dir): | 1164 if not os.path.exists(output_dir): |
1163 # Due to recipe changes, the builds extract folder contains | 1165 # Due to recipe changes, the builds extract folder contains |
1164 # out/Release instead of full-build-<platform>/Release. | 1166 # out/Release instead of full-build-<platform>/Release. |
1165 if os.path.exists(os.path.join(abs_build_dir, 'out', build_type)): | 1167 if os.path.exists(os.path.join(abs_build_dir, 'out', build_type)): |
1166 output_dir = os.path.join(abs_build_dir, 'out', build_type) | 1168 output_dir = os.path.join(abs_build_dir, 'out', build_type) |
1167 else: | 1169 else: |
1168 raise IOError('Missing extracted folder %s ' % output_dir) | 1170 raise IOError('Missing extracted folder %s ' % output_dir) |
1169 | 1171 |
1170 print 'Moving build from %s to %s' % ( | 1172 logging.info('Moving build from %s to %s', |
1171 output_dir, target_build_output_dir) | 1173 output_dir, target_build_output_dir) |
1172 shutil.move(output_dir, target_build_output_dir) | 1174 shutil.move(output_dir, target_build_output_dir) |
1173 return True | 1175 return True |
1174 except Exception as e: | 1176 except Exception as e: |
1175 print 'Something went wrong while extracting archive file: %s' % e | 1177 logging.info('Something went wrong while extracting archive file: %s', e) |
1176 self.BackupOrRestoreOutputDirectory(restore=True) | 1178 self.BackupOrRestoreOutputDirectory(restore=True) |
1177 # Cleanup any leftovers from unzipping. | 1179 # Cleanup any leftovers from unzipping. |
1178 if os.path.exists(output_dir): | 1180 if os.path.exists(output_dir): |
1179 RemoveDirectoryTree(output_dir) | 1181 RemoveDirectoryTree(output_dir) |
1180 finally: | 1182 finally: |
1181 # Delete downloaded archive | 1183 # Delete downloaded archive |
1182 if os.path.exists(downloaded_file): | 1184 if os.path.exists(downloaded_file): |
1183 os.remove(downloaded_file) | 1185 os.remove(downloaded_file) |
1184 return False | 1186 return False |
1185 | 1187 |
(...skipping 28 matching lines...) Expand all Loading... |
1214 bot_name = self._GetBuilderName(self.opts.target_platform) | 1216 bot_name = self._GetBuilderName(self.opts.target_platform) |
1215 build_timeout = self._GetBuilderBuildTime() | 1217 build_timeout = self._GetBuilderBuildTime() |
1216 target_file = None | 1218 target_file = None |
1217 try: | 1219 try: |
1218 # Execute try job request to build revision with patch. | 1220 # Execute try job request to build revision with patch. |
1219 _BuilderTryjob(git_revision, bot_name, build_request_id, patch) | 1221 _BuilderTryjob(git_revision, bot_name, build_request_id, patch) |
1220 target_file, error_msg = _WaitUntilBuildIsReady( | 1222 target_file, error_msg = _WaitUntilBuildIsReady( |
1221 fetch_build, bot_name, self.opts.builder_host, | 1223 fetch_build, bot_name, self.opts.builder_host, |
1222 self.opts.builder_port, build_request_id, build_timeout) | 1224 self.opts.builder_port, build_request_id, build_timeout) |
1223 if not target_file: | 1225 if not target_file: |
1224 print '%s [revision: %s]' % (error_msg, git_revision) | 1226 logging.warn('%s [revision: %s]', error_msg, git_revision) |
1225 except RunGitError as e: | 1227 except RunGitError as e: |
1226 print ('Failed to post builder try job for revision: [%s].\n' | 1228 logging.warn('Failed to post builder try job for revision: [%s].\n' |
1227 'Error: %s' % (git_revision, e)) | 1229 'Error: %s', git_revision, e) |
1228 | 1230 |
1229 return target_file | 1231 return target_file |
1230 | 1232 |
1231 @staticmethod | 1233 @staticmethod |
1232 def _GetBuilderName(target_platform): | 1234 def _GetBuilderName(target_platform): |
1233 """Gets builder bot name and build time in seconds based on platform.""" | 1235 """Gets builder bot name and build time in seconds based on platform.""" |
1234 if bisect_utils.IsWindowsHost(): | 1236 if bisect_utils.IsWindowsHost(): |
1235 return 'win_perf_bisect_builder' | 1237 return 'win_perf_bisect_builder' |
1236 if bisect_utils.IsLinuxHost(): | 1238 if bisect_utils.IsLinuxHost(): |
1237 if target_platform == 'android': | 1239 if target_platform == 'android': |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1275 """ | 1277 """ |
1276 # Check whether the depot and revision pattern in DEPS file vars | 1278 # Check whether the depot and revision pattern in DEPS file vars |
1277 # e.g. for webkit the format is "webkit_revision": "12345". | 1279 # e.g. for webkit the format is "webkit_revision": "12345". |
1278 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key, | 1280 deps_revision = re.compile(r'(?<="%s": ")([0-9]+)(?=")' % deps_key, |
1279 re.MULTILINE) | 1281 re.MULTILINE) |
1280 new_data = None | 1282 new_data = None |
1281 if re.search(deps_revision, deps_contents): | 1283 if re.search(deps_revision, deps_contents): |
1282 commit_position = source_control.GetCommitPosition( | 1284 commit_position = source_control.GetCommitPosition( |
1283 git_revision, self.depot_registry.GetDepotDir(depot)) | 1285 git_revision, self.depot_registry.GetDepotDir(depot)) |
1284 if not commit_position: | 1286 if not commit_position: |
1285 print 'Could not determine commit position for %s' % git_revision | 1287 logging.warn('Could not determine commit position for %s', git_revision) |
1286 return None | 1288 return None |
1287 # Update the revision information for the given depot | 1289 # Update the revision information for the given depot |
1288 new_data = re.sub(deps_revision, str(commit_position), deps_contents) | 1290 new_data = re.sub(deps_revision, str(commit_position), deps_contents) |
1289 else: | 1291 else: |
1290 # Check whether the depot and revision pattern in DEPS file vars | 1292 # Check whether the depot and revision pattern in DEPS file vars |
1291 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..". | 1293 # e.g. for webkit the format is "webkit_revision": "559a6d4ab7a84c539..". |
1292 deps_revision = re.compile( | 1294 deps_revision = re.compile( |
1293 r'(?<=["\']%s["\']: ["\'])([a-fA-F0-9]{40})(?=["\'])' % deps_key, | 1295 r'(?<=["\']%s["\']: ["\'])([a-fA-F0-9]{40})(?=["\'])' % deps_key, |
1294 re.MULTILINE) | 1296 re.MULTILINE) |
1295 if re.search(deps_revision, deps_contents): | 1297 if re.search(deps_revision, deps_contents): |
(...skipping 21 matching lines...) Expand all Loading... |
1317 | 1319 |
1318 Returns: | 1320 Returns: |
1319 True if DEPS file is modified successfully, otherwise False. | 1321 True if DEPS file is modified successfully, otherwise False. |
1320 """ | 1322 """ |
1321 if not os.path.exists(deps_file): | 1323 if not os.path.exists(deps_file): |
1322 return False | 1324 return False |
1323 | 1325 |
1324 deps_var = bisect_utils.DEPOT_DEPS_NAME[depot]['deps_var'] | 1326 deps_var = bisect_utils.DEPOT_DEPS_NAME[depot]['deps_var'] |
1325 # Don't update DEPS file if deps_var is not set in DEPOT_DEPS_NAME. | 1327 # Don't update DEPS file if deps_var is not set in DEPOT_DEPS_NAME. |
1326 if not deps_var: | 1328 if not deps_var: |
1327 print 'DEPS update not supported for Depot: %s', depot | 1329 logging.warn('DEPS update not supported for Depot: %s', depot) |
1328 return False | 1330 return False |
1329 | 1331 |
1330 # Hack for Angle repository. In the DEPS file, "vars" dictionary variable | 1332 # Hack for Angle repository. In the DEPS file, "vars" dictionary variable |
1331 # contains "angle_revision" key that holds git hash instead of SVN revision. | 1333 # contains "angle_revision" key that holds git hash instead of SVN revision. |
1332 # And sometime "angle_revision" key is not specified in "vars" variable. | 1334 # And sometime "angle_revision" key is not specified in "vars" variable. |
1333 # In such cases check, "deps" dictionary variable that matches | 1335 # In such cases check, "deps" dictionary variable that matches |
1334 # angle.git@[a-fA-F0-9]{40}$ and replace git hash. | 1336 # angle.git@[a-fA-F0-9]{40}$ and replace git hash. |
1335 if depot == 'angle': | 1337 if depot == 'angle': |
1336 return _UpdateDEPSForAngle(revision, depot, deps_file) | 1338 return _UpdateDEPSForAngle(revision, depot, deps_file) |
1337 | 1339 |
1338 try: | 1340 try: |
1339 deps_contents = ReadStringFromFile(deps_file) | 1341 deps_contents = ReadStringFromFile(deps_file) |
1340 updated_deps_content = self.UpdateDepsContents( | 1342 updated_deps_content = self.UpdateDepsContents( |
1341 deps_contents, depot, revision, deps_var) | 1343 deps_contents, depot, revision, deps_var) |
1342 # Write changes to DEPS file | 1344 # Write changes to DEPS file |
1343 if updated_deps_content: | 1345 if updated_deps_content: |
1344 WriteStringToFile(updated_deps_content, deps_file) | 1346 WriteStringToFile(updated_deps_content, deps_file) |
1345 return True | 1347 return True |
1346 except IOError, e: | 1348 except IOError, e: |
1347 print 'Something went wrong while updating DEPS file. [%s]' % e | 1349 logging.warn('Something went wrong while updating DEPS file. [%s]', e) |
1348 return False | 1350 return False |
1349 | 1351 |
1350 def CreateDEPSPatch(self, depot, revision): | 1352 def CreateDEPSPatch(self, depot, revision): |
1351 """Modifies DEPS and returns diff as text. | 1353 """Modifies DEPS and returns diff as text. |
1352 | 1354 |
1353 Args: | 1355 Args: |
1354 depot: Current depot being bisected. | 1356 depot: Current depot being bisected. |
1355 revision: A git hash revision of the dependency repository. | 1357 revision: A git hash revision of the dependency repository. |
1356 | 1358 |
1357 Returns: | 1359 Returns: |
(...skipping 906 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2264 if metric_increased: | 2266 if metric_increased: |
2265 message += "and the metric appears to have increased. " | 2267 message += "and the metric appears to have increased. " |
2266 else: | 2268 else: |
2267 message += "and the metric appears to have decreased. " | 2269 message += "and the metric appears to have decreased. " |
2268 if ((higher_is_better and metric_increased) or | 2270 if ((higher_is_better and metric_increased) or |
2269 (not higher_is_better and not metric_increased)): | 2271 (not higher_is_better and not metric_increased)): |
2270 error = (message + 'Then, the test results for the ends of the given ' | 2272 error = (message + 'Then, the test results for the ends of the given ' |
2271 '\'good\' - \'bad\' range of revisions represent an ' | 2273 '\'good\' - \'bad\' range of revisions represent an ' |
2272 'improvement (and not a regression).') | 2274 'improvement (and not a regression).') |
2273 return BisectResults(error=error) | 2275 return BisectResults(error=error) |
2274 print message, "Therefore we continue to bisect." | 2276 logging.info(message + "Therefore we continue to bisect.") |
2275 | 2277 |
2276 bisect_state = BisectState(target_depot, revision_list) | 2278 bisect_state = BisectState(target_depot, revision_list) |
2277 revision_states = bisect_state.GetRevisionStates() | 2279 revision_states = bisect_state.GetRevisionStates() |
2278 | 2280 |
2279 min_revision = 0 | 2281 min_revision = 0 |
2280 max_revision = len(revision_states) - 1 | 2282 max_revision = len(revision_states) - 1 |
2281 # Check how likely it is that the good and bad results are different | 2283 # Check how likely it is that the good and bad results are different |
2282 # beyond chance-induced variation. | 2284 # beyond chance-induced variation. |
2283 if not self.opts.debug_ignore_regression_confidence: | 2285 if not self.opts.debug_ignore_regression_confidence: |
2284 error = _CheckRegressionConfidenceError(good_revision, | 2286 error = _CheckRegressionConfidenceError(good_revision, |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2763 opts.metric = metric_values | 2765 opts.metric = metric_values |
2764 | 2766 |
2765 opts.repeat_test_count = min(max(opts.repeat_test_count, 1), 100) | 2767 opts.repeat_test_count = min(max(opts.repeat_test_count, 1), 100) |
2766 opts.max_time_minutes = min(max(opts.max_time_minutes, 1), 60) | 2768 opts.max_time_minutes = min(max(opts.max_time_minutes, 1), 60) |
2767 opts.truncate_percent = min(max(opts.truncate_percent, 0), 25) | 2769 opts.truncate_percent = min(max(opts.truncate_percent, 0), 25) |
2768 opts.truncate_percent = opts.truncate_percent / 100.0 | 2770 opts.truncate_percent = opts.truncate_percent / 100.0 |
2769 | 2771 |
2770 return opts | 2772 return opts |
2771 | 2773 |
2772 | 2774 |
| 2775 def _ConfigureLogging(): |
| 2776 """Trivial logging config. |
| 2777 |
| 2778 Configures logging to output any messages at or above INFO to standard out, |
| 2779 without any additional formatting. |
| 2780 """ |
| 2781 logging_format = '%(message)s' |
| 2782 logging.basicConfig( |
| 2783 stream=logging.sys.stdout, level=logging.INFO, format=logging_format) |
| 2784 |
| 2785 |
2773 def main(): | 2786 def main(): |
2774 | 2787 _ConfigureLogging() |
2775 try: | 2788 try: |
2776 opts = BisectOptions() | 2789 opts = BisectOptions() |
2777 opts.ParseCommandLine() | 2790 opts.ParseCommandLine() |
2778 | 2791 |
2779 if opts.extra_src: | 2792 if opts.extra_src: |
2780 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) | 2793 extra_src = bisect_utils.LoadExtraSrc(opts.extra_src) |
2781 if not extra_src: | 2794 if not extra_src: |
2782 raise RuntimeError('Invalid or missing --extra_src.') | 2795 raise RuntimeError('Invalid or missing --extra_src.') |
2783 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) | 2796 bisect_utils.AddAdditionalDepotInfo(extra_src.GetAdditionalDepotInfo()) |
2784 | 2797 |
(...skipping 29 matching lines...) Expand all Loading... |
2814 raise RuntimeError(results.error) | 2827 raise RuntimeError(results.error) |
2815 bisect_printer.FormatAndPrintResults(results) | 2828 bisect_printer.FormatAndPrintResults(results) |
2816 return 0 | 2829 return 0 |
2817 finally: | 2830 finally: |
2818 bisect_test.PerformCleanup() | 2831 bisect_test.PerformCleanup() |
2819 except RuntimeError, e: | 2832 except RuntimeError, e: |
2820 if opts.output_buildbot_annotations: | 2833 if opts.output_buildbot_annotations: |
2821 # The perf dashboard scrapes the "results" step in order to comment on | 2834 # The perf dashboard scrapes the "results" step in order to comment on |
2822 # bugs. If you change this, please update the perf dashboard as well. | 2835 # bugs. If you change this, please update the perf dashboard as well. |
2823 bisect_utils.OutputAnnotationStepStart('Results') | 2836 bisect_utils.OutputAnnotationStepStart('Results') |
2824 print 'Error: %s' % e.message | 2837 print 'Error: ', e.message |
| 2838 logging.warn('A RuntimeError was caught: %s', e.message) |
2825 if opts.output_buildbot_annotations: | 2839 if opts.output_buildbot_annotations: |
2826 bisect_utils.OutputAnnotationStepClosed() | 2840 bisect_utils.OutputAnnotationStepClosed() |
2827 return 1 | 2841 return 1 |
2828 | 2842 |
2829 | 2843 |
2830 if __name__ == '__main__': | 2844 if __name__ == '__main__': |
2831 sys.exit(main()) | 2845 sys.exit(main()) |
OLD | NEW |