Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: build/android/bb_run_sharded_steps.py

Issue 12321138: Android: allows ignoring results of flaky sharded perf tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sami/tom's comment Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 multiple connected devices. 11 multiple connected devices.
12 12
13 The buildbots will run this script multiple times per cycle: 13 The buildbots will run this script multiple times per cycle:
14 - First, without params: all steps will be executed in parallel using all 14 - First: all steps listed in -s in will be executed in parallel using all
15 connected devices. Step results will be pickled to disk (each step has a unique 15 connected devices. Step results will be pickled to disk. Each step has a unique
16 name). 16 name. The result code will be ignored if the step name is listed in
17 --flaky_steps.
17 The buildbot will treat this step as a regular step, and will not process any 18 The buildbot will treat this step as a regular step, and will not process any
18 graph data. 19 graph data.
19 20
20 - Then, with -p STEP_NAME: at this stage, we'll simply print the file with the 21 - Then, with -p STEP_NAME: at this stage, we'll simply print the file with the
21 step results previously saved. The buildbot will then process the graph data 22 step results previously saved. The buildbot will then process the graph data
22 accordingly. 23 accordingly.
23 24
24 The JSON config contains is a file containing a dictionary in the format: 25 The JSON steps file contains a dictionary in the format:
25 { 26 {
26 'step_name_foo': 'script_to_execute foo', 27 "step_name_foo": "script_to_execute foo",
27 'step_name_bar': 'script_to_execute bar' 28 "step_name_bar": "script_to_execute bar"
28 } 29 }
29 30
31 The JSON flaky steps file contains a list with step names which results should
32 be ignored:
33 [
34 "step_name_foo",
35 "step_name_bar"
36 ]
37
30 Note that script_to_execute necessarily have to take at least the following 38 Note that script_to_execute necessarily have to take at least the following
31 options: 39 options:
32 --device: the serial number to be passed to all adb commands. 40 --device: the serial number to be passed to all adb commands.
33 --keep_test_server_ports: indicates it's being run as a shard, and shouldn't 41 --keep_test_server_ports: indicates it's being run as a shard, and shouldn't
34 reset test server port allocation. 42 reset test server port allocation.
35 """ 43 """
36 44
37 45
38 import datetime 46 import datetime
39 import json 47 import json
(...skipping 24 matching lines...) Expand all
64 def _RunStepsPerDevice(steps): 72 def _RunStepsPerDevice(steps):
65 results = [] 73 results = []
66 for step in steps: 74 for step in steps:
67 start_time = datetime.datetime.now() 75 start_time = datetime.datetime.now()
68 print 'Starting %s: %s %s at %s' % (step['name'], step['cmd'], 76 print 'Starting %s: %s %s at %s' % (step['name'], step['cmd'],
69 start_time, step['device']) 77 start_time, step['device'])
70 output, exit_code = pexpect.run( 78 output, exit_code = pexpect.run(
71 step['cmd'], cwd=os.path.abspath(constants.CHROME_DIR), 79 step['cmd'], cwd=os.path.abspath(constants.CHROME_DIR),
72 withexitstatus=True, logfile=sys.stdout, timeout=1800, 80 withexitstatus=True, logfile=sys.stdout, timeout=1800,
73 env=os.environ) 81 env=os.environ)
82 exit_code = exit_code or 0
74 end_time = datetime.datetime.now() 83 end_time = datetime.datetime.now()
75 print 'Finished %s: %s %s at %s' % (step['name'], step['cmd'], 84 exit_msg = '%s %s' % (exit_code,
76 end_time, step['device']) 85 '(ignored, flaky step)' if step['is_flaky'] else '')
86 print 'Finished %s: %s %s %s at %s' % (step['name'], exit_msg, step['cmd'],
87 end_time, step['device'])
88 if step['is_flaky']:
89 exit_code = 0
77 result = {'name': step['name'], 90 result = {'name': step['name'],
78 'output': output, 91 'output': output,
79 'exit_code': exit_code or 0, 92 'exit_code': exit_code or 0,
Sami 2013/02/26 17:19:13 No need for the "or 0" anymore :)
80 'total_time': (end_time - start_time).seconds, 93 'total_time': (end_time - start_time).seconds,
81 'device': step['device']} 94 'device': step['device']}
82 _SaveResult(result) 95 _SaveResult(result)
83 results += [result] 96 results += [result]
84 return results 97 return results
85 98
86 99
87 def _RunShardedSteps(steps, devices): 100 def _RunShardedSteps(steps, flaky_steps, devices):
88 assert steps 101 assert steps
89 assert devices, 'No devices connected?' 102 assert devices, 'No devices connected?'
90 if os.path.exists(_OUTPUT_DIR): 103 if os.path.exists(_OUTPUT_DIR):
91 assert '/step_results' in _OUTPUT_DIR 104 assert '/step_results' in _OUTPUT_DIR
92 shutil.rmtree(_OUTPUT_DIR) 105 shutil.rmtree(_OUTPUT_DIR)
93 if not os.path.exists(_OUTPUT_DIR): 106 if not os.path.exists(_OUTPUT_DIR):
94 os.makedirs(_OUTPUT_DIR) 107 os.makedirs(_OUTPUT_DIR)
95 step_names = sorted(steps.keys()) 108 step_names = sorted(steps.keys())
96 all_params = [] 109 all_params = []
97 num_devices = len(devices) 110 num_devices = len(devices)
98 shard_size = (len(steps) + num_devices - 1) / num_devices 111 shard_size = (len(steps) + num_devices - 1) / num_devices
99 for i, device in enumerate(devices): 112 for i, device in enumerate(devices):
100 steps_per_device = [] 113 steps_per_device = []
101 for s in steps.keys()[i * shard_size:(i + 1) * shard_size]: 114 for s in steps.keys()[i * shard_size:(i + 1) * shard_size]:
102 steps_per_device += [{'name': s, 115 steps_per_device += [{'name': s,
103 'device': device, 116 'device': device,
117 'is_flaky': s in flaky_steps,
104 'cmd': steps[s] + ' --device ' + device + 118 'cmd': steps[s] + ' --device ' + device +
105 ' --keep_test_server_ports'}] 119 ' --keep_test_server_ports'}]
106 all_params += [steps_per_device] 120 all_params += [steps_per_device]
107 print 'Start sharding (note: output is not synchronized...)' 121 print 'Start sharding (note: output is not synchronized...)'
108 print '*' * 80 122 print '*' * 80
109 start_time = datetime.datetime.now() 123 start_time = datetime.datetime.now()
110 pool = multiprocessing.Pool(processes=num_devices) 124 pool = multiprocessing.Pool(processes=num_devices)
111 async_results = pool.map_async(_RunStepsPerDevice, all_params) 125 async_results = pool.map_async(_RunStepsPerDevice, all_params)
112 results_per_device = async_results.get(999999) 126 results_per_device = async_results.get(999999)
113 end_time = datetime.datetime.now() 127 end_time = datetime.datetime.now()
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 os.kill(int(pid), signal.SIGQUIT) 164 os.kill(int(pid), signal.SIGQUIT)
151 except Exception as e: 165 except Exception as e:
152 logging.warning('Failed killing %s %s %s', server, pid, e) 166 logging.warning('Failed killing %s %s %s', server, pid, e)
153 167
154 168
155 def main(argv): 169 def main(argv):
156 parser = optparse.OptionParser() 170 parser = optparse.OptionParser()
157 parser.add_option('-s', '--steps', 171 parser.add_option('-s', '--steps',
158 help='A JSON file containing all the steps to be ' 172 help='A JSON file containing all the steps to be '
159 'sharded.') 173 'sharded.')
174 parser.add_option('--flaky_steps',
175 help='A JSON file containing steps that are flaky and '
176 'will have its exit code ignored.')
160 parser.add_option('-p', '--print_results', 177 parser.add_option('-p', '--print_results',
161 help='Only prints the results for the previously ' 178 help='Only prints the results for the previously '
162 'executed step, do not run it again.') 179 'executed step, do not run it again.')
163 options, urls = parser.parse_args(argv) 180 options, urls = parser.parse_args(argv)
164 if options.print_results: 181 if options.print_results:
165 return _PrintStepOutput(options.print_results) 182 return _PrintStepOutput(options.print_results)
166 183
167 # At this point, we should kill everything that may have been left over from 184 # At this point, we should kill everything that may have been left over from
168 # previous runs. 185 # previous runs.
169 _KillPendingServers() 186 _KillPendingServers()
170 187
171 # Reset the test port allocation. It's important to do it before starting 188 # Reset the test port allocation. It's important to do it before starting
172 # to dispatch any step. 189 # to dispatch any step.
173 if not ports.ResetTestServerPortAllocation(): 190 if not ports.ResetTestServerPortAllocation():
174 raise Exception('Failed to reset test server port.') 191 raise Exception('Failed to reset test server port.')
175 192
176 # Sort the devices so that we'll try to always run a step in the same device. 193 # Sort the devices so that we'll try to always run a step in the same device.
177 devices = sorted(android_commands.GetAttachedDevices()) 194 devices = sorted(android_commands.GetAttachedDevices())
178 if not devices: 195 if not devices:
179 print 'You must attach a device' 196 print 'You must attach a device'
180 return 1 197 return 1
181 198
182 with file(options.steps, 'r') as f: 199 with file(options.steps, 'r') as f:
183 steps = json.load(f) 200 steps = json.load(f)
184 return _RunShardedSteps(steps, devices) 201 flaky_steps = []
202 if options.flaky_steps:
203 with file(options.flaky_steps, 'r') as f:
204 flaky_steps = json.load(f)
205 return _RunShardedSteps(steps, flaky_steps, devices)
185 206
186 207
187 if __name__ == '__main__': 208 if __name__ == '__main__':
188 sys.exit(main(sys.argv)) 209 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698