OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2014 The Chromium Authors. All rights reserved. | 2 # Copyright 2014 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 """Starts bisect try jobs on multiple platforms using known-good configs. | 6 """Starts bisect try jobs on multiple platforms using known-good configs. |
7 | 7 |
8 The purpose of this script is to serve as an integration test for the | 8 The purpose of this script is to serve as an integration test for the |
9 auto-bisect project by starting try jobs for various config types and | 9 auto-bisect project by starting try jobs for various config types and |
10 various platforms. | 10 various platforms. |
(...skipping 10 matching lines...) Expand all Loading... |
21 import logging | 21 import logging |
22 import os | 22 import os |
23 import subprocess | 23 import subprocess |
24 import sys | 24 import sys |
25 | 25 |
26 SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) | 26 SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) |
27 BISECT_CONFIG = os.path.join(SCRIPT_DIR, os.path.pardir, 'bisect.cfg') | 27 BISECT_CONFIG = os.path.join(SCRIPT_DIR, os.path.pardir, 'bisect.cfg') |
28 PERF_TEST_CONFIG = os.path.join( | 28 PERF_TEST_CONFIG = os.path.join( |
29 SCRIPT_DIR, os.path.pardir, os.path.pardir, 'run-perf-test.cfg') | 29 SCRIPT_DIR, os.path.pardir, os.path.pardir, 'run-perf-test.cfg') |
30 PLATFORM_BOT_MAP = { | 30 PLATFORM_BOT_MAP = { |
31 'linux': ['linux_perf_bot'], | 31 'linux': ['linux_perf_bisect'], |
32 'mac': ['mac_perf_bisect', 'mac_10_9_perf_bisect'], | 32 'mac': ['mac_perf_bisect', 'mac_10_9_perf_bisect'], |
33 'win': ['win_perf_bisect', 'win_8_perf_bisect', 'win_xp_perf_bisect'], | 33 'win': ['win_perf_bisect', 'win_8_perf_bisect', 'win_xp_perf_bisect'], |
34 'android': [ | 34 'android': [ |
| 35 'android_gn_perf_bisect', |
35 'android_nexus4_perf_bisect', | 36 'android_nexus4_perf_bisect', |
36 'android_nexus5_perf_bisect', | 37 'android_nexus5_perf_bisect', |
37 'android_nexus7_perf_bisect', | 38 'android_nexus7_perf_bisect', |
38 'android_nexus10_perf_bisect', | 39 'android_nexus10_perf_bisect', |
39 ], | 40 ], |
40 } | 41 } |
41 SVN_URL = 'svn://svn.chromium.org/chrome-try/try-perf' | 42 SVN_URL = 'svn://svn.chromium.org/chrome-try/try-perf' |
42 AUTO_COMMIT_MESSAGE = 'Automatic commit for bisect try job.' | 43 AUTO_COMMIT_MESSAGE = 'Automatic commit for bisect try job.' |
43 | 44 |
44 | 45 |
45 def main(argv): | 46 def main(argv): |
46 parser = argparse.ArgumentParser(description=__doc__) | 47 parser = argparse.ArgumentParser(description=__doc__) |
47 parser.add_argument('--full', action='store_true', | 48 parser.add_argument('--full', action='store_true', |
48 help='Run each config on all applicable bots.') | 49 help='Run each config on all applicable bots.') |
49 parser.add_argument('--filter', | 50 parser.add_argument('configs', nargs='+', |
50 help='Filter for config filenames to use. Only configs ' | 51 help='One or more sample config files.') |
51 'containing the given substring will be tried.') | 52 parser.add_argument('--verbose', '-v', action='store_true', |
52 parser.add_argument('--verbose', '-v', action='store_true') | 53 help='Output additional debugging information.') |
| 54 parser.add_argument('--dry-run', action='store_true', |
| 55 help='Don\'t execute "git try" while running.') |
53 args = parser.parse_args(argv[1:]) | 56 args = parser.parse_args(argv[1:]) |
54 _SetupLogging(args.verbose) | 57 _SetupLogging(args.verbose) |
55 source_configs = _SourceConfigs(args.filter) | 58 logging.debug('Source configs: %s', args.configs) |
56 logging.debug('Source configs: %s', source_configs) | |
57 try: | 59 try: |
58 _StartTryJobs(source_configs, args.full) | 60 _StartTryJobs(args.configs, args.full, args.dry_run) |
59 except subprocess.CalledProcessError as error: | 61 except subprocess.CalledProcessError as error: |
60 print str(error) | 62 print str(error) |
61 print error.output | 63 print error.output |
62 | 64 |
63 | 65 |
64 def _SetupLogging(verbose): | 66 def _SetupLogging(verbose): |
65 level = logging.INFO | 67 level = logging.INFO |
66 if verbose: | 68 if verbose: |
67 level = logging.DEBUG | 69 level = logging.DEBUG |
68 logging.basicConfig(level=level) | 70 logging.basicConfig(level=level) |
69 | 71 |
70 | 72 |
71 def _SourceConfigs(name_filter): | 73 def _StartTryJobs(source_configs, full_mode=False, dry_run=False): |
72 """Gets a list of paths to sample configs to try.""" | |
73 files = os.listdir(SCRIPT_DIR) | |
74 files = [os.path.join(SCRIPT_DIR, name) for name in files] | |
75 files = [name for name in files if name.endswith('.cfg')] | |
76 if name_filter: | |
77 files = [name for name in files if name_filter in name] | |
78 return files | |
79 | |
80 | |
81 def _StartTryJobs(source_configs, full_mode=False): | |
82 """Tries each of the given sample configs on one or more try bots.""" | 74 """Tries each of the given sample configs on one or more try bots.""" |
83 for source_config in source_configs: | 75 for source_config in source_configs: |
84 dest_config = _DestConfig(source_config) | 76 dest_config = _DestConfig(source_config) |
85 bot_names = _BotNames(source_config, full_mode=full_mode) | 77 bot_names = _BotNames(source_config, full_mode=full_mode) |
86 _StartTry(source_config, dest_config, bot_names) | 78 _StartTry(source_config, dest_config, bot_names, dry_run=dry_run) |
87 | 79 |
88 | 80 |
89 def _DestConfig(source_config): | 81 def _DestConfig(source_config): |
90 """Returns the path that a sample config should be copied to.""" | 82 """Returns the path that a sample config should be copied to.""" |
91 if 'bisect' in source_config: | 83 if 'bisect' in source_config: |
92 return BISECT_CONFIG | 84 return BISECT_CONFIG |
93 assert 'perf_test' in source_config, source_config | 85 assert 'perf_test' in source_config, source_config |
94 return PERF_TEST_CONFIG | 86 return PERF_TEST_CONFIG |
95 | 87 |
96 | 88 |
97 def _BotNames(source_config, full_mode=False): | 89 def _BotNames(source_config, full_mode=False): |
98 """Returns try bot names to use for the given config file name.""" | 90 """Returns try bot names to use for the given config file name.""" |
99 platform = os.path.basename(source_config).split('.')[0] | 91 platform = os.path.basename(source_config).split('.')[0] |
100 assert platform in PLATFORM_BOT_MAP | 92 assert platform in PLATFORM_BOT_MAP |
101 bot_names = PLATFORM_BOT_MAP[platform] | 93 bot_names = PLATFORM_BOT_MAP[platform] |
102 if full_mode: | 94 if full_mode: |
103 return bot_names | 95 return bot_names |
104 return [bot_names[0]] | 96 return [bot_names[0]] |
105 | 97 |
106 | 98 |
107 def _StartTry(source_config, dest_config, bot_names): | 99 def _StartTry(source_config, dest_config, bot_names, dry_run=False): |
108 """Sends a try job with the given config to the given try bots. | 100 """Sends a try job with the given config to the given try bots. |
109 | 101 |
110 Args: | 102 Args: |
111 source_config: Path of the sample config to copy over. | 103 source_config: Path of the sample config to copy over. |
112 dest_config: Destination path to copy sample to, e.g. "./bisect.cfg". | 104 dest_config: Destination path to copy sample to, e.g. "./bisect.cfg". |
113 bot_names: List of try bot builder names. | 105 bot_names: List of try bot builder names. |
114 """ | 106 """ |
115 assert os.path.exists(source_config) | 107 assert os.path.exists(source_config) |
116 assert os.path.exists(dest_config) | 108 assert os.path.exists(dest_config) |
117 assert _LastCommitMessage() != AUTO_COMMIT_MESSAGE | 109 assert _LastCommitMessage() != AUTO_COMMIT_MESSAGE |
118 | 110 |
119 # Copy the sample config over and commit it. | 111 # Copy the sample config over and commit it. |
120 _Run(['cp', source_config, dest_config]) | 112 _Run(['cp', source_config, dest_config]) |
121 _Run(['git', 'commit', '--all', '-m', AUTO_COMMIT_MESSAGE]) | 113 _Run(['git', 'commit', '--all', '-m', AUTO_COMMIT_MESSAGE]) |
122 | 114 |
123 try: | 115 try: |
124 # Start the try job. | 116 # Start the try job. |
125 job_name = 'Automatically-started (%s)' % os.path.basename(source_config) | 117 job_name = 'Automatically-started (%s)' % os.path.basename(source_config) |
126 try_command = ['git', 'try', '--svn_repo', SVN_URL, '-n', job_name] | 118 try_command = ['git', 'try', '--svn_repo', SVN_URL, '--name', job_name] |
127 for bot_name in bot_names: | 119 for bot_name in bot_names: |
128 try_command.extend(['-b', bot_name]) | 120 try_command.extend(['--bot', bot_name]) |
129 print _Run(try_command) | 121 print _Run(try_command, dry_run=dry_run) |
130 finally: | 122 finally: |
131 # Revert the immediately-previous commit which was made just above. | 123 # Revert the immediately-previous commit which was made just above. |
132 assert _LastCommitMessage() == AUTO_COMMIT_MESSAGE | 124 assert _LastCommitMessage() == AUTO_COMMIT_MESSAGE |
133 _Run(['git', 'reset', '--hard', 'HEAD~1']) | 125 _Run(['git', 'reset', '--hard', 'HEAD~1']) |
134 | 126 |
135 | 127 |
136 def _LastCommitMessage(): | 128 def _LastCommitMessage(): |
137 return _Run(['git', 'log', '--format=%s', '-1']).strip() | 129 return _Run(['git', 'log', '--format=%s', '-1']).strip() |
138 | 130 |
139 | 131 |
140 def _Run(command): | 132 def _Run(command, dry_run=False): |
141 """Runs a command in a subprocess. | 133 """Runs a command in a subprocess. |
142 | 134 |
143 Args: | 135 Args: |
144 command: The command given as an args list. | 136 command: The command given as an args list. |
145 | 137 |
146 Returns: | 138 Returns: |
147 The output of the command. | 139 The output of the command. |
148 | 140 |
149 Raises: | 141 Raises: |
150 subprocess.CalledProcessError: The return-code was non-zero. | 142 subprocess.CalledProcessError: The return-code was non-zero. |
151 """ | 143 """ |
152 logging.debug('Running %s', command) | 144 logging.debug('Running %s', command) |
| 145 if dry_run: |
| 146 return 'Did not run command because this is a dry run.' |
153 return subprocess.check_output(command) | 147 return subprocess.check_output(command) |
154 | 148 |
155 | 149 |
156 if __name__ == '__main__': | 150 if __name__ == '__main__': |
157 sys.exit(main(sys.argv)) | 151 sys.exit(main(sys.argv)) |
OLD | NEW |