OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 """Helper script to shard build bot steps and save results to disk. | 7 """Helper script to shard build bot steps and save results to disk. |
8 | 8 |
9 Our buildbot infrastructure requires each slave to run steps serially. | 9 Our buildbot infrastructure requires each slave to run steps serially. |
10 This is sub-optimal for android, where these steps can run independently on | 10 This is sub-optimal for android, where these steps can run independently on |
(...skipping 26 matching lines...) Expand all Loading... | |
37 | 37 |
38 import datetime | 38 import datetime |
39 import json | 39 import json |
40 import logging | 40 import logging |
41 import multiprocessing | 41 import multiprocessing |
42 import optparse | 42 import optparse |
43 import pexpect | 43 import pexpect |
44 import pickle | 44 import pickle |
45 import os | 45 import os |
46 import signal | 46 import signal |
47 import subprocess | |
tonyg
2013/01/11 16:54:44
nit: alphabetize one line down
bulach
2013/01/11 17:36:26
Done.
| |
47 import shutil | 48 import shutil |
48 import sys | 49 import sys |
49 | 50 |
50 from pylib import android_commands | 51 from pylib import android_commands |
51 from pylib import cmd_helper | 52 from pylib import cmd_helper |
52 from pylib import constants | 53 from pylib import constants |
53 from pylib import ports | 54 from pylib import ports |
54 | 55 |
55 | 56 |
56 _OUTPUT_DIR = os.path.join(constants.CHROME_DIR, 'out', 'step_results') | 57 _OUTPUT_DIR = os.path.join(constants.CHROME_DIR, 'out', 'step_results') |
(...skipping 20 matching lines...) Expand all Loading... | |
77 result = {'name': step['name'], | 78 result = {'name': step['name'], |
78 'output': output, | 79 'output': output, |
79 'exit_code': exit_code or 0, | 80 'exit_code': exit_code or 0, |
80 'total_time': (end_time - start_time).seconds, | 81 'total_time': (end_time - start_time).seconds, |
81 'device': step['device']} | 82 'device': step['device']} |
82 _SaveResult(result) | 83 _SaveResult(result) |
83 results += [result] | 84 results += [result] |
84 return results | 85 return results |
85 | 86 |
86 | 87 |
88 class _LogCatMonitor(object): | |
89 def __init__(self): | |
90 self._monitor = None | |
91 self._logcat_dir = os.path.join(constants.CHROME_DIR, 'out', | |
92 'sharded_steps_logcat_monitor') | |
93 | |
94 def __enter__(self): | |
95 cmd = [os.path.join(constants.CHROME_DIR, 'build', 'android', | |
96 'adb_logcat_monitor.py'), self._logcat_dir] | |
97 self._monitor = subprocess.Popen(cmd, cwd=constants.CHROME_DIR) | |
98 | |
99 def __exit__(self, *args): | |
100 if self._monitor: | |
101 self._monitor.terminate() | |
102 cmd = [os.path.join(constants.CHROME_DIR, 'build', 'android', | |
103 'adb_logcat_printer.py'), self._logcat_dir] | |
104 cmd = subprocess.Popen(cmd, cwd=constants.CHROME_DIR) | |
105 cmd.wait() | |
106 | |
107 | |
87 def _RunShardedSteps(steps, devices): | 108 def _RunShardedSteps(steps, devices): |
88 assert steps | 109 assert steps |
89 assert devices, 'No devices connected?' | 110 assert devices, 'No devices connected?' |
90 if os.path.exists(_OUTPUT_DIR): | 111 if os.path.exists(_OUTPUT_DIR): |
91 assert '/step_results' in _OUTPUT_DIR | 112 assert '/step_results' in _OUTPUT_DIR |
92 shutil.rmtree(_OUTPUT_DIR) | 113 shutil.rmtree(_OUTPUT_DIR) |
93 if not os.path.exists(_OUTPUT_DIR): | 114 if not os.path.exists(_OUTPUT_DIR): |
94 os.makedirs(_OUTPUT_DIR) | 115 os.makedirs(_OUTPUT_DIR) |
95 step_names = sorted(steps.keys()) | 116 step_names = sorted(steps.keys()) |
96 all_params = [] | 117 all_params = [] |
97 num_devices = len(devices) | 118 num_devices = len(devices) |
98 shard_size = (len(steps) + num_devices - 1) / num_devices | 119 shard_size = (len(steps) + num_devices - 1) / num_devices |
99 for i, device in enumerate(devices): | 120 for i, device in enumerate(devices): |
100 steps_per_device = [] | 121 steps_per_device = [] |
101 for s in steps.keys()[i * shard_size:(i + 1) * shard_size]: | 122 for s in steps.keys()[i * shard_size:(i + 1) * shard_size]: |
102 steps_per_device += [{'name': s, | 123 steps_per_device += [{'name': s, |
103 'device': device, | 124 'device': device, |
104 'cmd': steps[s] + ' --device ' + device + | 125 'cmd': steps[s] + ' --device ' + device + |
105 ' --keep_test_server_ports'}] | 126 ' --keep_test_server_ports'}] |
106 all_params += [steps_per_device] | 127 all_params += [steps_per_device] |
107 print 'Start sharding (note: output is not synchronized...)' | 128 print 'Start sharding (note: output is not synchronized...)' |
108 print '*' * 80 | 129 print '*' * 80 |
109 start_time = datetime.datetime.now() | 130 start_time = datetime.datetime.now() |
110 pool = multiprocessing.Pool(processes=num_devices) | 131 |
111 async_results = pool.map_async(_RunStepsPerDevice, all_params) | 132 with _LogCatMonitor() as logcat_monitor: |
112 results_per_device = async_results.get(999999) | 133 pool = multiprocessing.Pool(processes=num_devices) |
134 async_results = pool.map_async(_RunStepsPerDevice, all_params) | |
135 results_per_device = async_results.get(999999) | |
136 | |
113 end_time = datetime.datetime.now() | 137 end_time = datetime.datetime.now() |
114 print '*' * 80 | 138 print '*' * 80 |
115 print 'Finished sharding.' | 139 print 'Finished sharding.' |
116 print 'Summary' | 140 print 'Summary' |
117 total_time = 0 | 141 total_time = 0 |
118 for results in results_per_device: | 142 for results in results_per_device: |
119 for result in results: | 143 for result in results: |
120 print('%s : exit_code=%d in %d secs at %s' % | 144 print('%s : exit_code=%d in %d secs at %s' % |
121 (result['name'], result['exit_code'], result['total_time'], | 145 (result['name'], result['exit_code'], result['total_time'], |
122 result['device'])) | 146 result['device'])) |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 print 'You must attach a device' | 203 print 'You must attach a device' |
180 return 1 | 204 return 1 |
181 | 205 |
182 with file(options.steps, 'r') as f: | 206 with file(options.steps, 'r') as f: |
183 steps = json.load(f) | 207 steps = json.load(f) |
184 return _RunShardedSteps(steps, devices) | 208 return _RunShardedSteps(steps, devices) |
185 | 209 |
186 | 210 |
187 if __name__ == '__main__': | 211 if __name__ == '__main__': |
188 sys.exit(main(sys.argv)) | 212 sys.exit(main(sys.argv)) |
OLD | NEW |