summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2015-03-22 03:22:31 +0100
committerCarlos Martín Nieto <cmn@dwim.me>2015-03-22 03:22:31 +0100
commitef7903eae7ca70c58733599f02d739040abb2e63 (patch)
treecd981f3e6b13037fefa96481de9591462171da48
parent2a0f67f04cb717a7e57192696d69f91a3d208705 (diff)
downloadlibgit2-cmn/parallel-clar.tar.gz
Add a parallel runner for clarcmn/parallel-clar
As we are mostly I/O bound, the CPU tends to sit idle. With this script, we can split the work among multiple clar processes automatically, cutting down the time it takes for a full test run.
-rwxr-xr-xscript/pclar.py77
1 files changed, 77 insertions, 0 deletions
diff --git a/script/pclar.py b/script/pclar.py
new file mode 100755
index 000000000..173db42b5
--- /dev/null
+++ b/script/pclar.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+from __future__ import print_function, unicode_literals
+
+"""Parallel runner for clar
+"""
+
+import sys, time
+from os import path
+import subprocess
+
+def parse_suites(exe):
+ suites = subprocess.check_output([exe, '-l'])
+ return map(lambda s: s.split(' ')[1], # get the name from each line of output
+ filter(lambda s: s, # Remove any empty lines
+ map(lambda s: s.strip(), # remove leading whitespace
+ suites.split('\n')[3:]))) # skip first three which are info messages
+
+def start_process(exe, suites):
+ argv = [exe]
+ for suite in suites:
+ argv.append("-s{}".format(suite))
+
+ return subprocess.Popen(argv, stdout=subprocess.PIPE)
+
+if __name__ == '__main__':
+ from argparse import ArgumentParser
+
+ parser = ArgumentParser(description="Parallel runner for clar")
+ parser.add_argument('clar', type=unicode, help="Clar runner")
+ parser.add_argument('-j', '--jobs', type=int, default=1,
+ help="Number of parallel clars to run")
+ args = parser.parse_args()
+
+ if not args.jobs > 0:
+ print("fatal: umber of jobs must be positive", file=sys.stderr)
+ exit(1)
+
+ if not path.isfile(args.clar):
+ print("fatal: clar runner not found", file=sys.stderr)
+ exit(1)
+
+ suites = parse_suites(args.clar)
+ plural = "" if args.jobs == 1 else "es"
+ print("Loaded {} suites, using {} process{}".format(len(suites), args.jobs, plural))
+
+ # Split the suites into groups so we can give the list to the
+ # runners. The last one gets a few more in case the number of
+ # suites does not split evenly into the runners
+ indices = range(0, len(suites)+1, len(suites) / args.jobs)
+ indices[-1] = len(suites)
+
+ procs = []
+ for i in range(1, len(indices)):
+ lower = indices[i-1]
+ upper = indices[i]
+
+ procs.append(start_process(args.clar, suites[lower:upper]))
+
+ # Processes have been started
+ print("Started processes: {}".format(map(lambda p: p.pid, procs)))
+
+ while True:
+ running = len(filter(lambda p: p.poll() is None, procs))
+ if running == 0:
+ break
+
+ sys.stdout.write("\r{}Running {}".format("\033[K", running))
+ sys.stdout.flush()
+ time.sleep(1)
+
+ failures = len(filter(lambda p: p.poll() < 0, procs))
+ errors = sum(filter(lambda p: p.poll() > 0, procs))
+ successes = filter(lambda p: p.poll() == 0, procs)
+
+ print("")
+ print("errors: {}, failures: {}".format(errors, failures))