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: tools/sharding_supervisor/sharding_supervisor.py

Issue 10749018: Make merging of shard test results handle test suites that are split across shards better. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Review feedback Created 8 years, 5 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
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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 """Shards a given test suite and runs the shards in parallel. 6 """Shards a given test suite and runs the shards in parallel.
7 7
8 ShardingSupervisor is called to process the command line options and creates 8 ShardingSupervisor is called to process the command line options and creates
9 the specified number of worker threads. These threads then run each shard of 9 the specified number of worker threads. These threads then run each shard of
10 the test in a separate process and report on the results. When all the shards 10 the test in a separate process and report on the results. When all the shards
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 116
117 if not final_xml: 117 if not final_xml:
118 # Out final xml is empty, let's prepopulate it with the first one we see. 118 # Out final xml is empty, let's prepopulate it with the first one we see.
119 return shard_xml 119 return shard_xml
120 120
121 shard_node = shard_xml.documentElement 121 shard_node = shard_xml.documentElement
122 final_node = final_xml.documentElement 122 final_node = final_xml.documentElement
123 123
124 testcases = shard_node.getElementsByTagName('testcase') 124 testcases = shard_node.getElementsByTagName('testcase')
125 final_testcases = final_node.getElementsByTagName('testcase') 125 final_testcases = final_node.getElementsByTagName('testcase')
126
127 final_testsuites = final_node.getElementsByTagName('testsuite')
128 final_testsuites_by_name = dict(
129 (suite.getAttribute('name'), suite) for suite in final_testsuites)
130
126 for testcase in testcases: 131 for testcase in testcases:
127 name = testcase.getAttribute('name') 132 name = testcase.getAttribute('name')
128 classname = testcase.getAttribute('classname') 133 classname = testcase.getAttribute('classname')
129 failures = testcase.getElementsByTagName('failure') 134 failures = testcase.getElementsByTagName('failure')
130 status = testcase.getAttribute('status') 135 status = testcase.getAttribute('status')
131 elapsed = testcase.getAttribute('time') 136 elapsed = testcase.getAttribute('time')
132 137
133 # don't bother updating the final xml if there is no data. 138 # don't bother updating the final xml if there is no data.
134 if status == 'notrun': 139 if status == 'notrun':
135 continue 140 continue
136 141
137 # Look in our final xml to see if it's there. 142 # Look in our final xml to see if it's there.
138 # There has to be a better way... 143 # There has to be a better way...
144 merged_into_final_testcase = False
139 for final_testcase in final_testcases: 145 for final_testcase in final_testcases:
140 final_name = final_testcase.getAttribute('name') 146 final_name = final_testcase.getAttribute('name')
141 final_classname = final_testcase.getAttribute('classname') 147 final_classname = final_testcase.getAttribute('classname')
142 if final_name == name and final_classname == classname: 148 if final_name == name and final_classname == classname:
143 # We got the same entry. 149 # We got the same entry.
144 final_testcase.setAttribute('status', status) 150 final_testcase.setAttribute('status', status)
145 final_testcase.setAttribute('time', elapsed) 151 final_testcase.setAttribute('time', elapsed)
146 for failure in failures: 152 for failure in failures:
147 final_testcase.appendChild(failure) 153 final_testcase.appendChild(failure)
154 merged_into_final_testcase = True
155
156 # We couldn't find an existing testcase to merge the results into, so we
157 # copy the node into the existing test suite.
158 if not merged_into_final_testcase:
159 testsuite = testcase.parentNode
160 final_testsuite = final_testsuites_by_name[testsuite.getAttribute('name')]
161 final_testsuite.appendChild(testcase)
148 162
149 return final_xml 163 return final_xml
150 164
151 165
152 def RunShard(test, total_shards, index, gtest_args, stdout, stderr): 166 def RunShard(test, total_shards, index, gtest_args, stdout, stderr):
153 """Runs a single test shard in a subprocess. 167 """Runs a single test shard in a subprocess.
154 168
155 Returns: 169 Returns:
156 The Popen object representing the subprocess handle. 170 The Popen object representing the subprocess handle.
157 """ 171 """
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 shard_output: Buffer that stores the output from each shard. 295 shard_output: Buffer that stores the output from each shard.
282 test_counter: Stores the total number of tests run. 296 test_counter: Stores the total number of tests run.
283 total_slaves: Total number of slaves running this test. 297 total_slaves: Total number of slaves running this test.
284 slave_index: Current slave to run tests for. 298 slave_index: Current slave to run tests for.
285 299
286 If total_slaves is set, we run only a subset of the tests. This is meant to be 300 If total_slaves is set, we run only a subset of the tests. This is meant to be
287 used when we want to shard across machines as well as across cpus. In that 301 used when we want to shard across machines as well as across cpus. In that
288 case the number of shards to execute will be the same, but they will be 302 case the number of shards to execute will be the same, but they will be
289 smaller, as the total number of shards in the test suite will be multiplied 303 smaller, as the total number of shards in the test suite will be multiplied
290 by 'total_slaves'. 304 by 'total_slaves'.
291 305
292 For example, if you are on a quad core machine, the sharding supervisor by 306 For example, if you are on a quad core machine, the sharding supervisor by
293 default will use 20 shards for the whole suite. However, if you set 307 default will use 20 shards for the whole suite. However, if you set
294 total_slaves to 2, it will split the suite in 40 shards and will only run 308 total_slaves to 2, it will split the suite in 40 shards and will only run
295 shards [0-19] or shards [20-39] depending if you set slave_index to 0 or 1. 309 shards [0-19] or shards [20-39] depending if you set slave_index to 0 or 1.
296 """ 310 """
297 311
298 SHARD_COMPLETED = object() 312 SHARD_COMPLETED = object()
299 313
300 def __init__(self, test, num_shards_to_run, num_runs, color, original_order, 314 def __init__(self, test, num_shards_to_run, num_runs, color, original_order,
301 prefix, retry_percent, timeout, total_slaves, slave_index, 315 prefix, retry_percent, timeout, total_slaves, slave_index,
(...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 # shard and run the whole test 659 # shard and run the whole test
646 ss = ShardingSupervisor( 660 ss = ShardingSupervisor(
647 test, num_shards_to_run, num_runs, options.color, 661 test, num_shards_to_run, num_runs, options.color,
648 options.original_order, options.prefix, options.retry_percent, 662 options.original_order, options.prefix, options.retry_percent,
649 options.timeout, options.total_slaves, options.slave_index, gtest_args) 663 options.timeout, options.total_slaves, options.slave_index, gtest_args)
650 return ss.ShardTest() 664 return ss.ShardTest()
651 665
652 666
653 if __name__ == "__main__": 667 if __name__ == "__main__":
654 sys.exit(main()) 668 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/sharding_supervisor/data/gtest_results_expected.xml ('k') | tools/sharding_supervisor/sharding_supervisor_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698