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 28 matching lines...) Expand all Loading... |
39 import datetime | 39 import datetime |
40 import errno | 40 import errno |
41 import hashlib | 41 import hashlib |
42 import math | 42 import math |
43 import optparse | 43 import optparse |
44 import os | 44 import os |
45 import re | 45 import re |
46 import shlex | 46 import shlex |
47 import shutil | 47 import shutil |
48 import StringIO | 48 import StringIO |
49 import subprocess | |
50 import sys | 49 import sys |
51 import time | 50 import time |
52 import zipfile | 51 import zipfile |
53 | 52 |
54 sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry')) | 53 sys.path.append(os.path.join(os.path.dirname(__file__), 'telemetry')) |
55 | 54 |
56 from auto_bisect import bisect_utils | 55 from auto_bisect import bisect_utils |
57 from auto_bisect import post_perf_builder_job as bisect_builder | 56 from auto_bisect import post_perf_builder_job as bisect_builder |
| 57 from auto_bisect import source_control as source_control_module |
58 from telemetry.util import cloud_storage | 58 from telemetry.util import cloud_storage |
59 | 59 |
60 # The additional repositories that might need to be bisected. | 60 # The additional repositories that might need to be bisected. |
61 # If the repository has any dependant repositories (such as skia/src needs | 61 # If the repository has any dependant repositories (such as skia/src needs |
62 # skia/include and skia/gyp to be updated), specify them in the 'depends' | 62 # skia/include and skia/gyp to be updated), specify them in the 'depends' |
63 # so that they're synced appropriately. | 63 # so that they're synced appropriately. |
64 # Format is: | 64 # Format is: |
65 # src: path to the working directory. | 65 # src: path to the working directory. |
66 # recurse: True if this repositry will get bisected. | 66 # recurse: True if this repositry will get bisected. |
67 # depends: A list of other repositories that are actually part of the same | 67 # depends: A list of other repositories that are actually part of the same |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 "recurse" : False, | 136 "recurse" : False, |
137 "svn" : "http://skia.googlecode.com/svn/trunk/gyp", | 137 "svn" : "http://skia.googlecode.com/svn/trunk/gyp", |
138 "depends" : None, | 138 "depends" : None, |
139 "from" : ['chromium'], | 139 "from" : ['chromium'], |
140 'viewvc': 'https://code.google.com/p/skia/source/detail?r=', | 140 'viewvc': 'https://code.google.com/p/skia/source/detail?r=', |
141 'deps_var': 'None' | 141 'deps_var': 'None' |
142 }, | 142 }, |
143 } | 143 } |
144 | 144 |
145 DEPOT_NAMES = DEPOT_DEPS_NAME.keys() | 145 DEPOT_NAMES = DEPOT_DEPS_NAME.keys() |
| 146 |
146 CROS_SDK_PATH = os.path.join('..', 'cros', 'chromite', 'bin', 'cros_sdk') | 147 CROS_SDK_PATH = os.path.join('..', 'cros', 'chromite', 'bin', 'cros_sdk') |
147 CROS_VERSION_PATTERN = 'new version number from %s' | |
148 CROS_CHROMEOS_PATTERN = 'chromeos-base/chromeos-chrome' | 148 CROS_CHROMEOS_PATTERN = 'chromeos-base/chromeos-chrome' |
149 CROS_TEST_KEY_PATH = os.path.join('..', 'cros', 'chromite', 'ssh_keys', | 149 CROS_TEST_KEY_PATH = os.path.join('..', 'cros', 'chromite', 'ssh_keys', |
150 'testing_rsa') | 150 'testing_rsa') |
151 CROS_SCRIPT_KEY_PATH = os.path.join('..', 'cros', 'src', 'scripts', | 151 CROS_SCRIPT_KEY_PATH = os.path.join('..', 'cros', 'src', 'scripts', |
152 'mod_for_test_scripts', 'ssh_keys', | 152 'mod_for_test_scripts', 'ssh_keys', |
153 'testing_rsa') | 153 'testing_rsa') |
154 | 154 |
155 BUILD_RESULT_SUCCEED = 0 | 155 BUILD_RESULT_SUCCEED = 0 |
156 BUILD_RESULT_FAIL = 1 | 156 BUILD_RESULT_FAIL = 1 |
157 BUILD_RESULT_SKIPPED = 2 | 157 BUILD_RESULT_SKIPPED = 2 |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 def CalculateStandardError(values): | 406 def CalculateStandardError(values): |
407 """Calculates the standard error of a list of values.""" | 407 """Calculates the standard error of a list of values.""" |
408 if len(values) <= 1: | 408 if len(values) <= 1: |
409 return 0.0 | 409 return 0.0 |
410 | 410 |
411 std_dev = CalculateStandardDeviation(values) | 411 std_dev = CalculateStandardDeviation(values) |
412 | 412 |
413 return std_dev / math.sqrt(len(values)) | 413 return std_dev / math.sqrt(len(values)) |
414 | 414 |
415 | 415 |
416 def IsStringFloat(string_to_check): | |
417 """Checks whether or not the given string can be converted to a floating | |
418 point number. | |
419 | |
420 Args: | |
421 string_to_check: Input string to check if it can be converted to a float. | |
422 | |
423 Returns: | |
424 True if the string can be converted to a float. | |
425 """ | |
426 try: | |
427 float(string_to_check) | |
428 | |
429 return True | |
430 except ValueError: | |
431 return False | |
432 | |
433 | |
434 def IsStringInt(string_to_check): | |
435 """Checks whether or not the given string can be converted to a integer. | |
436 | |
437 Args: | |
438 string_to_check: Input string to check if it can be converted to an int. | |
439 | |
440 Returns: | |
441 True if the string can be converted to an int. | |
442 """ | |
443 try: | |
444 int(string_to_check) | |
445 | |
446 return True | |
447 except ValueError: | |
448 return False | |
449 | |
450 | |
451 def IsWindowsHost(): | |
452 """Checks whether or not the script is running on Windows. | |
453 | |
454 Returns: | |
455 True if running on Windows. | |
456 """ | |
457 return sys.platform == 'cygwin' or sys.platform.startswith('win') | |
458 | |
459 | |
460 def Is64BitWindows(): | |
461 """Returns whether or not Windows is a 64-bit version. | |
462 | |
463 Returns: | |
464 True if Windows is 64-bit, False if 32-bit. | |
465 """ | |
466 platform = os.environ['PROCESSOR_ARCHITECTURE'] | |
467 try: | |
468 platform = os.environ['PROCESSOR_ARCHITEW6432'] | |
469 except KeyError: | |
470 # Must not be running in WoW64, so PROCESSOR_ARCHITECTURE is correct | |
471 pass | |
472 | |
473 return platform in ['AMD64', 'I64'] | |
474 | |
475 | |
476 def IsLinuxHost(): | |
477 """Checks whether or not the script is running on Linux. | |
478 | |
479 Returns: | |
480 True if running on Linux. | |
481 """ | |
482 return sys.platform.startswith('linux') | |
483 | |
484 | |
485 def IsMacHost(): | |
486 """Checks whether or not the script is running on Mac. | |
487 | |
488 Returns: | |
489 True if running on Mac. | |
490 """ | |
491 return sys.platform.startswith('darwin') | |
492 | 416 |
493 | 417 |
494 def GetSHA1HexDigest(contents): | 418 def GetSHA1HexDigest(contents): |
495 """Returns secured hash containing hexadecimal for the given contents.""" | 419 """Returns secured hash containing hexadecimal for the given contents.""" |
496 return hashlib.sha1(contents).hexdigest() | 420 return hashlib.sha1(contents).hexdigest() |
497 | 421 |
498 | 422 |
499 def GetZipFileName(build_revision=None, target_arch='ia32', patch_sha=None): | 423 def GetZipFileName(build_revision=None, target_arch='ia32', patch_sha=None): |
500 """Gets the archive file name for the given revision.""" | 424 """Gets the archive file name for the given revision.""" |
501 def PlatformName(): | 425 def PlatformName(): |
502 """Return a string to be used in paths for the platform.""" | 426 """Return a string to be used in paths for the platform.""" |
503 if IsWindowsHost(): | 427 if bisect_utils.IsWindowsHost(): |
504 # Build archive for x64 is still stored with 'win32'suffix | 428 # Build archive for x64 is still stored with 'win32'suffix |
505 # (chromium_utils.PlatformName()). | 429 # (chromium_utils.PlatformName()). |
506 if Is64BitWindows() and target_arch == 'x64': | 430 if bisect_utils.Is64BitWindows() and target_arch == 'x64': |
507 return 'win32' | 431 return 'win32' |
508 return 'win32' | 432 return 'win32' |
509 if IsLinuxHost(): | 433 if bisect_utils.IsLinuxHost(): |
510 # Android builds too are archived with full-build-linux* prefix. | 434 # Android builds too are archived with full-build-linux* prefix. |
511 return 'linux' | 435 return 'linux' |
512 if IsMacHost(): | 436 if bisect_utils.IsMacHost(): |
513 return 'mac' | 437 return 'mac' |
514 raise NotImplementedError('Unknown platform "%s".' % sys.platform) | 438 raise NotImplementedError('Unknown platform "%s".' % sys.platform) |
515 | 439 |
516 base_name = 'full-build-%s' % PlatformName() | 440 base_name = 'full-build-%s' % PlatformName() |
517 if not build_revision: | 441 if not build_revision: |
518 return base_name | 442 return base_name |
519 if patch_sha: | 443 if patch_sha: |
520 build_revision = '%s_%s' % (build_revision , patch_sha) | 444 build_revision = '%s_%s' % (build_revision , patch_sha) |
521 return '%s_%s.zip' % (base_name, build_revision) | 445 return '%s_%s.zip' % (base_name, build_revision) |
522 | 446 |
523 | 447 |
524 def GetRemoteBuildPath(build_revision, target_platform='chromium', | 448 def GetRemoteBuildPath(build_revision, target_platform='chromium', |
525 target_arch='ia32', patch_sha=None): | 449 target_arch='ia32', patch_sha=None): |
526 """Compute the url to download the build from.""" | 450 """Compute the url to download the build from.""" |
527 def GetGSRootFolderName(target_platform): | 451 def GetGSRootFolderName(target_platform): |
528 """Gets Google Cloud Storage root folder names""" | 452 """Gets Google Cloud Storage root folder names""" |
529 if IsWindowsHost(): | 453 if bisect_utils.IsWindowsHost(): |
530 if Is64BitWindows() and target_arch == 'x64': | 454 if bisect_utils.Is64BitWindows() and target_arch == 'x64': |
531 return 'Win x64 Builder' | 455 return 'Win x64 Builder' |
532 return 'Win Builder' | 456 return 'Win Builder' |
533 if IsLinuxHost(): | 457 if bisect_utils.IsLinuxHost(): |
534 if target_platform == 'android': | 458 if target_platform == 'android': |
535 return 'android_perf_rel' | 459 return 'android_perf_rel' |
536 return 'Linux Builder' | 460 return 'Linux Builder' |
537 if IsMacHost(): | 461 if bisect_utils.IsMacHost(): |
538 return 'Mac Builder' | 462 return 'Mac Builder' |
539 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) | 463 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) |
540 | 464 |
541 base_filename = GetZipFileName( | 465 base_filename = GetZipFileName( |
542 build_revision, target_arch, patch_sha) | 466 build_revision, target_arch, patch_sha) |
543 builder_folder = GetGSRootFolderName(target_platform) | 467 builder_folder = GetGSRootFolderName(target_platform) |
544 return '%s/%s' % (builder_folder, base_filename) | 468 return '%s/%s' % (builder_folder, base_filename) |
545 | 469 |
546 | 470 |
547 def FetchFromCloudStorage(bucket_name, source_path, destination_path): | 471 def FetchFromCloudStorage(bucket_name, source_path, destination_path): |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 # handle links and file bits (executable), which is much | 517 # handle links and file bits (executable), which is much |
594 # easier then trying to do that with ZipInfo options. | 518 # easier then trying to do that with ZipInfo options. |
595 # | 519 # |
596 # The Mac Version of unzip unfortunately does not support Zip64, whereas | 520 # The Mac Version of unzip unfortunately does not support Zip64, whereas |
597 # the python module does, so we have to fallback to the python zip module | 521 # the python module does, so we have to fallback to the python zip module |
598 # on Mac if the filesize is greater than 4GB. | 522 # on Mac if the filesize is greater than 4GB. |
599 # | 523 # |
600 # On Windows, try to use 7z if it is installed, otherwise fall back to python | 524 # On Windows, try to use 7z if it is installed, otherwise fall back to python |
601 # zip module and pray we don't have files larger than 512MB to unzip. | 525 # zip module and pray we don't have files larger than 512MB to unzip. |
602 unzip_cmd = None | 526 unzip_cmd = None |
603 if ((IsMacHost() and os.path.getsize(filename) < 4 * 1024 * 1024 * 1024) | 527 if ((bisect_utils.IsMacHost() |
604 or IsLinuxHost()): | 528 and os.path.getsize(filename) < 4 * 1024 * 1024 * 1024) |
| 529 or bisect_utils.IsLinuxHost()): |
605 unzip_cmd = ['unzip', '-o'] | 530 unzip_cmd = ['unzip', '-o'] |
606 elif IsWindowsHost() and os.path.exists('C:\\Program Files\\7-Zip\\7z.exe'): | 531 elif (bisect_utils.IsWindowsHost() |
| 532 and os.path.exists('C:\\Program Files\\7-Zip\\7z.exe')): |
607 unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y'] | 533 unzip_cmd = ['C:\\Program Files\\7-Zip\\7z.exe', 'x', '-y'] |
608 | 534 |
609 if unzip_cmd: | 535 if unzip_cmd: |
610 # Make sure path is absolute before changing directories. | 536 # Make sure path is absolute before changing directories. |
611 filepath = os.path.abspath(filename) | 537 filepath = os.path.abspath(filename) |
612 saved_dir = os.getcwd() | 538 saved_dir = os.getcwd() |
613 os.chdir(output_dir) | 539 os.chdir(output_dir) |
614 command = unzip_cmd + [filepath] | 540 command = unzip_cmd + [filepath] |
615 result = RunProcess(command) | 541 result = bisect_utils.RunProcess(command) |
616 os.chdir(saved_dir) | 542 os.chdir(saved_dir) |
617 if result: | 543 if result: |
618 raise IOError('unzip failed: %s => %s' % (str(command), result)) | 544 raise IOError('unzip failed: %s => %s' % (str(command), result)) |
619 else: | 545 else: |
620 assert IsWindowsHost() or IsMacHost() | 546 assert bisect_utils.IsWindowsHost() or bisect_utils.IsMacHost() |
621 zf = zipfile.ZipFile(filename) | 547 zf = zipfile.ZipFile(filename) |
622 for name in zf.namelist(): | 548 for name in zf.namelist(): |
623 if verbose: | 549 if verbose: |
624 print 'Extracting %s' % name | 550 print 'Extracting %s' % name |
625 zf.extract(name, output_dir) | 551 zf.extract(name, output_dir) |
626 if IsMacHost(): | 552 if bisect_utils.IsMacHost(): |
627 # Restore permission bits. | 553 # Restore permission bits. |
628 os.chmod(os.path.join(output_dir, name), | 554 os.chmod(os.path.join(output_dir, name), |
629 zf.getinfo(name).external_attr >> 16L) | 555 zf.getinfo(name).external_attr >> 16L) |
630 | 556 |
631 | 557 |
632 def RunProcess(command): | |
633 """Runs an arbitrary command. | |
634 | |
635 If output from the call is needed, use RunProcessAndRetrieveOutput instead. | |
636 | |
637 Args: | |
638 command: A list containing the command and args to execute. | |
639 | |
640 Returns: | |
641 The return code of the call. | |
642 """ | |
643 # On Windows, use shell=True to get PATH interpretation. | |
644 shell = IsWindowsHost() | |
645 return subprocess.call(command, shell=shell) | |
646 | |
647 | |
648 def RunProcessAndRetrieveOutput(command, cwd=None): | |
649 """Runs an arbitrary command, returning its output and return code. | |
650 | |
651 Since output is collected via communicate(), there will be no output until | |
652 the call terminates. If you need output while the program runs (ie. so | |
653 that the buildbot doesn't terminate the script), consider RunProcess(). | |
654 | |
655 Args: | |
656 command: A list containing the command and args to execute. | |
657 cwd: A directory to change to while running the command. The command can be | |
658 relative to this directory. If this is None, the command will be run in | |
659 the current directory. | |
660 | |
661 Returns: | |
662 A tuple of the output and return code. | |
663 """ | |
664 if cwd: | |
665 original_cwd = os.getcwd() | |
666 os.chdir(cwd) | |
667 | |
668 # On Windows, use shell=True to get PATH interpretation. | |
669 shell = IsWindowsHost() | |
670 proc = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE) | |
671 (output, _) = proc.communicate() | |
672 | |
673 if cwd: | |
674 os.chdir(original_cwd) | |
675 | |
676 return (output, proc.returncode) | |
677 | |
678 | |
679 def RunGit(command, cwd=None): | |
680 """Run a git subcommand, returning its output and return code. | |
681 | |
682 Args: | |
683 command: A list containing the args to git. | |
684 cwd: A directory to change to while running the git command (optional). | |
685 | |
686 Returns: | |
687 A tuple of the output and return code. | |
688 """ | |
689 command = ['git'] + command | |
690 | |
691 return RunProcessAndRetrieveOutput(command, cwd=cwd) | |
692 | |
693 | |
694 def CheckRunGit(command, cwd=None): | |
695 """Run a git subcommand, returning its output and return code. Asserts if | |
696 the return code of the call is non-zero. | |
697 | |
698 Args: | |
699 command: A list containing the args to git. | |
700 | |
701 Returns: | |
702 A tuple of the output and return code. | |
703 """ | |
704 (output, return_code) = RunGit(command, cwd=cwd) | |
705 | |
706 assert not return_code, 'An error occurred while running'\ | |
707 ' "git %s"' % ' '.join(command) | |
708 return output | |
709 | 558 |
710 | 559 |
711 def SetBuildSystemDefault(build_system, use_goma, goma_dir): | 560 def SetBuildSystemDefault(build_system, use_goma, goma_dir): |
712 """Sets up any environment variables needed to build with the specified build | 561 """Sets up any environment variables needed to build with the specified build |
713 system. | 562 system. |
714 | 563 |
715 Args: | 564 Args: |
716 build_system: A string specifying build system. Currently only 'ninja' or | 565 build_system: A string specifying build system. Currently only 'ninja' or |
717 'make' are supported.""" | 566 'make' are supported.""" |
718 if build_system == 'ninja': | 567 if build_system == 'ninja': |
719 gyp_var = os.getenv('GYP_GENERATORS') | 568 gyp_var = os.getenv('GYP_GENERATORS') |
720 | 569 |
721 if not gyp_var or not 'ninja' in gyp_var: | 570 if not gyp_var or not 'ninja' in gyp_var: |
722 if gyp_var: | 571 if gyp_var: |
723 os.environ['GYP_GENERATORS'] = gyp_var + ',ninja' | 572 os.environ['GYP_GENERATORS'] = gyp_var + ',ninja' |
724 else: | 573 else: |
725 os.environ['GYP_GENERATORS'] = 'ninja' | 574 os.environ['GYP_GENERATORS'] = 'ninja' |
726 | 575 |
727 if IsWindowsHost(): | 576 if bisect_utils.IsWindowsHost(): |
728 os.environ['GYP_DEFINES'] = 'component=shared_library '\ | 577 os.environ['GYP_DEFINES'] = 'component=shared_library '\ |
729 'incremental_chrome_dll=1 disable_nacl=1 fastbuild=1 '\ | 578 'incremental_chrome_dll=1 disable_nacl=1 fastbuild=1 '\ |
730 'chromium_win_pch=0' | 579 'chromium_win_pch=0' |
731 | 580 |
732 elif build_system == 'make': | 581 elif build_system == 'make': |
733 os.environ['GYP_GENERATORS'] = 'make' | 582 os.environ['GYP_GENERATORS'] = 'make' |
734 else: | 583 else: |
735 raise RuntimeError('%s build not supported.' % build_system) | 584 raise RuntimeError('%s build not supported.' % build_system) |
736 | 585 |
737 if use_goma: | 586 if use_goma: |
738 os.environ['GYP_DEFINES'] = '%s %s' % (os.getenv('GYP_DEFINES', ''), | 587 os.environ['GYP_DEFINES'] = '%s %s' % (os.getenv('GYP_DEFINES', ''), |
739 'use_goma=1') | 588 'use_goma=1') |
740 if goma_dir: | 589 if goma_dir: |
741 os.environ['GYP_DEFINES'] += ' gomadir=%s' % goma_dir | 590 os.environ['GYP_DEFINES'] += ' gomadir=%s' % goma_dir |
742 | 591 |
743 | 592 |
744 def BuildWithMake(threads, targets, build_type='Release'): | 593 def BuildWithMake(threads, targets, build_type='Release'): |
745 cmd = ['make', 'BUILDTYPE=%s' % build_type] | 594 cmd = ['make', 'BUILDTYPE=%s' % build_type] |
746 | 595 |
747 if threads: | 596 if threads: |
748 cmd.append('-j%d' % threads) | 597 cmd.append('-j%d' % threads) |
749 | 598 |
750 cmd += targets | 599 cmd += targets |
751 | 600 |
752 return_code = RunProcess(cmd) | 601 return_code = bisect_utils.RunProcess(cmd) |
753 | 602 |
754 return not return_code | 603 return not return_code |
755 | 604 |
756 | 605 |
757 def BuildWithNinja(threads, targets, build_type='Release'): | 606 def BuildWithNinja(threads, targets, build_type='Release'): |
758 cmd = ['ninja', '-C', os.path.join('out', build_type)] | 607 cmd = ['ninja', '-C', os.path.join('out', build_type)] |
759 | 608 |
760 if threads: | 609 if threads: |
761 cmd.append('-j%d' % threads) | 610 cmd.append('-j%d' % threads) |
762 | 611 |
763 cmd += targets | 612 cmd += targets |
764 | 613 |
765 return_code = RunProcess(cmd) | 614 return_code = bisect_utils.RunProcess(cmd) |
766 | 615 |
767 return not return_code | 616 return not return_code |
768 | 617 |
769 | 618 |
770 def BuildWithVisualStudio(targets, build_type='Release'): | 619 def BuildWithVisualStudio(targets, build_type='Release'): |
771 path_to_devenv = os.path.abspath( | 620 path_to_devenv = os.path.abspath( |
772 os.path.join(os.environ['VS100COMNTOOLS'], '..', 'IDE', 'devenv.com')) | 621 os.path.join(os.environ['VS100COMNTOOLS'], '..', 'IDE', 'devenv.com')) |
773 path_to_sln = os.path.join(os.getcwd(), 'chrome', 'chrome.sln') | 622 path_to_sln = os.path.join(os.getcwd(), 'chrome', 'chrome.sln') |
774 cmd = [path_to_devenv, '/build', build_type, path_to_sln] | 623 cmd = [path_to_devenv, '/build', build_type, path_to_sln] |
775 | 624 |
776 for t in targets: | 625 for t in targets: |
777 cmd.extend(['/Project', t]) | 626 cmd.extend(['/Project', t]) |
778 | 627 |
779 return_code = RunProcess(cmd) | 628 return_code = bisect_utils.RunProcess(cmd) |
780 | 629 |
781 return not return_code | 630 return not return_code |
782 | 631 |
783 | 632 |
784 def WriteStringToFile(text, file_name): | 633 def WriteStringToFile(text, file_name): |
785 try: | 634 try: |
786 with open(file_name, "wb") as f: | 635 with open(file_name, "wb") as f: |
787 f.write(text) | 636 f.write(text) |
788 except IOError as e: | 637 except IOError as e: |
789 raise RuntimeError('Error writing to file [%s]' % file_name ) | 638 raise RuntimeError('Error writing to file [%s]' % file_name ) |
(...skipping 21 matching lines...) Expand all Loading... |
811 | 660 |
812 class Builder(object): | 661 class Builder(object): |
813 """Builder is used by the bisect script to build relevant targets and deploy. | 662 """Builder is used by the bisect script to build relevant targets and deploy. |
814 """ | 663 """ |
815 def __init__(self, opts): | 664 def __init__(self, opts): |
816 """Performs setup for building with target build system. | 665 """Performs setup for building with target build system. |
817 | 666 |
818 Args: | 667 Args: |
819 opts: Options parsed from command line. | 668 opts: Options parsed from command line. |
820 """ | 669 """ |
821 if IsWindowsHost(): | 670 if bisect_utils.IsWindowsHost(): |
822 if not opts.build_preference: | 671 if not opts.build_preference: |
823 opts.build_preference = 'msvs' | 672 opts.build_preference = 'msvs' |
824 | 673 |
825 if opts.build_preference == 'msvs': | 674 if opts.build_preference == 'msvs': |
826 if not os.getenv('VS100COMNTOOLS'): | 675 if not os.getenv('VS100COMNTOOLS'): |
827 raise RuntimeError( | 676 raise RuntimeError( |
828 'Path to visual studio could not be determined.') | 677 'Path to visual studio could not be determined.') |
829 else: | 678 else: |
830 SetBuildSystemDefault(opts.build_preference, opts.use_goma, | 679 SetBuildSystemDefault(opts.build_preference, opts.use_goma, |
831 opts.goma_dir) | 680 opts.goma_dir) |
(...skipping 24 matching lines...) Expand all Loading... |
856 | 705 |
857 def Build(self, depot, opts): | 706 def Build(self, depot, opts): |
858 raise NotImplementedError() | 707 raise NotImplementedError() |
859 | 708 |
860 def GetBuildOutputDirectory(self, opts, src_dir=None): | 709 def GetBuildOutputDirectory(self, opts, src_dir=None): |
861 """Returns the path to the build directory, relative to the checkout root. | 710 """Returns the path to the build directory, relative to the checkout root. |
862 | 711 |
863 Assumes that the current working directory is the checkout root. | 712 Assumes that the current working directory is the checkout root. |
864 """ | 713 """ |
865 src_dir = src_dir or 'src' | 714 src_dir = src_dir or 'src' |
866 if opts.build_preference == 'ninja' or IsLinuxHost(): | 715 if opts.build_preference == 'ninja' or bisect_utils.IsLinuxHost(): |
867 return os.path.join(src_dir, 'out') | 716 return os.path.join(src_dir, 'out') |
868 if IsMacHost(): | 717 if bisect_utils.IsMacHost(): |
869 return os.path.join(src_dir, 'xcodebuild') | 718 return os.path.join(src_dir, 'xcodebuild') |
870 if IsWindowsHost(): | 719 if bisect_utils.IsWindowsHost(): |
871 return os.path.join(src_dir, 'build') | 720 return os.path.join(src_dir, 'build') |
872 raise NotImplementedError('Unexpected platform %s' % sys.platform) | 721 raise NotImplementedError('Unexpected platform %s' % sys.platform) |
873 | 722 |
874 | 723 |
875 class DesktopBuilder(Builder): | 724 class DesktopBuilder(Builder): |
876 """DesktopBuilder is used to build Chromium on linux/mac/windows.""" | 725 """DesktopBuilder is used to build Chromium on linux/mac/windows.""" |
877 def __init__(self, opts): | 726 def __init__(self, opts): |
878 super(DesktopBuilder, self).__init__(opts) | 727 super(DesktopBuilder, self).__init__(opts) |
879 | 728 |
880 def Build(self, depot, opts): | 729 def Build(self, depot, opts): |
(...skipping 12 matching lines...) Expand all Loading... |
893 threads = None | 742 threads = None |
894 if opts.use_goma: | 743 if opts.use_goma: |
895 threads = 64 | 744 threads = 64 |
896 | 745 |
897 build_success = False | 746 build_success = False |
898 if opts.build_preference == 'make': | 747 if opts.build_preference == 'make': |
899 build_success = BuildWithMake(threads, targets, opts.target_build_type) | 748 build_success = BuildWithMake(threads, targets, opts.target_build_type) |
900 elif opts.build_preference == 'ninja': | 749 elif opts.build_preference == 'ninja': |
901 build_success = BuildWithNinja(threads, targets, opts.target_build_type) | 750 build_success = BuildWithNinja(threads, targets, opts.target_build_type) |
902 elif opts.build_preference == 'msvs': | 751 elif opts.build_preference == 'msvs': |
903 assert IsWindowsHost(), 'msvs is only supported on Windows.' | 752 assert bisect_utils.IsWindowsHost(), 'msvs is only supported on Windows.' |
904 build_success = BuildWithVisualStudio(targets, opts.target_build_type) | 753 build_success = BuildWithVisualStudio(targets, opts.target_build_type) |
905 else: | 754 else: |
906 assert False, 'No build system defined.' | 755 assert False, 'No build system defined.' |
907 return build_success | 756 return build_success |
908 | 757 |
909 | 758 |
910 class AndroidBuilder(Builder): | 759 class AndroidBuilder(Builder): |
911 """AndroidBuilder is used to build on android.""" | 760 """AndroidBuilder is used to build on android.""" |
912 def __init__(self, opts): | 761 def __init__(self, opts): |
913 super(AndroidBuilder, self).__init__(opts) | 762 super(AndroidBuilder, self).__init__(opts) |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
965 True if successful. | 814 True if successful. |
966 """ | 815 """ |
967 try: | 816 try: |
968 # Keys will most likely be set to 0640 after wiping the chroot. | 817 # Keys will most likely be set to 0640 after wiping the chroot. |
969 os.chmod(CROS_SCRIPT_KEY_PATH, 0600) | 818 os.chmod(CROS_SCRIPT_KEY_PATH, 0600) |
970 os.chmod(CROS_TEST_KEY_PATH, 0600) | 819 os.chmod(CROS_TEST_KEY_PATH, 0600) |
971 cmd = [CROS_SDK_PATH, '--', './bin/cros_image_to_target.py', | 820 cmd = [CROS_SDK_PATH, '--', './bin/cros_image_to_target.py', |
972 '--remote=%s' % opts.cros_remote_ip, | 821 '--remote=%s' % opts.cros_remote_ip, |
973 '--board=%s' % opts.cros_board, '--test', '--verbose'] | 822 '--board=%s' % opts.cros_board, '--test', '--verbose'] |
974 | 823 |
975 return_code = RunProcess(cmd) | 824 return_code = bisect_utils.RunProcess(cmd) |
976 return not return_code | 825 return not return_code |
977 except OSError, e: | 826 except OSError, e: |
978 return False | 827 return False |
979 | 828 |
980 def BuildPackages(self, opts, depot): | 829 def BuildPackages(self, opts, depot): |
981 """Builds packages for cros. | 830 """Builds packages for cros. |
982 | 831 |
983 Args: | 832 Args: |
984 opts: Program options containing cros_board. | 833 opts: Program options containing cros_board. |
985 depot: The depot being bisected. | 834 depot: The depot being bisected. |
986 | 835 |
987 Returns: | 836 Returns: |
988 True if successful. | 837 True if successful. |
989 """ | 838 """ |
990 cmd = [CROS_SDK_PATH] | 839 cmd = [CROS_SDK_PATH] |
991 | 840 |
992 if depot != 'cros': | 841 if depot != 'cros': |
993 path_to_chrome = os.path.join(os.getcwd(), '..') | 842 path_to_chrome = os.path.join(os.getcwd(), '..') |
994 cmd += ['--chrome_root=%s' % path_to_chrome] | 843 cmd += ['--chrome_root=%s' % path_to_chrome] |
995 | 844 |
996 cmd += ['--'] | 845 cmd += ['--'] |
997 | 846 |
998 if depot != 'cros': | 847 if depot != 'cros': |
999 cmd += ['CHROME_ORIGIN=LOCAL_SOURCE'] | 848 cmd += ['CHROME_ORIGIN=LOCAL_SOURCE'] |
1000 | 849 |
1001 cmd += ['BUILDTYPE=%s' % opts.target_build_type, './build_packages', | 850 cmd += ['BUILDTYPE=%s' % opts.target_build_type, './build_packages', |
1002 '--board=%s' % opts.cros_board] | 851 '--board=%s' % opts.cros_board] |
1003 return_code = RunProcess(cmd) | 852 return_code = bisect_utils.RunProcess(cmd) |
1004 | 853 |
1005 return not return_code | 854 return not return_code |
1006 | 855 |
1007 def BuildImage(self, opts, depot): | 856 def BuildImage(self, opts, depot): |
1008 """Builds test image for cros. | 857 """Builds test image for cros. |
1009 | 858 |
1010 Args: | 859 Args: |
1011 opts: Program options containing cros_board. | 860 opts: Program options containing cros_board. |
1012 depot: The depot being bisected. | 861 depot: The depot being bisected. |
1013 | 862 |
1014 Returns: | 863 Returns: |
1015 True if successful. | 864 True if successful. |
1016 """ | 865 """ |
1017 cmd = [CROS_SDK_PATH] | 866 cmd = [CROS_SDK_PATH] |
1018 | 867 |
1019 if depot != 'cros': | 868 if depot != 'cros': |
1020 path_to_chrome = os.path.join(os.getcwd(), '..') | 869 path_to_chrome = os.path.join(os.getcwd(), '..') |
1021 cmd += ['--chrome_root=%s' % path_to_chrome] | 870 cmd += ['--chrome_root=%s' % path_to_chrome] |
1022 | 871 |
1023 cmd += ['--'] | 872 cmd += ['--'] |
1024 | 873 |
1025 if depot != 'cros': | 874 if depot != 'cros': |
1026 cmd += ['CHROME_ORIGIN=LOCAL_SOURCE'] | 875 cmd += ['CHROME_ORIGIN=LOCAL_SOURCE'] |
1027 | 876 |
1028 cmd += ['BUILDTYPE=%s' % opts.target_build_type, '--', './build_image', | 877 cmd += ['BUILDTYPE=%s' % opts.target_build_type, '--', './build_image', |
1029 '--board=%s' % opts.cros_board, 'test'] | 878 '--board=%s' % opts.cros_board, 'test'] |
1030 | 879 |
1031 return_code = RunProcess(cmd) | 880 return_code = bisect_utils.RunProcess(cmd) |
1032 | 881 |
1033 return not return_code | 882 return not return_code |
1034 | 883 |
1035 def Build(self, depot, opts): | 884 def Build(self, depot, opts): |
1036 """Builds targets using options passed into the script. | 885 """Builds targets using options passed into the script. |
1037 | 886 |
1038 Args: | 887 Args: |
1039 depot: Current depot being bisected. | 888 depot: Current depot being bisected. |
1040 opts: The options parsed from the command line. | 889 opts: The options parsed from the command line. |
1041 | 890 |
1042 Returns: | 891 Returns: |
1043 True if build was successful. | 892 True if build was successful. |
1044 """ | 893 """ |
1045 if self.BuildPackages(opts, depot): | 894 if self.BuildPackages(opts, depot): |
1046 if self.BuildImage(opts, depot): | 895 if self.BuildImage(opts, depot): |
1047 return self.ImageToTarget(opts) | 896 return self.ImageToTarget(opts) |
1048 return False | 897 return False |
1049 | 898 |
1050 | 899 |
1051 class SourceControl(object): | |
1052 """SourceControl is an abstraction over the underlying source control | |
1053 system used for chromium. For now only git is supported, but in the | |
1054 future, the svn workflow could be added as well.""" | |
1055 def __init__(self): | |
1056 super(SourceControl, self).__init__() | |
1057 | |
1058 def SyncToRevisionWithGClient(self, revision): | |
1059 """Uses gclient to sync to the specified revision. | |
1060 | |
1061 ie. gclient sync --revision <revision> | |
1062 | |
1063 Args: | |
1064 revision: The git SHA1 or svn CL (depending on workflow). | |
1065 | |
1066 Returns: | |
1067 The return code of the call. | |
1068 """ | |
1069 return bisect_utils.RunGClient(['sync', '--verbose', '--reset', '--force', | |
1070 '--delete_unversioned_trees', '--nohooks', '--revision', revision]) | |
1071 | |
1072 def SyncToRevisionWithRepo(self, timestamp): | |
1073 """Uses repo to sync all the underlying git depots to the specified | |
1074 time. | |
1075 | |
1076 Args: | |
1077 timestamp: The unix timestamp to sync to. | |
1078 | |
1079 Returns: | |
1080 The return code of the call. | |
1081 """ | |
1082 return bisect_utils.RunRepoSyncAtTimestamp(timestamp) | |
1083 | |
1084 | |
1085 class GitSourceControl(SourceControl): | |
1086 """GitSourceControl is used to query the underlying source control. """ | |
1087 def __init__(self, opts): | |
1088 super(GitSourceControl, self).__init__() | |
1089 self.opts = opts | |
1090 | |
1091 def IsGit(self): | |
1092 return True | |
1093 | |
1094 def GetRevisionList(self, revision_range_end, revision_range_start, cwd=None): | |
1095 """Retrieves a list of revisions between |revision_range_start| and | |
1096 |revision_range_end|. | |
1097 | |
1098 Args: | |
1099 revision_range_end: The SHA1 for the end of the range. | |
1100 revision_range_start: The SHA1 for the beginning of the range. | |
1101 | |
1102 Returns: | |
1103 A list of the revisions between |revision_range_start| and | |
1104 |revision_range_end| (inclusive). | |
1105 """ | |
1106 revision_range = '%s..%s' % (revision_range_start, revision_range_end) | |
1107 cmd = ['log', '--format=%H', '-10000', '--first-parent', revision_range] | |
1108 log_output = CheckRunGit(cmd, cwd=cwd) | |
1109 | |
1110 revision_hash_list = log_output.split() | |
1111 revision_hash_list.append(revision_range_start) | |
1112 | |
1113 return revision_hash_list | |
1114 | |
1115 def SyncToRevision(self, revision, sync_client=None): | |
1116 """Syncs to the specified revision. | |
1117 | |
1118 Args: | |
1119 revision: The revision to sync to. | |
1120 use_gclient: Specifies whether or not we should sync using gclient or | |
1121 just use source control directly. | |
1122 | |
1123 Returns: | |
1124 True if successful. | |
1125 """ | |
1126 | |
1127 if not sync_client: | |
1128 results = RunGit(['checkout', revision])[1] | |
1129 elif sync_client == 'gclient': | |
1130 results = self.SyncToRevisionWithGClient(revision) | |
1131 elif sync_client == 'repo': | |
1132 results = self.SyncToRevisionWithRepo(revision) | |
1133 | |
1134 return not results | |
1135 | |
1136 def ResolveToRevision(self, revision_to_check, depot, search, cwd=None): | |
1137 """If an SVN revision is supplied, try to resolve it to a git SHA1. | |
1138 | |
1139 Args: | |
1140 revision_to_check: The user supplied revision string that may need to be | |
1141 resolved to a git SHA1. | |
1142 depot: The depot the revision_to_check is from. | |
1143 search: The number of changelists to try if the first fails to resolve | |
1144 to a git hash. If the value is negative, the function will search | |
1145 backwards chronologically, otherwise it will search forward. | |
1146 | |
1147 Returns: | |
1148 A string containing a git SHA1 hash, otherwise None. | |
1149 """ | |
1150 # Android-chrome is git only, so no need to resolve this to anything else. | |
1151 if depot == 'android-chrome': | |
1152 return revision_to_check | |
1153 | |
1154 if depot != 'cros': | |
1155 if not IsStringInt(revision_to_check): | |
1156 return revision_to_check | |
1157 | |
1158 depot_svn = 'svn://svn.chromium.org/chrome/trunk/src' | |
1159 | |
1160 if depot != 'chromium': | |
1161 depot_svn = DEPOT_DEPS_NAME[depot]['svn'] | |
1162 | |
1163 svn_revision = int(revision_to_check) | |
1164 git_revision = None | |
1165 | |
1166 if search > 0: | |
1167 search_range = xrange(svn_revision, svn_revision + search, 1) | |
1168 else: | |
1169 search_range = xrange(svn_revision, svn_revision + search, -1) | |
1170 | |
1171 for i in search_range: | |
1172 svn_pattern = 'git-svn-id: %s@%d' % (depot_svn, i) | |
1173 cmd = ['log', '--format=%H', '-1', '--grep', svn_pattern, | |
1174 'origin/master'] | |
1175 | |
1176 (log_output, return_code) = RunGit(cmd, cwd=cwd) | |
1177 | |
1178 assert not return_code, 'An error occurred while running'\ | |
1179 ' "git %s"' % ' '.join(cmd) | |
1180 | |
1181 if not return_code: | |
1182 log_output = log_output.strip() | |
1183 | |
1184 if log_output: | |
1185 git_revision = log_output | |
1186 | |
1187 break | |
1188 | |
1189 return git_revision | |
1190 else: | |
1191 if IsStringInt(revision_to_check): | |
1192 return int(revision_to_check) | |
1193 else: | |
1194 cwd = os.getcwd() | |
1195 os.chdir(os.path.join(os.getcwd(), 'src', 'third_party', | |
1196 'chromiumos-overlay')) | |
1197 pattern = CROS_VERSION_PATTERN % revision_to_check | |
1198 cmd = ['log', '--format=%ct', '-1', '--grep', pattern] | |
1199 | |
1200 git_revision = None | |
1201 | |
1202 log_output = CheckRunGit(cmd, cwd=cwd) | |
1203 if log_output: | |
1204 git_revision = log_output | |
1205 git_revision = int(log_output.strip()) | |
1206 os.chdir(cwd) | |
1207 | |
1208 return git_revision | |
1209 | |
1210 def IsInProperBranch(self): | |
1211 """Confirms they're in the master branch for performing the bisection. | |
1212 This is needed or gclient will fail to sync properly. | |
1213 | |
1214 Returns: | |
1215 True if the current branch on src is 'master' | |
1216 """ | |
1217 cmd = ['rev-parse', '--abbrev-ref', 'HEAD'] | |
1218 log_output = CheckRunGit(cmd) | |
1219 log_output = log_output.strip() | |
1220 | |
1221 return log_output == "master" | |
1222 | |
1223 def SVNFindRev(self, revision, cwd=None): | |
1224 """Maps directly to the 'git svn find-rev' command. | |
1225 | |
1226 Args: | |
1227 revision: The git SHA1 to use. | |
1228 | |
1229 Returns: | |
1230 An integer changelist #, otherwise None. | |
1231 """ | |
1232 | |
1233 cmd = ['svn', 'find-rev', revision] | |
1234 | |
1235 output = CheckRunGit(cmd, cwd) | |
1236 svn_revision = output.strip() | |
1237 | |
1238 if IsStringInt(svn_revision): | |
1239 return int(svn_revision) | |
1240 | |
1241 return None | |
1242 | |
1243 def QueryRevisionInfo(self, revision, cwd=None): | |
1244 """Gathers information on a particular revision, such as author's name, | |
1245 email, subject, and date. | |
1246 | |
1247 Args: | |
1248 revision: Revision you want to gather information on. | |
1249 Returns: | |
1250 A dict in the following format: | |
1251 { | |
1252 'author': %s, | |
1253 'email': %s, | |
1254 'date': %s, | |
1255 'subject': %s, | |
1256 'body': %s, | |
1257 } | |
1258 """ | |
1259 commit_info = {} | |
1260 | |
1261 formats = ['%cN', '%cE', '%s', '%cD', '%b'] | |
1262 targets = ['author', 'email', 'subject', 'date', 'body'] | |
1263 | |
1264 for i in xrange(len(formats)): | |
1265 cmd = ['log', '--format=%s' % formats[i], '-1', revision] | |
1266 output = CheckRunGit(cmd, cwd=cwd) | |
1267 commit_info[targets[i]] = output.rstrip() | |
1268 | |
1269 return commit_info | |
1270 | |
1271 def CheckoutFileAtRevision(self, file_name, revision, cwd=None): | |
1272 """Performs a checkout on a file at the given revision. | |
1273 | |
1274 Returns: | |
1275 True if successful. | |
1276 """ | |
1277 return not RunGit(['checkout', revision, file_name], cwd=cwd)[1] | |
1278 | |
1279 def RevertFileToHead(self, file_name): | |
1280 """Unstages a file and returns it to HEAD. | |
1281 | |
1282 Returns: | |
1283 True if successful. | |
1284 """ | |
1285 # Reset doesn't seem to return 0 on success. | |
1286 RunGit(['reset', 'HEAD', file_name]) | |
1287 | |
1288 return not RunGit(['checkout', bisect_utils.FILE_DEPS_GIT])[1] | |
1289 | |
1290 def QueryFileRevisionHistory(self, filename, revision_start, revision_end): | |
1291 """Returns a list of commits that modified this file. | |
1292 | |
1293 Args: | |
1294 filename: Name of file. | |
1295 revision_start: Start of revision range. | |
1296 revision_end: End of revision range. | |
1297 | |
1298 Returns: | |
1299 Returns a list of commits that touched this file. | |
1300 """ | |
1301 cmd = ['log', '--format=%H', '%s~1..%s' % (revision_start, revision_end), | |
1302 filename] | |
1303 output = CheckRunGit(cmd) | |
1304 | |
1305 return [o for o in output.split('\n') if o] | |
1306 | 900 |
1307 | 901 |
1308 class BisectPerformanceMetrics(object): | 902 class BisectPerformanceMetrics(object): |
1309 """This class contains functionality to perform a bisection of a range of | 903 """This class contains functionality to perform a bisection of a range of |
1310 revisions to narrow down where performance regressions may have occurred. | 904 revisions to narrow down where performance regressions may have occurred. |
1311 | 905 |
1312 The main entry-point is the Run method. | 906 The main entry-point is the Run method. |
1313 """ | 907 """ |
1314 | 908 |
1315 def __init__(self, source_control, opts): | 909 def __init__(self, source_control, opts): |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1356 cwd = os.getcwd() | 950 cwd = os.getcwd() |
1357 self.ChangeToDepotWorkingDirectory('cros') | 951 self.ChangeToDepotWorkingDirectory('cros') |
1358 | 952 |
1359 # Print the commit timestamps for every commit in the revision time | 953 # Print the commit timestamps for every commit in the revision time |
1360 # range. We'll sort them and bisect by that. There is a remote chance that | 954 # range. We'll sort them and bisect by that. There is a remote chance that |
1361 # 2 (or more) commits will share the exact same timestamp, but it's | 955 # 2 (or more) commits will share the exact same timestamp, but it's |
1362 # probably safe to ignore that case. | 956 # probably safe to ignore that case. |
1363 cmd = ['repo', 'forall', '-c', | 957 cmd = ['repo', 'forall', '-c', |
1364 'git log --format=%%ct --before=%d --after=%d' % ( | 958 'git log --format=%%ct --before=%d --after=%d' % ( |
1365 revision_range_end, revision_range_start)] | 959 revision_range_end, revision_range_start)] |
1366 (output, return_code) = RunProcessAndRetrieveOutput(cmd) | 960 (output, return_code) = bisect_utils.RunProcessAndRetrieveOutput(cmd) |
1367 | 961 |
1368 assert not return_code, 'An error occurred while running'\ | 962 assert not return_code, 'An error occurred while running'\ |
1369 ' "%s"' % ' '.join(cmd) | 963 ' "%s"' % ' '.join(cmd) |
1370 | 964 |
1371 os.chdir(cwd) | 965 os.chdir(cwd) |
1372 | 966 |
1373 revision_work_list = list(set( | 967 revision_work_list = list(set( |
1374 [int(o) for o in output.split('\n') if IsStringInt(o)])) | 968 [int(o) for o in output.split('\n') if bisect_utils.IsStringInt(o)])) |
1375 revision_work_list = sorted(revision_work_list, reverse=True) | 969 revision_work_list = sorted(revision_work_list, reverse=True) |
1376 else: | 970 else: |
1377 cwd = self._GetDepotDirectory(depot) | 971 cwd = self._GetDepotDirectory(depot) |
1378 revision_work_list = self.source_control.GetRevisionList(bad_revision, | 972 revision_work_list = self.source_control.GetRevisionList(bad_revision, |
1379 good_revision, cwd=cwd) | 973 good_revision, cwd=cwd) |
1380 | 974 |
1381 return revision_work_list | 975 return revision_work_list |
1382 | 976 |
1383 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision): | 977 def _GetV8BleedingEdgeFromV8TrunkIfMappable(self, revision): |
1384 svn_revision = self.source_control.SVNFindRev(revision) | 978 svn_revision = self.source_control.SVNFindRev(revision) |
1385 | 979 |
1386 if IsStringInt(svn_revision): | 980 if bisect_utils.IsStringInt(svn_revision): |
1387 # V8 is tricky to bisect, in that there are only a few instances when | 981 # V8 is tricky to bisect, in that there are only a few instances when |
1388 # we can dive into bleeding_edge and get back a meaningful result. | 982 # we can dive into bleeding_edge and get back a meaningful result. |
1389 # Try to detect a V8 "business as usual" case, which is when: | 983 # Try to detect a V8 "business as usual" case, which is when: |
1390 # 1. trunk revision N has description "Version X.Y.Z" | 984 # 1. trunk revision N has description "Version X.Y.Z" |
1391 # 2. bleeding_edge revision (N-1) has description "Prepare push to | 985 # 2. bleeding_edge revision (N-1) has description "Prepare push to |
1392 # trunk. Now working on X.Y.(Z+1)." | 986 # trunk. Now working on X.Y.(Z+1)." |
1393 # | 987 # |
1394 # As of 01/24/2014, V8 trunk descriptions are formatted: | 988 # As of 01/24/2014, V8 trunk descriptions are formatted: |
1395 # "Version 3.X.Y (based on bleeding_edge revision rZ)" | 989 # "Version 3.X.Y (based on bleeding_edge revision rZ)" |
1396 # So we can just try parsing that out first and fall back to the old way. | 990 # So we can just try parsing that out first and fall back to the old way. |
(...skipping 10 matching lines...) Expand all Loading... |
1407 if regex_results: | 1001 if regex_results: |
1408 git_revision = None | 1002 git_revision = None |
1409 | 1003 |
1410 # Look for "based on bleeding_edge" and parse out revision | 1004 # Look for "based on bleeding_edge" and parse out revision |
1411 if 'based on bleeding_edge' in revision_info['subject']: | 1005 if 'based on bleeding_edge' in revision_info['subject']: |
1412 try: | 1006 try: |
1413 bleeding_edge_revision = revision_info['subject'].split( | 1007 bleeding_edge_revision = revision_info['subject'].split( |
1414 'bleeding_edge revision r')[1] | 1008 'bleeding_edge revision r')[1] |
1415 bleeding_edge_revision = int(bleeding_edge_revision.split(')')[0]) | 1009 bleeding_edge_revision = int(bleeding_edge_revision.split(')')[0]) |
1416 git_revision = self.source_control.ResolveToRevision( | 1010 git_revision = self.source_control.ResolveToRevision( |
1417 bleeding_edge_revision, 'v8_bleeding_edge', 1, | 1011 bleeding_edge_revision, 'v8_bleeding_edge', DEPOT_DEPS_NAME, 1, |
1418 cwd=v8_bleeding_edge_dir) | 1012 cwd=v8_bleeding_edge_dir) |
1419 return git_revision | 1013 return git_revision |
1420 except (IndexError, ValueError): | 1014 except (IndexError, ValueError): |
1421 pass | 1015 pass |
1422 | 1016 |
1423 if not git_revision: | 1017 if not git_revision: |
1424 # Wasn't successful, try the old way of looking for "Prepare push to" | 1018 # Wasn't successful, try the old way of looking for "Prepare push to" |
1425 git_revision = self.source_control.ResolveToRevision( | 1019 git_revision = self.source_control.ResolveToRevision( |
1426 int(svn_revision) - 1, 'v8_bleeding_edge', -1, | 1020 int(svn_revision) - 1, 'v8_bleeding_edge', DEPOT_DEPS_NAME, -1, |
1427 cwd=v8_bleeding_edge_dir) | 1021 cwd=v8_bleeding_edge_dir) |
1428 | 1022 |
1429 if git_revision: | 1023 if git_revision: |
1430 revision_info = self.source_control.QueryRevisionInfo(git_revision, | 1024 revision_info = self.source_control.QueryRevisionInfo(git_revision, |
1431 cwd=v8_bleeding_edge_dir) | 1025 cwd=v8_bleeding_edge_dir) |
1432 | 1026 |
1433 if 'Prepare push to trunk' in revision_info['subject']: | 1027 if 'Prepare push to trunk' in revision_info['subject']: |
1434 return git_revision | 1028 return git_revision |
1435 return None | 1029 return None |
1436 | 1030 |
1437 def _GetNearestV8BleedingEdgeFromTrunk(self, revision, search_forward=True): | 1031 def _GetNearestV8BleedingEdgeFromTrunk(self, revision, search_forward=True): |
1438 cwd = self._GetDepotDirectory('v8') | 1032 cwd = self._GetDepotDirectory('v8') |
1439 cmd = ['log', '--format=%ct', '-1', revision] | 1033 cmd = ['log', '--format=%ct', '-1', revision] |
1440 output = CheckRunGit(cmd, cwd=cwd) | 1034 output = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
1441 commit_time = int(output) | 1035 commit_time = int(output) |
1442 commits = [] | 1036 commits = [] |
1443 | 1037 |
1444 if search_forward: | 1038 if search_forward: |
1445 cmd = ['log', '--format=%H', '-10', '--after=%d' % commit_time, | 1039 cmd = ['log', '--format=%H', '-10', '--after=%d' % commit_time, |
1446 'origin/master'] | 1040 'origin/master'] |
1447 output = CheckRunGit(cmd, cwd=cwd) | 1041 output = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
1448 output = output.split() | 1042 output = output.split() |
1449 commits = output | 1043 commits = output |
1450 commits = reversed(commits) | 1044 commits = reversed(commits) |
1451 else: | 1045 else: |
1452 cmd = ['log', '--format=%H', '-10', '--before=%d' % commit_time, | 1046 cmd = ['log', '--format=%H', '-10', '--before=%d' % commit_time, |
1453 'origin/master'] | 1047 'origin/master'] |
1454 output = CheckRunGit(cmd, cwd=cwd) | 1048 output = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
1455 output = output.split() | 1049 output = output.split() |
1456 commits = output | 1050 commits = output |
1457 | 1051 |
1458 bleeding_edge_revision = None | 1052 bleeding_edge_revision = None |
1459 | 1053 |
1460 for c in commits: | 1054 for c in commits: |
1461 bleeding_edge_revision = self._GetV8BleedingEdgeFromV8TrunkIfMappable(c) | 1055 bleeding_edge_revision = self._GetV8BleedingEdgeFromV8TrunkIfMappable(c) |
1462 if bleeding_edge_revision: | 1056 if bleeding_edge_revision: |
1463 break | 1057 break |
1464 | 1058 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1557 | 1151 |
1558 results = {} | 1152 results = {} |
1559 | 1153 |
1560 if depot == 'chromium' or depot == 'android-chrome': | 1154 if depot == 'chromium' or depot == 'android-chrome': |
1561 results = self._ParseRevisionsFromDEPSFile(depot) | 1155 results = self._ParseRevisionsFromDEPSFile(depot) |
1562 os.chdir(cwd) | 1156 os.chdir(cwd) |
1563 elif depot == 'cros': | 1157 elif depot == 'cros': |
1564 cmd = [CROS_SDK_PATH, '--', 'portageq-%s' % self.opts.cros_board, | 1158 cmd = [CROS_SDK_PATH, '--', 'portageq-%s' % self.opts.cros_board, |
1565 'best_visible', '/build/%s' % self.opts.cros_board, 'ebuild', | 1159 'best_visible', '/build/%s' % self.opts.cros_board, 'ebuild', |
1566 CROS_CHROMEOS_PATTERN] | 1160 CROS_CHROMEOS_PATTERN] |
1567 (output, return_code) = RunProcessAndRetrieveOutput(cmd) | 1161 (output, return_code) = bisect_utils.RunProcessAndRetrieveOutput(cmd) |
1568 | 1162 |
1569 assert not return_code, 'An error occurred while running' \ | 1163 assert not return_code, 'An error occurred while running' \ |
1570 ' "%s"' % ' '.join(cmd) | 1164 ' "%s"' % ' '.join(cmd) |
1571 | 1165 |
1572 if len(output) > CROS_CHROMEOS_PATTERN: | 1166 if len(output) > CROS_CHROMEOS_PATTERN: |
1573 output = output[len(CROS_CHROMEOS_PATTERN):] | 1167 output = output[len(CROS_CHROMEOS_PATTERN):] |
1574 | 1168 |
1575 if len(output) > 1: | 1169 if len(output) > 1: |
1576 output = output.split('_')[0] | 1170 output = output.split('_')[0] |
1577 | 1171 |
1578 if len(output) > 3: | 1172 if len(output) > 3: |
1579 contents = output.split('.') | 1173 contents = output.split('.') |
1580 | 1174 |
1581 version = contents[2] | 1175 version = contents[2] |
1582 | 1176 |
1583 if contents[3] != '0': | 1177 if contents[3] != '0': |
1584 warningText = 'Chrome version: %s.%s but using %s.0 to bisect.' % \ | 1178 warningText = 'Chrome version: %s.%s but using %s.0 to bisect.' % \ |
1585 (version, contents[3], version) | 1179 (version, contents[3], version) |
1586 if not warningText in self.warnings: | 1180 if not warningText in self.warnings: |
1587 self.warnings.append(warningText) | 1181 self.warnings.append(warningText) |
1588 | 1182 |
1589 cwd = os.getcwd() | 1183 cwd = os.getcwd() |
1590 self.ChangeToDepotWorkingDirectory('chromium') | 1184 self.ChangeToDepotWorkingDirectory('chromium') |
1591 return_code = CheckRunGit(['log', '-1', '--format=%H', | 1185 cmd = ['log', '-1', '--format=%H', |
1592 '--author=chrome-release@google.com', '--grep=to %s' % version, | 1186 '--author=chrome-release@google.com', |
1593 'origin/master']) | 1187 '--grep=to %s' % version, 'origin/master'] |
| 1188 return_code = bisect_utils.CheckRunGit(cmd) |
1594 os.chdir(cwd) | 1189 os.chdir(cwd) |
1595 | 1190 |
1596 results['chromium'] = output.strip() | 1191 results['chromium'] = output.strip() |
1597 elif depot == 'v8': | 1192 elif depot == 'v8': |
1598 # We can't try to map the trunk revision to bleeding edge yet, because | 1193 # We can't try to map the trunk revision to bleeding edge yet, because |
1599 # we don't know which direction to try to search in. Have to wait until | 1194 # we don't know which direction to try to search in. Have to wait until |
1600 # the bisect has narrowed the results down to 2 v8 rolls. | 1195 # the bisect has narrowed the results down to 2 v8 rolls. |
1601 results['v8_bleeding_edge'] = None | 1196 results['v8_bleeding_edge'] = None |
1602 | 1197 |
1603 return results | 1198 return results |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1797 # Get SVN revision for the given SHA. | 1392 # Get SVN revision for the given SHA. |
1798 svn_revision = self.source_control.SVNFindRev(revision) | 1393 svn_revision = self.source_control.SVNFindRev(revision) |
1799 if not svn_revision: | 1394 if not svn_revision: |
1800 raise RuntimeError( | 1395 raise RuntimeError( |
1801 'Failed to determine SVN revision for %s' % revision) | 1396 'Failed to determine SVN revision for %s' % revision) |
1802 | 1397 |
1803 def GetBuilderNameAndBuildTime(target_platform, target_arch='ia32'): | 1398 def GetBuilderNameAndBuildTime(target_platform, target_arch='ia32'): |
1804 """Gets builder bot name and buildtime in seconds based on platform.""" | 1399 """Gets builder bot name and buildtime in seconds based on platform.""" |
1805 # Bot names should match the one listed in tryserver.chromium's | 1400 # Bot names should match the one listed in tryserver.chromium's |
1806 # master.cfg which produces builds for bisect. | 1401 # master.cfg which produces builds for bisect. |
1807 if IsWindowsHost(): | 1402 if bisect_utils.IsWindowsHost(): |
1808 if Is64BitWindows() and target_arch == 'x64': | 1403 if bisect_utils.Is64BitWindows() and target_arch == 'x64': |
1809 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) | 1404 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) |
1810 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) | 1405 return ('win_perf_bisect_builder', MAX_WIN_BUILD_TIME) |
1811 if IsLinuxHost(): | 1406 if bisect_utils.IsLinuxHost(): |
1812 if target_platform == 'android': | 1407 if target_platform == 'android': |
1813 return ('android_perf_bisect_builder', MAX_LINUX_BUILD_TIME) | 1408 return ('android_perf_bisect_builder', MAX_LINUX_BUILD_TIME) |
1814 return ('linux_perf_bisect_builder', MAX_LINUX_BUILD_TIME) | 1409 return ('linux_perf_bisect_builder', MAX_LINUX_BUILD_TIME) |
1815 if IsMacHost(): | 1410 if bisect_utils.IsMacHost(): |
1816 return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME) | 1411 return ('mac_perf_bisect_builder', MAX_MAC_BUILD_TIME) |
1817 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) | 1412 raise NotImplementedError('Unsupported Platform "%s".' % sys.platform) |
1818 if not fetch_build: | 1413 if not fetch_build: |
1819 return False | 1414 return False |
1820 | 1415 |
1821 bot_name, build_timeout = GetBuilderNameAndBuildTime( | 1416 bot_name, build_timeout = GetBuilderNameAndBuildTime( |
1822 self.opts.target_platform, self.opts.target_arch) | 1417 self.opts.target_platform, self.opts.target_arch) |
1823 builder_host = self.opts.builder_host | 1418 builder_host = self.opts.builder_host |
1824 builder_port = self.opts.builder_port | 1419 builder_port = self.opts.builder_port |
1825 # Create a unique ID for each build request posted to tryserver builders. | 1420 # Create a unique ID for each build request posted to tryserver builders. |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2001 depot: Current depot being bisected. | 1596 depot: Current depot being bisected. |
2002 revision: A git hash revision of the dependency repository. | 1597 revision: A git hash revision of the dependency repository. |
2003 | 1598 |
2004 Returns: | 1599 Returns: |
2005 A tuple with git hash of chromium revision and DEPS patch text. | 1600 A tuple with git hash of chromium revision and DEPS patch text. |
2006 """ | 1601 """ |
2007 deps_file_path = os.path.join(self.src_cwd, bisect_utils.FILE_DEPS) | 1602 deps_file_path = os.path.join(self.src_cwd, bisect_utils.FILE_DEPS) |
2008 if not os.path.exists(deps_file_path): | 1603 if not os.path.exists(deps_file_path): |
2009 raise RuntimeError('DEPS file does not exists.[%s]' % deps_file_path) | 1604 raise RuntimeError('DEPS file does not exists.[%s]' % deps_file_path) |
2010 # Get current chromium revision (git hash). | 1605 # Get current chromium revision (git hash). |
2011 chromium_sha = CheckRunGit(['rev-parse', 'HEAD']).strip() | 1606 cmd = ['rev-parse', 'HEAD'] |
| 1607 chromium_sha = bisect_utils.CheckRunGit(cmd).strip() |
2012 if not chromium_sha: | 1608 if not chromium_sha: |
2013 raise RuntimeError('Failed to determine Chromium revision for %s' % | 1609 raise RuntimeError('Failed to determine Chromium revision for %s' % |
2014 revision) | 1610 revision) |
2015 if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or | 1611 if ('chromium' in DEPOT_DEPS_NAME[depot]['from'] or |
2016 'v8' in DEPOT_DEPS_NAME[depot]['from']): | 1612 'v8' in DEPOT_DEPS_NAME[depot]['from']): |
2017 # Checkout DEPS file for the current chromium revision. | 1613 # Checkout DEPS file for the current chromium revision. |
2018 if self.source_control.CheckoutFileAtRevision(bisect_utils.FILE_DEPS, | 1614 if self.source_control.CheckoutFileAtRevision(bisect_utils.FILE_DEPS, |
2019 chromium_sha, | 1615 chromium_sha, |
2020 cwd=self.src_cwd): | 1616 cwd=self.src_cwd): |
2021 if self.UpdateDeps(revision, depot, deps_file_path): | 1617 if self.UpdateDeps(revision, depot, deps_file_path): |
2022 diff_command = ['diff', | 1618 diff_command = ['diff', |
2023 '--src-prefix=src/', | 1619 '--src-prefix=src/', |
2024 '--dst-prefix=src/', | 1620 '--dst-prefix=src/', |
2025 '--no-ext-diff', | 1621 '--no-ext-diff', |
2026 bisect_utils.FILE_DEPS] | 1622 bisect_utils.FILE_DEPS] |
2027 diff_text = CheckRunGit(diff_command, cwd=self.src_cwd) | 1623 diff_text = bisect_utils.CheckRunGit( |
| 1624 diff_command, cwd=self.src_cwd) |
2028 return (chromium_sha, ChangeBackslashToSlashInPatch(diff_text)) | 1625 return (chromium_sha, ChangeBackslashToSlashInPatch(diff_text)) |
2029 else: | 1626 else: |
2030 raise RuntimeError('Failed to update DEPS file for chromium: [%s]' % | 1627 raise RuntimeError('Failed to update DEPS file for chromium: [%s]' % |
2031 chromium_sha) | 1628 chromium_sha) |
2032 else: | 1629 else: |
2033 raise RuntimeError('DEPS checkout Failed for chromium revision : [%s]' % | 1630 raise RuntimeError('DEPS checkout Failed for chromium revision : [%s]' % |
2034 chromium_sha) | 1631 chromium_sha) |
2035 return (None, None) | 1632 return (None, None) |
2036 | 1633 |
2037 def BuildCurrentRevision(self, depot, revision=None): | 1634 def BuildCurrentRevision(self, depot, revision=None): |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2150 single_result_match.group('VALUE')): | 1747 single_result_match.group('VALUE')): |
2151 values_list += [single_result_match.group('VALUE')] | 1748 values_list += [single_result_match.group('VALUE')] |
2152 elif (not multi_results_match is None and | 1749 elif (not multi_results_match is None and |
2153 multi_results_match.group('VALUES')): | 1750 multi_results_match.group('VALUES')): |
2154 metric_values = multi_results_match.group('VALUES') | 1751 metric_values = multi_results_match.group('VALUES') |
2155 values_list += metric_values.split(',') | 1752 values_list += metric_values.split(',') |
2156 elif (not mean_stddev_match is None and | 1753 elif (not mean_stddev_match is None and |
2157 mean_stddev_match.group('MEAN')): | 1754 mean_stddev_match.group('MEAN')): |
2158 values_list += [mean_stddev_match.group('MEAN')] | 1755 values_list += [mean_stddev_match.group('MEAN')] |
2159 | 1756 |
2160 values_list = [float(v) for v in values_list if IsStringFloat(v)] | 1757 values_list = [float(v) for v in values_list |
| 1758 if bisect_utils.IsStringFloat(v)] |
2161 | 1759 |
2162 # If the metric is times/t, we need to sum the timings in order to get | 1760 # If the metric is times/t, we need to sum the timings in order to get |
2163 # similar regression results as the try-bots. | 1761 # similar regression results as the try-bots. |
2164 metrics_to_sum = [['times', 't'], ['times', 'page_load_time'], | 1762 metrics_to_sum = [['times', 't'], ['times', 'page_load_time'], |
2165 ['cold_times', 'page_load_time'], ['warm_times', 'page_load_time']] | 1763 ['cold_times', 'page_load_time'], ['warm_times', 'page_load_time']] |
2166 | 1764 |
2167 if metric in metrics_to_sum: | 1765 if metric in metrics_to_sum: |
2168 if values_list: | 1766 if values_list: |
2169 values_list = [reduce(lambda x, y: float(x) + float(y), values_list)] | 1767 values_list = [reduce(lambda x, y: float(x) + float(y), values_list)] |
2170 | 1768 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2214 # Check 2 cases, --arg=<val> and --arg <val> | 1812 # Check 2 cases, --arg=<val> and --arg <val> |
2215 if len(current_arg_split) == 2: | 1813 if len(current_arg_split) == 2: |
2216 arg_dict[arg_to_parse] = current_arg_split[1] | 1814 arg_dict[arg_to_parse] = current_arg_split[1] |
2217 elif i + 1 < len(command_args): | 1815 elif i + 1 < len(command_args): |
2218 arg_dict[arg_to_parse] = command_args[i+1] | 1816 arg_dict[arg_to_parse] = command_args[i+1] |
2219 | 1817 |
2220 path_to_generate = os.path.join('tools', 'perf', 'generate_profile') | 1818 path_to_generate = os.path.join('tools', 'perf', 'generate_profile') |
2221 | 1819 |
2222 if arg_dict.has_key('--profile-dir') and arg_dict.has_key('--browser'): | 1820 if arg_dict.has_key('--profile-dir') and arg_dict.has_key('--browser'): |
2223 profile_path, profile_type = os.path.split(arg_dict['--profile-dir']) | 1821 profile_path, profile_type = os.path.split(arg_dict['--profile-dir']) |
2224 return not RunProcess(['python', path_to_generate, | 1822 return not bisect_utils.RunProcess(['python', path_to_generate, |
2225 '--profile-type-to-generate', profile_type, | 1823 '--profile-type-to-generate', profile_type, |
2226 '--browser', arg_dict['--browser'], '--output-dir', profile_path]) | 1824 '--browser', arg_dict['--browser'], '--output-dir', profile_path]) |
2227 return False | 1825 return False |
2228 return True | 1826 return True |
2229 | 1827 |
2230 def _IsBisectModeUsingMetric(self): | 1828 def _IsBisectModeUsingMetric(self): |
2231 return self.opts.bisect_mode in [BISECT_MODE_MEAN, BISECT_MODE_STD_DEV] | 1829 return self.opts.bisect_mode in [BISECT_MODE_MEAN, BISECT_MODE_STD_DEV] |
2232 | 1830 |
2233 def _IsBisectModeReturnCode(self): | 1831 def _IsBisectModeReturnCode(self): |
2234 return self.opts.bisect_mode in [BISECT_MODE_RETURN_CODE] | 1832 return self.opts.bisect_mode in [BISECT_MODE_RETURN_CODE] |
2235 | 1833 |
2236 def _IsBisectModeStandardDeviation(self): | 1834 def _IsBisectModeStandardDeviation(self): |
2237 return self.opts.bisect_mode in [BISECT_MODE_STD_DEV] | 1835 return self.opts.bisect_mode in [BISECT_MODE_STD_DEV] |
2238 | 1836 |
2239 def GetCompatibleCommand(self, command_to_run, revision, depot): | 1837 def GetCompatibleCommand(self, command_to_run, revision, depot): |
2240 # Prior to crrev.com/274857 *only* android-chromium-testshell | 1838 # Prior to crrev.com/274857 *only* android-chromium-testshell |
2241 # Then until crrev.com/276628 *both* (android-chromium-testshell and | 1839 # Then until crrev.com/276628 *both* (android-chromium-testshell and |
2242 # android-chrome-shell) work. After that rev 276628 *only* | 1840 # android-chrome-shell) work. After that rev 276628 *only* |
2243 # android-chrome-shell works. bisect-perf-reggresion.py script should | 1841 # android-chrome-shell works. bisect-perf-reggresion.py script should |
2244 # handle these cases and set appropriate browser type based on revision. | 1842 # handle these cases and set appropriate browser type based on revision. |
2245 if self.opts.target_platform in ['android']: | 1843 if self.opts.target_platform in ['android']: |
2246 # When its a third_party depot, get the chromium revision. | 1844 # When its a third_party depot, get the chromium revision. |
2247 if depot != 'chromium': | 1845 if depot != 'chromium': |
2248 revision = CheckRunGit(['rev-parse', 'HEAD'], cwd=self.src_cwd).strip() | 1846 revision = bisect_utils.CheckRunGit( |
| 1847 ['rev-parse', 'HEAD'], cwd=self.src_cwd).strip() |
2249 svn_revision = self.source_control.SVNFindRev(revision, cwd=self.src_cwd) | 1848 svn_revision = self.source_control.SVNFindRev(revision, cwd=self.src_cwd) |
2250 if not svn_revision: | 1849 if not svn_revision: |
2251 return command_to_run | 1850 return command_to_run |
2252 cmd_re = re.compile('--browser=(?P<browser_type>\S+)') | 1851 cmd_re = re.compile('--browser=(?P<browser_type>\S+)') |
2253 matches = cmd_re.search(command_to_run) | 1852 matches = cmd_re.search(command_to_run) |
2254 if IsStringInt(svn_revision) and matches: | 1853 if bisect_utils.IsStringInt(svn_revision) and matches: |
2255 cmd_browser = matches.group('browser_type') | 1854 cmd_browser = matches.group('browser_type') |
2256 if svn_revision <= 274857 and cmd_browser == 'android-chrome-shell': | 1855 if svn_revision <= 274857 and cmd_browser == 'android-chrome-shell': |
2257 return command_to_run.replace(cmd_browser, | 1856 return command_to_run.replace(cmd_browser, |
2258 'android-chromium-testshell') | 1857 'android-chromium-testshell') |
2259 elif (svn_revision >= 276628 and | 1858 elif (svn_revision >= 276628 and |
2260 cmd_browser == 'android-chromium-testshell'): | 1859 cmd_browser == 'android-chromium-testshell'): |
2261 return command_to_run.replace(cmd_browser, | 1860 return command_to_run.replace(cmd_browser, |
2262 'android-chrome-shell') | 1861 'android-chrome-shell') |
2263 return command_to_run | 1862 return command_to_run |
2264 | 1863 |
(...skipping 25 matching lines...) Expand all Loading... |
2290 'mean': 0.0, | 1889 'mean': 0.0, |
2291 'std_err': 0.0, | 1890 'std_err': 0.0, |
2292 'std_dev': 0.0, | 1891 'std_dev': 0.0, |
2293 'values': [0.0] | 1892 'values': [0.0] |
2294 } | 1893 } |
2295 return (fake_results, success_code) | 1894 return (fake_results, success_code) |
2296 | 1895 |
2297 # For Windows platform set posix=False, to parse windows paths correctly. | 1896 # For Windows platform set posix=False, to parse windows paths correctly. |
2298 # On Windows, path separators '\' or '\\' are replace by '' when posix=True, | 1897 # On Windows, path separators '\' or '\\' are replace by '' when posix=True, |
2299 # refer to http://bugs.python.org/issue1724822. By default posix=True. | 1898 # refer to http://bugs.python.org/issue1724822. By default posix=True. |
2300 args = shlex.split(command_to_run, posix=not IsWindowsHost()) | 1899 args = shlex.split(command_to_run, posix=not bisect_utils.IsWindowsHost()) |
2301 | 1900 |
2302 if not self._GenerateProfileIfNecessary(args): | 1901 if not self._GenerateProfileIfNecessary(args): |
2303 err_text = 'Failed to generate profile for performance test.' | 1902 err_text = 'Failed to generate profile for performance test.' |
2304 return (err_text, failure_code) | 1903 return (err_text, failure_code) |
2305 | 1904 |
2306 # If running a Telemetry test for Chrome OS, insert the remote IP and | 1905 # If running a Telemetry test for Chrome OS, insert the remote IP and |
2307 # identity parameters. | 1906 # identity parameters. |
2308 is_telemetry = bisect_utils.IsTelemetryCommand(command_to_run) | 1907 is_telemetry = bisect_utils.IsTelemetryCommand(command_to_run) |
2309 if self.opts.target_platform == 'cros' and is_telemetry: | 1908 if self.opts.target_platform == 'cros' and is_telemetry: |
2310 args.append('--remote=%s' % self.opts.cros_remote_ip) | 1909 args.append('--remote=%s' % self.opts.cros_remote_ip) |
2311 args.append('--identity=%s' % CROS_TEST_KEY_PATH) | 1910 args.append('--identity=%s' % CROS_TEST_KEY_PATH) |
2312 | 1911 |
2313 start_time = time.time() | 1912 start_time = time.time() |
2314 | 1913 |
2315 metric_values = [] | 1914 metric_values = [] |
2316 output_of_all_runs = '' | 1915 output_of_all_runs = '' |
2317 for i in xrange(self.opts.repeat_test_count): | 1916 for i in xrange(self.opts.repeat_test_count): |
2318 # Can ignore the return code since if the tests fail, it won't return 0. | 1917 # Can ignore the return code since if the tests fail, it won't return 0. |
2319 current_args = copy.copy(args) | 1918 current_args = copy.copy(args) |
2320 if is_telemetry: | 1919 if is_telemetry: |
2321 if i == 0 and reset_on_first_run: | 1920 if i == 0 and reset_on_first_run: |
2322 current_args.append('--reset-results') | 1921 current_args.append('--reset-results') |
2323 elif i == self.opts.repeat_test_count - 1 and upload_on_last_run: | 1922 elif i == self.opts.repeat_test_count - 1 and upload_on_last_run: |
2324 current_args.append('--upload-results') | 1923 current_args.append('--upload-results') |
2325 if results_label: | 1924 if results_label: |
2326 current_args.append('--results-label=%s' % results_label) | 1925 current_args.append('--results-label=%s' % results_label) |
2327 try: | 1926 try: |
2328 (output, return_code) = RunProcessAndRetrieveOutput(current_args, | 1927 (output, return_code) = bisect_utils.RunProcessAndRetrieveOutput( |
2329 cwd=self.src_cwd) | 1928 current_args, cwd=self.src_cwd) |
2330 except OSError, e: | 1929 except OSError, e: |
2331 if e.errno == errno.ENOENT: | 1930 if e.errno == errno.ENOENT: |
2332 err_text = ('Something went wrong running the performance test. ' | 1931 err_text = ('Something went wrong running the performance test. ' |
2333 'Please review the command line:\n\n') | 1932 'Please review the command line:\n\n') |
2334 if 'src/' in ' '.join(args): | 1933 if 'src/' in ' '.join(args): |
2335 err_text += ('Check that you haven\'t accidentally specified a ' | 1934 err_text += ('Check that you haven\'t accidentally specified a ' |
2336 'path with src/ in the command.\n\n') | 1935 'path with src/ in the command.\n\n') |
2337 err_text += ' '.join(args) | 1936 err_text += ' '.join(args) |
2338 err_text += '\n' | 1937 err_text += '\n' |
2339 | 1938 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2428 # guarantee that the SVN revision will exist for each of the dependant | 2027 # guarantee that the SVN revision will exist for each of the dependant |
2429 # depots, so we have to grep the git logs and grab the next earlier one. | 2028 # depots, so we have to grep the git logs and grab the next earlier one. |
2430 if not is_base and\ | 2029 if not is_base and\ |
2431 DEPOT_DEPS_NAME[depot]['depends'] and\ | 2030 DEPOT_DEPS_NAME[depot]['depends'] and\ |
2432 self.source_control.IsGit(): | 2031 self.source_control.IsGit(): |
2433 svn_rev = self.source_control.SVNFindRev(revision) | 2032 svn_rev = self.source_control.SVNFindRev(revision) |
2434 | 2033 |
2435 for d in DEPOT_DEPS_NAME[depot]['depends']: | 2034 for d in DEPOT_DEPS_NAME[depot]['depends']: |
2436 self.ChangeToDepotWorkingDirectory(d) | 2035 self.ChangeToDepotWorkingDirectory(d) |
2437 | 2036 |
2438 dependant_rev = self.source_control.ResolveToRevision(svn_rev, d, -1000) | 2037 dependant_rev = self.source_control.ResolveToRevision( |
| 2038 svn_rev, d, DEPOT_DEPS_NAME, -1000) |
2439 | 2039 |
2440 if dependant_rev: | 2040 if dependant_rev: |
2441 revisions_to_sync.append([d, dependant_rev]) | 2041 revisions_to_sync.append([d, dependant_rev]) |
2442 | 2042 |
2443 num_resolved = len(revisions_to_sync) | 2043 num_resolved = len(revisions_to_sync) |
2444 num_needed = len(DEPOT_DEPS_NAME[depot]['depends']) | 2044 num_needed = len(DEPOT_DEPS_NAME[depot]['depends']) |
2445 | 2045 |
2446 self.ChangeToDepotWorkingDirectory(depot) | 2046 self.ChangeToDepotWorkingDirectory(depot) |
2447 | 2047 |
2448 if not ((num_resolved - 1) == num_needed): | 2048 if not ((num_resolved - 1) == num_needed): |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2494 | 2094 |
2495 def PerformCrosChrootCleanup(self): | 2095 def PerformCrosChrootCleanup(self): |
2496 """Deletes the chroot. | 2096 """Deletes the chroot. |
2497 | 2097 |
2498 Returns: | 2098 Returns: |
2499 True if successful. | 2099 True if successful. |
2500 """ | 2100 """ |
2501 cwd = os.getcwd() | 2101 cwd = os.getcwd() |
2502 self.ChangeToDepotWorkingDirectory('cros') | 2102 self.ChangeToDepotWorkingDirectory('cros') |
2503 cmd = [CROS_SDK_PATH, '--delete'] | 2103 cmd = [CROS_SDK_PATH, '--delete'] |
2504 return_code = RunProcess(cmd) | 2104 return_code = bisect_utils.RunProcess(cmd) |
2505 os.chdir(cwd) | 2105 os.chdir(cwd) |
2506 return not return_code | 2106 return not return_code |
2507 | 2107 |
2508 def CreateCrosChroot(self): | 2108 def CreateCrosChroot(self): |
2509 """Creates a new chroot. | 2109 """Creates a new chroot. |
2510 | 2110 |
2511 Returns: | 2111 Returns: |
2512 True if successful. | 2112 True if successful. |
2513 """ | 2113 """ |
2514 cwd = os.getcwd() | 2114 cwd = os.getcwd() |
2515 self.ChangeToDepotWorkingDirectory('cros') | 2115 self.ChangeToDepotWorkingDirectory('cros') |
2516 cmd = [CROS_SDK_PATH, '--create'] | 2116 cmd = [CROS_SDK_PATH, '--create'] |
2517 return_code = RunProcess(cmd) | 2117 return_code = bisect_utils.RunProcess(cmd) |
2518 os.chdir(cwd) | 2118 os.chdir(cwd) |
2519 return not return_code | 2119 return not return_code |
2520 | 2120 |
2521 def PerformPreSyncCleanup(self, revision, depot): | 2121 def PerformPreSyncCleanup(self, revision, depot): |
2522 """Performs any necessary cleanup before syncing. | 2122 """Performs any necessary cleanup before syncing. |
2523 | 2123 |
2524 Returns: | 2124 Returns: |
2525 True if successful. | 2125 True if successful. |
2526 """ | 2126 """ |
2527 if depot == 'chromium' or depot == 'android-chrome': | 2127 if depot == 'chromium' or depot == 'android-chrome': |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2567 Args: | 2167 Args: |
2568 depot: The depot being bisected. | 2168 depot: The depot being bisected. |
2569 revision: Current revision we're synced to. | 2169 revision: Current revision we're synced to. |
2570 | 2170 |
2571 Returns: | 2171 Returns: |
2572 True if we should skip building/testing this revision. | 2172 True if we should skip building/testing this revision. |
2573 """ | 2173 """ |
2574 if depot == 'chromium': | 2174 if depot == 'chromium': |
2575 if self.source_control.IsGit(): | 2175 if self.source_control.IsGit(): |
2576 cmd = ['diff-tree', '--no-commit-id', '--name-only', '-r', revision] | 2176 cmd = ['diff-tree', '--no-commit-id', '--name-only', '-r', revision] |
2577 output = CheckRunGit(cmd) | 2177 output = bisect_utils.CheckRunGit(cmd) |
2578 | 2178 |
2579 files = output.splitlines() | 2179 files = output.splitlines() |
2580 | 2180 |
2581 if len(files) == 1 and files[0] == 'DEPS': | 2181 if len(files) == 1 and files[0] == 'DEPS': |
2582 return True | 2182 return True |
2583 | 2183 |
2584 return False | 2184 return False |
2585 | 2185 |
2586 def SyncBuildAndRunRevision(self, revision, depot, command_to_run, metric, | 2186 def SyncBuildAndRunRevision(self, revision, depot, command_to_run, metric, |
2587 skippable=False): | 2187 skippable=False): |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2924 if changes_to_deps: | 2524 if changes_to_deps: |
2925 # DEPS file was changed, search from the oldest change to DEPS file to | 2525 # DEPS file was changed, search from the oldest change to DEPS file to |
2926 # bad_revision to see if there are matching .DEPS.git changes. | 2526 # bad_revision to see if there are matching .DEPS.git changes. |
2927 oldest_deps_change = changes_to_deps[-1] | 2527 oldest_deps_change = changes_to_deps[-1] |
2928 changes_to_gitdeps = self.source_control.QueryFileRevisionHistory( | 2528 changes_to_gitdeps = self.source_control.QueryFileRevisionHistory( |
2929 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) | 2529 bisect_utils.FILE_DEPS_GIT, oldest_deps_change, bad_revision) |
2930 | 2530 |
2931 if len(changes_to_deps) != len(changes_to_gitdeps): | 2531 if len(changes_to_deps) != len(changes_to_gitdeps): |
2932 # Grab the timestamp of the last DEPS change | 2532 # Grab the timestamp of the last DEPS change |
2933 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] | 2533 cmd = ['log', '--format=%ct', '-1', changes_to_deps[0]] |
2934 output = CheckRunGit(cmd) | 2534 output = bisect_utils.CheckRunGit(cmd) |
2935 commit_time = int(output) | 2535 commit_time = int(output) |
2936 | 2536 |
2937 # Try looking for a commit that touches the .DEPS.git file in the | 2537 # Try looking for a commit that touches the .DEPS.git file in the |
2938 # next 15 minutes after the DEPS file change. | 2538 # next 15 minutes after the DEPS file change. |
2939 cmd = ['log', '--format=%H', '-1', | 2539 cmd = ['log', '--format=%H', '-1', |
2940 '--before=%d' % (commit_time + 900), '--after=%d' % commit_time, | 2540 '--before=%d' % (commit_time + 900), '--after=%d' % commit_time, |
2941 'origin/master', bisect_utils.FILE_DEPS_GIT] | 2541 'origin/master', bisect_utils.FILE_DEPS_GIT] |
2942 output = CheckRunGit(cmd) | 2542 output = bisect_utils.CheckRunGit(cmd) |
2943 output = output.strip() | 2543 output = output.strip() |
2944 if output: | 2544 if output: |
2945 self.warnings.append('Detected change to DEPS and modified ' | 2545 self.warnings.append('Detected change to DEPS and modified ' |
2946 'revision range to include change to .DEPS.git') | 2546 'revision range to include change to .DEPS.git') |
2947 return (output, good_revision) | 2547 return (output, good_revision) |
2948 else: | 2548 else: |
2949 self.warnings.append('Detected change to DEPS but couldn\'t find ' | 2549 self.warnings.append('Detected change to DEPS but couldn\'t find ' |
2950 'matching change to .DEPS.git') | 2550 'matching change to .DEPS.git') |
2951 return (bad_revision, good_revision) | 2551 return (bad_revision, good_revision) |
2952 | 2552 |
2953 def CheckIfRevisionsInProperOrder(self, | 2553 def CheckIfRevisionsInProperOrder(self, |
2954 target_depot, | 2554 target_depot, |
2955 good_revision, | 2555 good_revision, |
2956 bad_revision): | 2556 bad_revision): |
2957 """Checks that |good_revision| is an earlier revision than |bad_revision|. | 2557 """Checks that |good_revision| is an earlier revision than |bad_revision|. |
2958 | 2558 |
2959 Args: | 2559 Args: |
2960 good_revision: Number/tag of the known good revision. | 2560 good_revision: Number/tag of the known good revision. |
2961 bad_revision: Number/tag of the known bad revision. | 2561 bad_revision: Number/tag of the known bad revision. |
2962 | 2562 |
2963 Returns: | 2563 Returns: |
2964 True if the revisions are in the proper order (good earlier than bad). | 2564 True if the revisions are in the proper order (good earlier than bad). |
2965 """ | 2565 """ |
2966 if self.source_control.IsGit() and target_depot != 'cros': | 2566 if self.source_control.IsGit() and target_depot != 'cros': |
2967 cmd = ['log', '--format=%ct', '-1', good_revision] | 2567 cmd = ['log', '--format=%ct', '-1', good_revision] |
2968 cwd = self._GetDepotDirectory(target_depot) | 2568 cwd = self._GetDepotDirectory(target_depot) |
2969 | 2569 |
2970 output = CheckRunGit(cmd, cwd=cwd) | 2570 output = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
2971 good_commit_time = int(output) | 2571 good_commit_time = int(output) |
2972 | 2572 |
2973 cmd = ['log', '--format=%ct', '-1', bad_revision] | 2573 cmd = ['log', '--format=%ct', '-1', bad_revision] |
2974 output = CheckRunGit(cmd, cwd=cwd) | 2574 output = bisect_utils.CheckRunGit(cmd, cwd=cwd) |
2975 bad_commit_time = int(output) | 2575 bad_commit_time = int(output) |
2976 | 2576 |
2977 return good_commit_time <= bad_commit_time | 2577 return good_commit_time <= bad_commit_time |
2978 else: | 2578 else: |
2979 # Cros/svn use integers | 2579 # Cros/svn use integers |
2980 return int(good_revision) <= int(bad_revision) | 2580 return int(good_revision) <= int(bad_revision) |
2981 | 2581 |
2982 def CanPerformBisect(self, revision_to_check): | 2582 def CanPerformBisect(self, revision_to_check): |
2983 """Checks whether a given revision is bisectable. | 2583 """Checks whether a given revision is bisectable. |
2984 | 2584 |
2985 Note: At present it checks whether a given revision is bisectable on | 2585 Note: At present it checks whether a given revision is bisectable on |
2986 android bots(refer crbug.com/385324). | 2586 android bots(refer crbug.com/385324). |
2987 | 2587 |
2988 Args: | 2588 Args: |
2989 revision_to_check: Known good revision. | 2589 revision_to_check: Known good revision. |
2990 | 2590 |
2991 Returns: | 2591 Returns: |
2992 A dictionary indicating the result. If revision is not bisectable, | 2592 A dictionary indicating the result. If revision is not bisectable, |
2993 this will contain the field "error", otherwise None. | 2593 this will contain the field "error", otherwise None. |
2994 """ | 2594 """ |
2995 if self.opts.target_platform == 'android': | 2595 if self.opts.target_platform == 'android': |
2996 revision_to_check = self.source_control.SVNFindRev(revision_to_check) | 2596 revision_to_check = self.source_control.SVNFindRev(revision_to_check) |
2997 if IsStringInt(revision_to_check) and revision_to_check < 265549: | 2597 if (bisect_utils.IsStringInt(revision_to_check) |
| 2598 and revision_to_check < 265549): |
2998 return {'error': ( | 2599 return {'error': ( |
2999 'Bisect cannot conitnue for the given revision range.\n' | 2600 'Bisect cannot conitnue for the given revision range.\n' |
3000 'It is impossible to bisect Android regressions ' | 2601 'It is impossible to bisect Android regressions ' |
3001 'prior to r265549, which allows the bisect bot to ' | 2602 'prior to r265549, which allows the bisect bot to ' |
3002 'rely on Telemetry to do apk installation of the most recently ' | 2603 'rely on Telemetry to do apk installation of the most recently ' |
3003 'built local ChromeShell(refer to crbug.com/385324).\n' | 2604 'built local ChromeShell(refer to crbug.com/385324).\n' |
3004 'Please try bisecting revisions greater than or equal to r265549.')} | 2605 'Please try bisecting revisions greater than or equal to r265549.')} |
3005 return None | 2606 return None |
3006 | 2607 |
3007 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): | 2608 def Run(self, command_to_run, bad_revision_in, good_revision_in, metric): |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3054 target_depot = 'chromium' | 2655 target_depot = 'chromium' |
3055 if self.opts.target_platform == 'cros': | 2656 if self.opts.target_platform == 'cros': |
3056 target_depot = 'cros' | 2657 target_depot = 'cros' |
3057 elif self.opts.target_platform == 'android-chrome': | 2658 elif self.opts.target_platform == 'android-chrome': |
3058 target_depot = 'android-chrome' | 2659 target_depot = 'android-chrome' |
3059 | 2660 |
3060 cwd = os.getcwd() | 2661 cwd = os.getcwd() |
3061 self.ChangeToDepotWorkingDirectory(target_depot) | 2662 self.ChangeToDepotWorkingDirectory(target_depot) |
3062 | 2663 |
3063 # If they passed SVN CL's, etc... we can try match them to git SHA1's. | 2664 # If they passed SVN CL's, etc... we can try match them to git SHA1's. |
3064 bad_revision = self.source_control.ResolveToRevision(bad_revision_in, | 2665 bad_revision = self.source_control.ResolveToRevision( |
3065 target_depot, 100) | 2666 bad_revision_in, target_depot, DEPOT_DEPS_NAME, 100) |
3066 good_revision = self.source_control.ResolveToRevision(good_revision_in, | 2667 good_revision = self.source_control.ResolveToRevision( |
3067 target_depot, -100) | 2668 good_revision_in, target_depot, DEPOT_DEPS_NAME, -100) |
3068 | 2669 |
3069 os.chdir(cwd) | 2670 os.chdir(cwd) |
3070 | 2671 |
3071 | 2672 |
3072 if bad_revision is None: | 2673 if bad_revision is None: |
3073 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,) | 2674 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (bad_revision_in,) |
3074 return results | 2675 return results |
3075 | 2676 |
3076 if good_revision is None: | 2677 if good_revision is None: |
3077 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,) | 2678 results['error'] = 'Could\'t resolve [%s] to SHA1.' % (good_revision_in,) |
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3649 cwd = os.getcwd() | 3250 cwd = os.getcwd() |
3650 self.ChangeToDepotWorkingDirectory( | 3251 self.ChangeToDepotWorkingDirectory( |
3651 revision_data[last_broken_revision]['depot']) | 3252 revision_data[last_broken_revision]['depot']) |
3652 | 3253 |
3653 if revision_data[last_broken_revision]['depot'] == 'cros': | 3254 if revision_data[last_broken_revision]['depot'] == 'cros': |
3654 # Want to get a list of all the commits and what depots they belong | 3255 # Want to get a list of all the commits and what depots they belong |
3655 # to so that we can grab info about each. | 3256 # to so that we can grab info about each. |
3656 cmd = ['repo', 'forall', '-c', | 3257 cmd = ['repo', 'forall', '-c', |
3657 'pwd ; git log --pretty=oneline --before=%d --after=%d' % ( | 3258 'pwd ; git log --pretty=oneline --before=%d --after=%d' % ( |
3658 last_broken_revision, first_working_revision + 1)] | 3259 last_broken_revision, first_working_revision + 1)] |
3659 (output, return_code) = RunProcessAndRetrieveOutput(cmd) | 3260 (output, return_code) = bisect_utils.RunProcessAndRetrieveOutput(cmd) |
3660 | 3261 |
3661 changes = [] | 3262 changes = [] |
3662 assert not return_code, 'An error occurred while running'\ | 3263 assert not return_code, 'An error occurred while running'\ |
3663 ' "%s"' % ' '.join(cmd) | 3264 ' "%s"' % ' '.join(cmd) |
3664 last_depot = None | 3265 last_depot = None |
3665 cwd = os.getcwd() | 3266 cwd = os.getcwd() |
3666 for l in output.split('\n'): | 3267 for l in output.split('\n'): |
3667 if l: | 3268 if l: |
3668 # Output will be in form: | 3269 # Output will be in form: |
3669 # /path_to_depot | 3270 # /path_to_depot |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3777 results_dict['first_working_revision'], | 3378 results_dict['first_working_revision'], |
3778 results_dict['last_broken_revision'], | 3379 results_dict['last_broken_revision'], |
3779 results_dict['confidence']) | 3380 results_dict['confidence']) |
3780 self._PrintStepTime(revision_data_sorted) | 3381 self._PrintStepTime(revision_data_sorted) |
3781 self._PrintReproSteps() | 3382 self._PrintReproSteps() |
3782 self._PrintThankYou() | 3383 self._PrintThankYou() |
3783 if self.opts.output_buildbot_annotations: | 3384 if self.opts.output_buildbot_annotations: |
3784 bisect_utils.OutputAnnotationStepClosed() | 3385 bisect_utils.OutputAnnotationStepClosed() |
3785 | 3386 |
3786 | 3387 |
3787 def DetermineAndCreateSourceControl(opts): | |
3788 """Attempts to determine the underlying source control workflow and returns | |
3789 a SourceControl object. | |
3790 | |
3791 Returns: | |
3792 An instance of a SourceControl object, or None if the current workflow | |
3793 is unsupported. | |
3794 """ | |
3795 | |
3796 (output, _) = RunGit(['rev-parse', '--is-inside-work-tree']) | |
3797 | |
3798 if output.strip() == 'true': | |
3799 return GitSourceControl(opts) | |
3800 | |
3801 return None | |
3802 | |
3803 | |
3804 def IsPlatformSupported(opts): | 3388 def IsPlatformSupported(opts): |
3805 """Checks that this platform and build system are supported. | 3389 """Checks that this platform and build system are supported. |
3806 | 3390 |
3807 Args: | 3391 Args: |
3808 opts: The options parsed from the command line. | 3392 opts: The options parsed from the command line. |
3809 | 3393 |
3810 Returns: | 3394 Returns: |
3811 True if the platform and build system are supported. | 3395 True if the platform and build system are supported. |
3812 """ | 3396 """ |
3813 # Haven't tested the script out on any other platforms yet. | 3397 # Haven't tested the script out on any other platforms yet. |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4057 if not opts.builder_host: | 3641 if not opts.builder_host: |
4058 raise RuntimeError('Must specify try server hostname, when ' | 3642 raise RuntimeError('Must specify try server hostname, when ' |
4059 'gs_bucket is used: --builder_host') | 3643 'gs_bucket is used: --builder_host') |
4060 if not opts.builder_port: | 3644 if not opts.builder_port: |
4061 raise RuntimeError('Must specify try server port number, when ' | 3645 raise RuntimeError('Must specify try server port number, when ' |
4062 'gs_bucket is used: --builder_port') | 3646 'gs_bucket is used: --builder_port') |
4063 if opts.target_platform == 'cros': | 3647 if opts.target_platform == 'cros': |
4064 # Run sudo up front to make sure credentials are cached for later. | 3648 # Run sudo up front to make sure credentials are cached for later. |
4065 print 'Sudo is required to build cros:' | 3649 print 'Sudo is required to build cros:' |
4066 print | 3650 print |
4067 RunProcess(['sudo', 'true']) | 3651 bisect_utils.RunProcess(['sudo', 'true']) |
4068 | 3652 |
4069 if not opts.cros_board: | 3653 if not opts.cros_board: |
4070 raise RuntimeError('missing required parameter: --cros_board') | 3654 raise RuntimeError('missing required parameter: --cros_board') |
4071 | 3655 |
4072 if not opts.cros_remote_ip: | 3656 if not opts.cros_remote_ip: |
4073 raise RuntimeError('missing required parameter: --cros_remote_ip') | 3657 raise RuntimeError('missing required parameter: --cros_remote_ip') |
4074 | 3658 |
4075 if not opts.working_directory: | 3659 if not opts.working_directory: |
4076 raise RuntimeError('missing required parameter: --working_directory') | 3660 raise RuntimeError('missing required parameter: --working_directory') |
4077 | 3661 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4145 bisect_utils.CreateBisectDirectoryAndSetupDepot(opts, custom_deps) | 3729 bisect_utils.CreateBisectDirectoryAndSetupDepot(opts, custom_deps) |
4146 | 3730 |
4147 os.chdir(os.path.join(os.getcwd(), 'src')) | 3731 os.chdir(os.path.join(os.getcwd(), 'src')) |
4148 | 3732 |
4149 if not RemoveBuildFiles(opts.target_build_type): | 3733 if not RemoveBuildFiles(opts.target_build_type): |
4150 raise RuntimeError('Something went wrong removing the build files.') | 3734 raise RuntimeError('Something went wrong removing the build files.') |
4151 | 3735 |
4152 if not IsPlatformSupported(opts): | 3736 if not IsPlatformSupported(opts): |
4153 raise RuntimeError("Sorry, this platform isn't supported yet.") | 3737 raise RuntimeError("Sorry, this platform isn't supported yet.") |
4154 | 3738 |
4155 # Check what source control method they're using. Only support git workflow | 3739 # Check what source control method is being used, and create a |
4156 # at the moment. | 3740 # SourceControl object if possible. |
4157 source_control = DetermineAndCreateSourceControl(opts) | 3741 source_control = source_control_module.DetermineAndCreateSourceControl(opts) |
4158 | 3742 |
4159 if not source_control: | 3743 if not source_control: |
4160 raise RuntimeError("Sorry, only the git workflow is supported at the " | 3744 raise RuntimeError("Sorry, only the git workflow is supported at the " |
4161 "moment.") | 3745 "moment.") |
4162 | 3746 |
4163 # gClient sync seems to fail if you're not in master branch. | 3747 # gClient sync seems to fail if you're not in master branch. |
4164 if (not source_control.IsInProperBranch() and | 3748 if (not source_control.IsInProperBranch() and |
4165 not opts.debug_ignore_sync and | 3749 not opts.debug_ignore_sync and |
4166 not opts.working_directory): | 3750 not opts.working_directory): |
4167 raise RuntimeError("You must switch to master branch to run bisection.") | 3751 raise RuntimeError("You must switch to master branch to run bisection.") |
(...skipping 14 matching lines...) Expand all Loading... |
4182 # The perf dashboard scrapes the "results" step in order to comment on | 3766 # The perf dashboard scrapes the "results" step in order to comment on |
4183 # bugs. If you change this, please update the perf dashboard as well. | 3767 # bugs. If you change this, please update the perf dashboard as well. |
4184 bisect_utils.OutputAnnotationStepStart('Results') | 3768 bisect_utils.OutputAnnotationStepStart('Results') |
4185 print 'Error: %s' % e.message | 3769 print 'Error: %s' % e.message |
4186 if opts.output_buildbot_annotations: | 3770 if opts.output_buildbot_annotations: |
4187 bisect_utils.OutputAnnotationStepClosed() | 3771 bisect_utils.OutputAnnotationStepClosed() |
4188 return 1 | 3772 return 1 |
4189 | 3773 |
4190 if __name__ == '__main__': | 3774 if __name__ == '__main__': |
4191 sys.exit(main()) | 3775 sys.exit(main()) |
OLD | NEW |