Commit d59dcac0 authored by Thanassis Tsiodras's avatar Thanassis Tsiodras

Parallel execution of all tests.

parent 2726f5c8
#!/usr/bin/env python3
"""
This uses all available cores to spawn processes that build
all test projects (Demo_*/)
"""
import os
import sys
import time
import signal
import multiprocessing
# Tell the orchestrator to..
#
# - stop complaining about POHI issues under multicores
os.putenv("DISABLE_MULTICORE_CHECK", "1")
# - immediately abort in case of error (No "Hit ENTER...")
os.putenv("CLEANUP", "1")
def get_tests():
"""Collect all Demo_... folders not excluded via 'NOTEST' """
for folder in sorted(os.listdir(".")):
if all([folder.startswith('Demo'),
not os.path.exists(folder + "/NOTEST")]):
yield folder
def build_me(folder):
"""
Performs a build in the passed-in folder, and also spawns regression.py
(if it exists in that folder).
Spawned from a multiprocessing pool, returns the result back in tuple form
for asynchronous reporting.
"""
root = os.getcwd()
os.chdir(folder)
try:
res = os.system("./bui*.sh > build.log 2>&1 || exit 1")
if res != 0:
return folder, False, "Build failed..."
if os.path.exists("regression.py"):
res = os.system("./regression.py > regression.log 2>&1 || exit 1")
if res != 0:
return folder, False, "Regression check failed..."
return folder, True, "OK"
finally:
os.chdir(root)
def color_me(result, msg):
"""Color the output according to the result."""
if sys.stdout.isatty():
msg = chr(27) + "[3" + (
"2" if result else "1") + "m" + msg + chr(27) + "[0m"
return msg
def main():
"""Run the TASTE regression-checking project suite"""
cwd = os.path.dirname(os.path.realpath(__file__))
# Navigate to the folder hosting all test projects (i.e. "Demo_*/")
os.chdir(cwd)
# Detect how many workers we will use
total_cpus = multiprocessing.cpu_count()
total_tests = len(list(get_tests()))
# Measure time to execute
start_time = time.time()
print("Spawning", total_cpus, "workers to run", total_tests, "tests...\n")
pool = multiprocessing.Pool(total_cpus)
try:
failed_tests = 0
run_tests = 0
results = pool.imap_unordered(build_me, get_tests())
for res in results:
run_tests += 1
test, result, msg = res
print("%40s: %s" % (test, color_me(result, msg)))
if not result:
failed_tests += 1
except KeyboardInterrupt:
# The devil is always in the details... This is the only
# way I found to propagate the SIGINT to the builds done
# by the worker processes of the pool AND immediately
# terminate. Numerous people cry about it on the web...
# ...and I had to look at the code of concurrent.futures
# (which I abandoned), multiprocessing/pool.py,
# multiprocessing/process.py AND subprocess.py to see
# what I had to do. Gotta love our profession.
for job in pool._pool: # pylint: disable=W0212
os.kill(job.pid, signal.SIGINT)
job.terminate()
pool.terminate()
pool.join()
else:
pool.close()
pool.join()
print("\nFinished in %d seconds." % (time.time() - start_time))
print(run_tests, "tests,", failed_tests, "failure" + (
"s" if (failed_tests > 1 or failed_tests == 0) else "") + ".")
if __name__ == "__main__":
main()
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment