Chromium Code Reviews| 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 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 244 command: A list containing the args to git. | 244 command: A list containing the args to git. |
| 245 | 245 |
| 246 Returns: | 246 Returns: |
| 247 A tuple of the output and return code. | 247 A tuple of the output and return code. |
| 248 """ | 248 """ |
| 249 command = ['git'] + command | 249 command = ['git'] + command |
| 250 | 250 |
| 251 return RunProcess(command) | 251 return RunProcess(command) |
| 252 | 252 |
| 253 | 253 |
| 254 def CheckRunGit(command): | |
| 255 """Run a git subcommand, returning its output and return code. Asserts if | |
| 256 the return code of the call is non-zero. | |
| 257 | |
| 258 Args: | |
| 259 command: A list containing the args to git. | |
| 260 | |
| 261 Returns: | |
| 262 A tuple of the output and return code. | |
| 263 """ | |
| 264 (output, return_code) = RunGit(command) | |
| 265 | |
| 266 assert not return_code, 'An error occurred while running'\ | |
| 267 ' "git %s"' % ' '.join(command) | |
| 268 return (output, return_code) | |
|
tonyg
2013/05/28 23:45:06
Since we know return_code is 0 at this point, I'd
shatch
2013/05/29 16:25:28
Done.
| |
| 269 | |
| 270 | |
| 254 def BuildWithMake(threads, targets, print_output): | 271 def BuildWithMake(threads, targets, print_output): |
| 255 cmd = ['make', 'BUILDTYPE=Release', '-j%d' % threads] + targets | 272 cmd = ['make', 'BUILDTYPE=Release', '-j%d' % threads] + targets |
| 256 | 273 |
| 257 (output, return_code) = RunProcess(cmd, print_output) | 274 (output, return_code) = RunProcess(cmd, print_output) |
| 258 | 275 |
| 259 return not return_code | 276 return not return_code |
| 260 | 277 |
| 261 | 278 |
| 262 def BuildWithNinja(threads, targets, print_output): | 279 def BuildWithNinja(threads, targets, print_output): |
| 263 cmd = ['ninja', '-C', os.path.join('out', 'Release'), | 280 cmd = ['ninja', '-C', os.path.join('out', 'Release'), |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 Args: | 336 Args: |
| 320 revision_range_end: The SHA1 for the end of the range. | 337 revision_range_end: The SHA1 for the end of the range. |
| 321 revision_range_start: The SHA1 for the beginning of the range. | 338 revision_range_start: The SHA1 for the beginning of the range. |
| 322 | 339 |
| 323 Returns: | 340 Returns: |
| 324 A list of the revisions between |revision_range_start| and | 341 A list of the revisions between |revision_range_start| and |
| 325 |revision_range_end| (inclusive). | 342 |revision_range_end| (inclusive). |
| 326 """ | 343 """ |
| 327 revision_range = '%s..%s' % (revision_range_start, revision_range_end) | 344 revision_range = '%s..%s' % (revision_range_start, revision_range_end) |
| 328 cmd = ['log', '--format=%H', '-10000', '--first-parent', revision_range] | 345 cmd = ['log', '--format=%H', '-10000', '--first-parent', revision_range] |
| 329 (log_output, return_code) = RunGit(cmd) | 346 (log_output, return_code) = CheckRunGit(cmd) |
| 330 | |
| 331 assert not return_code, 'An error occurred while running'\ | |
| 332 ' "git %s"' % ' '.join(cmd) | |
| 333 | 347 |
| 334 revision_hash_list = log_output.split() | 348 revision_hash_list = log_output.split() |
| 335 revision_hash_list.append(revision_range_start) | 349 revision_hash_list.append(revision_range_start) |
| 336 | 350 |
| 337 return revision_hash_list | 351 return revision_hash_list |
| 338 | 352 |
| 339 def SyncToRevision(self, revision, use_gclient=True): | 353 def SyncToRevision(self, revision, use_gclient=True): |
| 340 """Syncs to the specified revision. | 354 """Syncs to the specified revision. |
| 341 | 355 |
| 342 Args: | 356 Args: |
| 343 revision: The revision to sync to. | 357 revision: The revision to sync to. |
| 344 use_gclient: Specifies whether or not we should sync using gclient or | 358 use_gclient: Specifies whether or not we should sync using gclient or |
| 345 just use source control directly. | 359 just use source control directly. |
| 346 | 360 |
| 347 Returns: | 361 Returns: |
| 348 True if successful. | 362 True if successful. |
| 349 """ | 363 """ |
| 350 | 364 |
| 351 if use_gclient: | 365 if use_gclient: |
| 352 results = self.SyncToRevisionWithGClient(revision) | 366 results = self.SyncToRevisionWithGClient(revision) |
| 353 else: | 367 else: |
| 354 results = RunGit(['checkout', revision])[1] | 368 results = RunGit(['checkout', revision])[1] |
|
tonyg
2013/05/28 23:45:06
CheckRunGit?
shatch
2013/05/29 16:25:28
Not sure under which conditions checkout can fail.
| |
| 355 | 369 |
| 356 return not results | 370 return not results |
| 357 | 371 |
| 358 def ResolveToRevision(self, revision_to_check, depot, search): | 372 def ResolveToRevision(self, revision_to_check, depot, search): |
| 359 """If an SVN revision is supplied, try to resolve it to a git SHA1. | 373 """If an SVN revision is supplied, try to resolve it to a git SHA1. |
| 360 | 374 |
| 361 Args: | 375 Args: |
| 362 revision_to_check: The user supplied revision string that may need to be | 376 revision_to_check: The user supplied revision string that may need to be |
| 363 resolved to a git SHA1. | 377 resolved to a git SHA1. |
| 364 depot: The depot the revision_to_check is from. | 378 depot: The depot the revision_to_check is from. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 382 | 396 |
| 383 if search > 0: | 397 if search > 0: |
| 384 search_range = xrange(svn_revision, svn_revision + search, 1) | 398 search_range = xrange(svn_revision, svn_revision + search, 1) |
| 385 else: | 399 else: |
| 386 search_range = xrange(svn_revision, svn_revision + search, -1) | 400 search_range = xrange(svn_revision, svn_revision + search, -1) |
| 387 | 401 |
| 388 for i in search_range: | 402 for i in search_range: |
| 389 svn_pattern = 'git-svn-id: %s@%d' % (depot_svn, i) | 403 svn_pattern = 'git-svn-id: %s@%d' % (depot_svn, i) |
| 390 cmd = ['log', '--format=%H', '-1', '--grep', svn_pattern, 'origin/master'] | 404 cmd = ['log', '--format=%H', '-1', '--grep', svn_pattern, 'origin/master'] |
| 391 | 405 |
| 392 (log_output, return_code) = RunGit(cmd) | 406 (log_output, return_code) = CheckRunGit(cmd) |
| 393 | |
| 394 assert not return_code, 'An error occurred while running'\ | |
| 395 ' "git %s"' % ' '.join(cmd) | |
| 396 | 407 |
| 397 if not return_code: | 408 if not return_code: |
| 398 log_output = log_output.strip() | 409 log_output = log_output.strip() |
| 399 | 410 |
| 400 if log_output: | 411 if log_output: |
| 401 git_revision = log_output | 412 git_revision = log_output |
| 402 | 413 |
| 403 break | 414 break |
| 404 | 415 |
| 405 return git_revision | 416 return git_revision |
| 406 | 417 |
| 407 def IsInProperBranch(self): | 418 def IsInProperBranch(self): |
| 408 """Confirms they're in the master branch for performing the bisection. | 419 """Confirms they're in the master branch for performing the bisection. |
| 409 This is needed or gclient will fail to sync properly. | 420 This is needed or gclient will fail to sync properly. |
| 410 | 421 |
| 411 Returns: | 422 Returns: |
| 412 True if the current branch on src is 'master' | 423 True if the current branch on src is 'master' |
| 413 """ | 424 """ |
| 414 cmd = ['rev-parse', '--abbrev-ref', 'HEAD'] | 425 cmd = ['rev-parse', '--abbrev-ref', 'HEAD'] |
| 415 (log_output, return_code) = RunGit(cmd) | 426 (log_output, return_code) = CheckRunGit(cmd) |
| 416 | |
| 417 assert not return_code, 'An error occurred while running'\ | |
| 418 ' "git %s"' % ' '.join(cmd) | |
| 419 | 427 |
| 420 log_output = log_output.strip() | 428 log_output = log_output.strip() |
| 421 | 429 |
| 422 return log_output == "master" | 430 return log_output == "master" |
| 423 | 431 |
| 424 def SVNFindRev(self, revision): | 432 def SVNFindRev(self, revision): |
| 425 """Maps directly to the 'git svn find-rev' command. | 433 """Maps directly to the 'git svn find-rev' command. |
| 426 | 434 |
| 427 Args: | 435 Args: |
| 428 revision: The git SHA1 to use. | 436 revision: The git SHA1 to use. |
| 429 | 437 |
| 430 Returns: | 438 Returns: |
| 431 An integer changelist #, otherwise None. | 439 An integer changelist #, otherwise None. |
| 432 """ | 440 """ |
| 433 | 441 |
| 434 cmd = ['svn', 'find-rev', revision] | 442 cmd = ['svn', 'find-rev', revision] |
| 435 | 443 |
| 436 (output, return_code) = RunGit(cmd) | 444 (output, return_code) = CheckRunGit(cmd) |
| 437 | |
| 438 assert not return_code, 'An error occurred while running'\ | |
| 439 ' "git %s"' % ' '.join(cmd) | |
| 440 | 445 |
| 441 svn_revision = output.strip() | 446 svn_revision = output.strip() |
| 442 | 447 |
| 443 if IsStringInt(svn_revision): | 448 if IsStringInt(svn_revision): |
| 444 return int(svn_revision) | 449 return int(svn_revision) |
| 445 | 450 |
| 446 return None | 451 return None |
| 447 | 452 |
| 448 def QueryRevisionInfo(self, revision): | 453 def QueryRevisionInfo(self, revision): |
| 449 """Gathers information on a particular revision, such as author's name, | 454 """Gathers information on a particular revision, such as author's name, |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 460 'subject': %s, | 465 'subject': %s, |
| 461 } | 466 } |
| 462 """ | 467 """ |
| 463 commit_info = {} | 468 commit_info = {} |
| 464 | 469 |
| 465 formats = ['%cN', '%cE', '%s', '%cD'] | 470 formats = ['%cN', '%cE', '%s', '%cD'] |
| 466 targets = ['author', 'email', 'subject', 'date'] | 471 targets = ['author', 'email', 'subject', 'date'] |
| 467 | 472 |
| 468 for i in xrange(len(formats)): | 473 for i in xrange(len(formats)): |
| 469 cmd = ['log', '--format=%s' % formats[i], '-1', revision] | 474 cmd = ['log', '--format=%s' % formats[i], '-1', revision] |
| 470 (output, return_code) = RunGit(cmd) | 475 (output, return_code) = CheckRunGit(cmd) |
| 471 commit_info[targets[i]] = output.rstrip() | 476 commit_info[targets[i]] = output.rstrip() |
| 472 | 477 |
| 473 assert not return_code, 'An error occurred while running'\ | |
| 474 ' "git %s"' % ' '.join(cmd) | |
| 475 | |
| 476 return commit_info | 478 return commit_info |
| 477 | 479 |
| 478 def CheckoutFileAtRevision(self, file_name, revision): | 480 def CheckoutFileAtRevision(self, file_name, revision): |
| 479 """Performs a checkout on a file at the given revision. | 481 """Performs a checkout on a file at the given revision. |
| 480 | 482 |
| 481 Returns: | 483 Returns: |
| 482 True if successful. | 484 True if successful. |
| 483 """ | 485 """ |
| 484 return not RunGit(['checkout', revision, file_name])[1] | 486 return not RunGit(['checkout', revision, file_name])[1] |
| 485 | 487 |
| 486 def RevertFileToHead(self, file_name): | 488 def RevertFileToHead(self, file_name): |
| 487 """Unstages a file and returns it to HEAD. | 489 """Unstages a file and returns it to HEAD. |
| 488 | 490 |
| 489 Returns: | 491 Returns: |
| 490 True if successful. | 492 True if successful. |
| 491 """ | 493 """ |
| 492 # Reset doesn't seem to return 0 on success. | 494 # Reset doesn't seem to return 0 on success. |
| 493 RunGit(['reset', 'HEAD', bisect_utils.FILE_DEPS_GIT]) | 495 RunGit(['reset', 'HEAD', bisect_utils.FILE_DEPS_GIT]) |
| 494 | 496 |
| 495 return not RunGit(['checkout', bisect_utils.FILE_DEPS_GIT])[1] | 497 return not RunGit(['checkout', bisect_utils.FILE_DEPS_GIT])[1] |
| 496 | 498 |
| 499 def QueryFileRevisionHistory(self, filename, revision_start, revision_end): | |
| 500 """Returns a list of commits that modified this file. | |
| 501 | |
| 502 Args: | |
| 503 filename: Name of file. | |
| 504 revision_start: Start of revision range. | |
| 505 revision_end: End of revision range. | |
| 506 | |
| 507 Returns: | |
| 508 Returns a list of commits that touched this file. | |
| 509 """ | |
| 510 cmd = ['log', '--format=%H', '%s^1..%s' % (revision_start, revision_end), | |
| 511 filename] | |
| 512 (output, return_code) = CheckRunGit(cmd) | |
| 513 | |
| 514 return [o for o in output.split('\n') if o] | |
| 515 | |
| 497 class BisectPerformanceMetrics(object): | 516 class BisectPerformanceMetrics(object): |
| 498 """BisectPerformanceMetrics performs a bisection against a list of range | 517 """BisectPerformanceMetrics performs a bisection against a list of range |
| 499 of revisions to narrow down where performance regressions may have | 518 of revisions to narrow down where performance regressions may have |
| 500 occurred.""" | 519 occurred.""" |
| 501 | 520 |
| 502 def __init__(self, source_control, opts): | 521 def __init__(self, source_control, opts): |
| 503 super(BisectPerformanceMetrics, self).__init__() | 522 super(BisectPerformanceMetrics, self).__init__() |
| 504 | 523 |
| 505 self.opts = opts | 524 self.opts = opts |
| 506 self.source_control = source_control | 525 self.source_control = source_control |
| 507 self.src_cwd = os.getcwd() | 526 self.src_cwd = os.getcwd() |
| 508 self.depot_cwd = {} | 527 self.depot_cwd = {} |
| 509 self.cleanup_commands = [] | 528 self.cleanup_commands = [] |
| 529 self.warnings = [] | |
| 510 | 530 |
| 511 # This always starts true since the script grabs latest first. | 531 # This always starts true since the script grabs latest first. |
| 512 self.was_blink = True | 532 self.was_blink = True |
| 513 | 533 |
| 514 for d in DEPOT_NAMES: | 534 for d in DEPOT_NAMES: |
| 515 # The working directory of each depot is just the path to the depot, but | 535 # The working directory of each depot is just the path to the depot, but |
| 516 # since we're already in 'src', we can skip that part. | 536 # since we're already in 'src', we can skip that part. |
| 517 | 537 |
| 518 self.depot_cwd[d] = self.src_cwd + DEPOT_DEPS_NAME[d]['src'][3:] | 538 self.depot_cwd[d] = self.src_cwd + DEPOT_DEPS_NAME[d]['src'][3:] |
| 519 | 539 |
| (...skipping 517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1037 | 1057 |
| 1038 print | 1058 print |
| 1039 print 'Revisions to bisect on [%s]:' % depot | 1059 print 'Revisions to bisect on [%s]:' % depot |
| 1040 for revision_id in revision_list: | 1060 for revision_id in revision_list: |
| 1041 print ' -> %s' % (revision_id, ) | 1061 print ' -> %s' % (revision_id, ) |
| 1042 print | 1062 print |
| 1043 | 1063 |
| 1044 if self.opts.output_buildbot_annotations: | 1064 if self.opts.output_buildbot_annotations: |
| 1045 bisect_utils.OutputAnnotationStepClosed() | 1065 bisect_utils.OutputAnnotationStepClosed() |
| 1046 | 1066 |
| 1067 def NudgeRevisionsIfDEPSChange(self, bad_revision, good_revision): | |
| 1068 """Checks to see if changes to DEPS file occurred, and that the revision | |
| 1069 range also includes the change to .DEPS.git. If it doesn't, attempts to | |
| 1070 expand the revision range to include it. | |
| 1071 | |
| 1072 Args: | |
| 1073 bad_rev: First known bad revision. | |
| 1074 good_revision: Last known good revision. | |
| 1075 | |
| 1076 Returns: | |
| 1077 A tuple with the new bad and good revisions. | |
| 1078 """ | |
| 1079 if self.source_control.IsGit(): | |
| 1080 changes_to_deps = self.source_control.QueryFileRevisionHistory( | |
| 1081 'DEPS', good_revision, bad_revision) | |
| 1082 | |
| 1083 if changes_to_deps: | |
| 1084 # DEPS file was changed, search from the oldest change to DEPS file to | |
| 1085 # bad_revision to see if there are matching .DEPS.git changes. | |
| 1086 oldest_deps_change = changes_to_deps[-1] | |
| 1087 changes_to_gitdeps = self.source_control.QueryFileRevisionHistory( | |
| 1088 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) | |
| 1089 | |
| 1090 if len(changes_to_deps) != len(changes_to_gitdeps): | |
| 1091 # Grab the timestamp of the last DEPS change | |
| 1092 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] | |
| 1093 (output, return_code) = CheckRunGit(cmd) | |
| 1094 | |
| 1095 commit_time = int(output) | |
| 1096 | |
| 1097 # Try looking for a commit that touches the .DEPS.git file in the | |
| 1098 # next 15 minutes after the DEPS file change. | |
| 1099 cmd = ['log', '--format=%H', '-1', | |
| 1100 '--before=%d' % (commit_time + 900), '--after=%d' % commit_time, | |
| 1101 'origin/master', bisect_utils.FILE_DEPS_GIT] | |
| 1102 (output, return_code) = CheckRunGit(cmd) | |
| 1103 | |
| 1104 output = output.strip() | |
| 1105 if output: | |
| 1106 self.warnings.append('Detected change to DEPS and modified ' | |
| 1107 'revision range to include change to .DEPS.git') | |
| 1108 return (output, good_revision) | |
| 1109 else: | |
| 1110 self.warnings.append('Detected change to DEPS but couldn\'t find ' | |
| 1111 'matching change to .DEPS.git') | |
| 1112 return (bad_revision, good_revision) | |
| 1113 | |
| 1047 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): | 1114 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): |
| 1048 """Given known good and bad revisions, run a binary search on all | 1115 """Given known good and bad revisions, run a binary search on all |
| 1049 intermediate revisions to determine the CL where the performance regression | 1116 intermediate revisions to determine the CL where the performance regression |
| 1050 occurred. | 1117 occurred. |
| 1051 | 1118 |
| 1052 Args: | 1119 Args: |
| 1053 command_to_run: Specify the command to execute the performance test. | 1120 command_to_run: Specify the command to execute the performance test. |
| 1054 good_revision: Number/tag of the known good revision. | 1121 good_revision: Number/tag of the known good revision. |
| 1055 bad_revision: Number/tag of the known bad revision. | 1122 bad_revision: Number/tag of the known bad revision. |
| 1056 metric: The performance metric to monitor. | 1123 metric: The performance metric to monitor. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1098 'src', -100) | 1165 'src', -100) |
| 1099 | 1166 |
| 1100 if bad_revision is None: | 1167 if bad_revision is None: |
| 1101 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,) | 1168 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,) |
| 1102 return results | 1169 return results |
| 1103 | 1170 |
| 1104 if good_revision is None: | 1171 if good_revision is None: |
| 1105 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,) | 1172 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,) |
| 1106 return results | 1173 return results |
| 1107 | 1174 |
| 1175 (bad_revision, good_revision) = self.NudgeRevisionsIfDEPSChange( | |
| 1176 bad_revision, good_revision) | |
| 1177 | |
| 1108 if self.opts.output_buildbot_annotations: | 1178 if self.opts.output_buildbot_annotations: |
| 1109 bisect_utils.OutputAnnotationStepStart('Gathering Revisions') | 1179 bisect_utils.OutputAnnotationStepStart('Gathering Revisions') |
| 1110 | 1180 |
| 1111 print 'Gathering revision range for bisection.' | 1181 print 'Gathering revision range for bisection.' |
| 1112 | 1182 |
| 1113 # Retrieve a list of revisions to do bisection on. | 1183 # Retrieve a list of revisions to do bisection on. |
| 1114 src_revision_list = self.GetRevisionList(bad_revision, good_revision) | 1184 src_revision_list = self.GetRevisionList(bad_revision, good_revision) |
| 1115 | 1185 |
| 1116 if self.opts.output_buildbot_annotations: | 1186 if self.opts.output_buildbot_annotations: |
| 1117 bisect_utils.OutputAnnotationStepClosed() | 1187 bisect_utils.OutputAnnotationStepClosed() |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1373 good_std_dev = revision_data[first_working_revision]['value']['std_dev'] | 1443 good_std_dev = revision_data[first_working_revision]['value']['std_dev'] |
| 1374 good_mean = revision_data[first_working_revision]['value']['mean'] | 1444 good_mean = revision_data[first_working_revision]['value']['mean'] |
| 1375 bad_mean = revision_data[last_broken_revision]['value']['mean'] | 1445 bad_mean = revision_data[last_broken_revision]['value']['mean'] |
| 1376 | 1446 |
| 1377 # A standard deviation of 0 could indicate either insufficient runs | 1447 # A standard deviation of 0 could indicate either insufficient runs |
| 1378 # or a test that consistently returns the same value. | 1448 # or a test that consistently returns the same value. |
| 1379 if good_std_dev > 0: | 1449 if good_std_dev > 0: |
| 1380 deviations = math.fabs(bad_mean - good_mean) / good_std_dev | 1450 deviations = math.fabs(bad_mean - good_mean) / good_std_dev |
| 1381 | 1451 |
| 1382 if deviations < 1.5: | 1452 if deviations < 1.5: |
| 1383 print 'Warning: Regression was less than 1.5 standard deviations '\ | 1453 self.warnings.append('Regression was less than 1.5 standard ' |
| 1384 'from "good" value. Results may not be accurate.' | 1454 'deviations from "good" value. Results may not be accurate.') |
| 1385 print | |
| 1386 elif self.opts.repeat_test_count == 1: | 1455 elif self.opts.repeat_test_count == 1: |
| 1387 print 'Warning: Tests were only set to run once. This may be '\ | 1456 self.warnings.append('Tests were only set to run once. This ' |
| 1388 'insufficient to get meaningful results.' | 1457 'may be insufficient to get meaningful results.') |
| 1389 print | |
| 1390 | 1458 |
| 1391 # Check for any other possible regression ranges | 1459 # Check for any other possible regression ranges |
| 1392 prev_revision_data = revision_data_sorted[0][1] | 1460 prev_revision_data = revision_data_sorted[0][1] |
| 1393 prev_revision_id = revision_data_sorted[0][0] | 1461 prev_revision_id = revision_data_sorted[0][0] |
| 1394 possible_regressions = [] | 1462 possible_regressions = [] |
| 1395 for current_id, current_data in revision_data_sorted: | 1463 for current_id, current_data in revision_data_sorted: |
| 1396 if current_data['value']: | 1464 if current_data['value']: |
| 1397 prev_mean = prev_revision_data['value']['mean'] | 1465 prev_mean = prev_revision_data['value']['mean'] |
| 1398 cur_mean = current_data['value']['mean'] | 1466 cur_mean = current_data['value']['mean'] |
| 1399 | 1467 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1440 if percent_change is None: | 1508 if percent_change is None: |
| 1441 percent_change = 0 | 1509 percent_change = 0 |
| 1442 | 1510 |
| 1443 print ' %8s %s [%.2f%%, %s x std.dev]' % ( | 1511 print ' %8s %s [%.2f%%, %s x std.dev]' % ( |
| 1444 previous_data['depot'], previous_id, 100 * percent_change, | 1512 previous_data['depot'], previous_id, 100 * percent_change, |
| 1445 deviations) | 1513 deviations) |
| 1446 print ' %8s %s' % ( | 1514 print ' %8s %s' % ( |
| 1447 current_data['depot'], current_id) | 1515 current_data['depot'], current_id) |
| 1448 print | 1516 print |
| 1449 | 1517 |
| 1518 if self.warnings: | |
| 1519 print | |
| 1520 print 'The following warnings were generated:' | |
| 1521 print | |
| 1522 for w in self.warnings: | |
| 1523 print ' - %s' % w | |
| 1524 print | |
| 1525 | |
| 1450 if self.opts.output_buildbot_annotations: | 1526 if self.opts.output_buildbot_annotations: |
| 1451 bisect_utils.OutputAnnotationStepClosed() | 1527 bisect_utils.OutputAnnotationStepClosed() |
| 1452 | 1528 |
| 1453 | 1529 |
| 1454 def DetermineAndCreateSourceControl(): | 1530 def DetermineAndCreateSourceControl(): |
| 1455 """Attempts to determine the underlying source control workflow and returns | 1531 """Attempts to determine the underlying source control workflow and returns |
| 1456 a SourceControl object. | 1532 a SourceControl object. |
| 1457 | 1533 |
| 1458 Returns: | 1534 Returns: |
| 1459 An instance of a SourceControl object, or None if the current workflow | 1535 An instance of a SourceControl object, or None if the current workflow |
| 1460 is unsupported. | 1536 is unsupported. |
| 1461 """ | 1537 """ |
| 1462 | 1538 |
| 1463 (output, return_code) = RunGit(['rev-parse', '--is-inside-work-tree']) | 1539 (output, return_code) = RunGit(['rev-parse', '--is-inside-work-tree']) |
|
tonyg
2013/05/28 23:45:06
CheckRunGit?
shatch
2013/05/29 16:25:28
Prefer not to here, since a more descriptive error
| |
| 1464 | 1540 |
| 1465 if output.strip() == 'true': | 1541 if output.strip() == 'true': |
| 1466 return GitSourceControl() | 1542 return GitSourceControl() |
| 1467 | 1543 |
| 1468 return None | 1544 return None |
| 1469 | 1545 |
| 1470 | 1546 |
| 1471 def SetNinjaBuildSystemDefault(): | 1547 def SetNinjaBuildSystemDefault(): |
| 1472 """Makes ninja the default build system to be used by | 1548 """Makes ninja the default build system to be used by |
| 1473 the bisection script.""" | 1549 the bisection script.""" |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1729 | 1805 |
| 1730 if not(bisect_results['error']): | 1806 if not(bisect_results['error']): |
| 1731 return 0 | 1807 return 0 |
| 1732 else: | 1808 else: |
| 1733 print 'Error: ' + bisect_results['error'] | 1809 print 'Error: ' + bisect_results['error'] |
| 1734 print | 1810 print |
| 1735 return 1 | 1811 return 1 |
| 1736 | 1812 |
| 1737 if __name__ == '__main__': | 1813 if __name__ == '__main__': |
| 1738 sys.exit(main()) | 1814 sys.exit(main()) |
| OLD | NEW |