| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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 |
| 11 have been completed, the supervisor reprints any lines indicating a test | 11 have been completed, the supervisor reprints any lines indicating a test |
| 12 failure for convenience. If only one shard is to be run, a single subprocess | 12 failure for convenience. If only one shard is to be run, a single subprocess |
| 13 is started for that shard and the output is identical to gtest's output. | 13 is started for that shard and the output is identical to gtest's output. |
| 14 """ | 14 """ |
| 15 | 15 |
| 16 | 16 |
| 17 from cStringIO import StringIO | 17 from cStringIO import StringIO |
| 18 import optparse | 18 import optparse |
| 19 import os | 19 import os |
| 20 import pty | 20 import pty |
| 21 import Queue | 21 import Queue |
| 22 import random |
| 22 import re | 23 import re |
| 23 import subprocess | 24 import subprocess |
| 24 import sys | 25 import sys |
| 25 import threading | 26 import threading |
| 26 | 27 |
| 27 | 28 |
| 28 SS_USAGE = "Usage: python %prog [options] path/to/test [gtest_args]" | 29 SS_USAGE = "Usage: python %prog [options] path/to/test [gtest_args]" |
| 29 SS_DEFAULT_NUM_CORES = 4 | 30 SS_DEFAULT_NUM_CORES = 4 |
| 30 SS_DEFAULT_SHARDS_PER_CORE = 5 # num_shards = cores * SHARDS_PER_CORE | 31 SS_DEFAULT_SHARDS_PER_CORE = 5 # num_shards = cores * SHARDS_PER_CORE |
| 31 SS_DEFAULT_RUNS_PER_CORE = 1 # num_workers = cores * RUNS_PER_CORE | 32 SS_DEFAULT_RUNS_PER_CORE = 1 # num_workers = cores * RUNS_PER_CORE |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 " specified") | 286 " specified") |
| 286 parser.add_option( | 287 parser.add_option( |
| 287 "--no-color", action="store_false", dest="color", | 288 "--no-color", action="store_false", dest="color", |
| 288 help="disable color output") | 289 help="disable color output") |
| 289 parser.add_option( | 290 parser.add_option( |
| 290 "-s", "--runshard", type="int", help="single shard index to run") | 291 "-s", "--runshard", type="int", help="single shard index to run") |
| 291 parser.add_option( | 292 parser.add_option( |
| 292 "--reorder", action="store_true", | 293 "--reorder", action="store_true", |
| 293 help="ensure that all output from an earlier shard is printed before" | 294 help="ensure that all output from an earlier shard is printed before" |
| 294 " output from a later shard") | 295 " output from a later shard") |
| 296 parser.add_option("--random-seed", action="store_true", |
| 297 help="shuffle the tests with a random seed value") |
| 295 parser.disable_interspersed_args() | 298 parser.disable_interspersed_args() |
| 296 (options, args) = parser.parse_args() | 299 (options, args) = parser.parse_args() |
| 297 | 300 |
| 298 if not args: | 301 if not args: |
| 299 parser.error("You must specify a path to test!") | 302 parser.error("You must specify a path to test!") |
| 300 if not os.path.exists(args[0]): | 303 if not os.path.exists(args[0]): |
| 301 parser.error("%s does not exist!" % args[0]) | 304 parser.error("%s does not exist!" % args[0]) |
| 302 | 305 |
| 303 num_cores = DetectNumCores() | 306 num_cores = DetectNumCores() |
| 304 | 307 |
| 305 if options.shards_per_core < 1: | 308 if options.shards_per_core < 1: |
| 306 parser.error("You must have at least 1 shard per core!") | 309 parser.error("You must have at least 1 shard per core!") |
| 307 num_shards = num_cores * options.shards_per_core | 310 num_shards = num_cores * options.shards_per_core |
| 308 | 311 |
| 309 if options.runs_per_core < 1: | 312 if options.runs_per_core < 1: |
| 310 parser.error("You must have at least 1 run per core!") | 313 parser.error("You must have at least 1 run per core!") |
| 311 num_runs = num_cores * options.runs_per_core | 314 num_runs = num_cores * options.runs_per_core |
| 312 | 315 |
| 313 gtest_args = ["--gtest_color=%s" % { | 316 gtest_args = ["--gtest_color=%s" % { |
| 314 True: "yes", False: "no"}[options.color]] + args[1:] | 317 True: "yes", False: "no"}[options.color]] + args[1:] |
| 315 | 318 |
| 319 if options.random_seed: |
| 320 seed = random.randint(1, 99999) |
| 321 gtest_args.extend(["--gtest_shuffle", "--gtest_random_seed=%i" % seed]) |
| 322 |
| 316 if options.runshard != None: | 323 if options.runshard != None: |
| 317 # run a single shard and exit | 324 # run a single shard and exit |
| 318 if (options.runshard < 0 or options.runshard >= num_shards): | 325 if (options.runshard < 0 or options.runshard >= num_shards): |
| 319 parser.error("Invalid shard number given parameters!") | 326 parser.error("Invalid shard number given parameters!") |
| 320 shard = RunShard( | 327 shard = RunShard( |
| 321 args[0], num_shards, options.runshard, gtest_args, None, None) | 328 args[0], num_shards, options.runshard, gtest_args, None, None) |
| 322 shard.communicate() | 329 shard.communicate() |
| 323 return shard.poll() | 330 return shard.poll() |
| 324 | 331 |
| 325 # shard and run the whole test | 332 # shard and run the whole test |
| 326 ss = ShardingSupervisor(args[0], num_shards, num_runs, options.color, | 333 ss = ShardingSupervisor(args[0], num_shards, num_runs, options.color, |
| 327 options.reorder, gtest_args) | 334 options.reorder, gtest_args) |
| 328 return ss.ShardTest() | 335 return ss.ShardTest() |
| 329 | 336 |
| 330 | 337 |
| 331 if __name__ == "__main__": | 338 if __name__ == "__main__": |
| 332 sys.exit(main()) | 339 sys.exit(main()) |
| 333 | 340 |
| OLD | NEW |