From 81e37e1220c601734d3a6f14df46d49cb44f02ea Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 1 Apr 2016 20:51:11 +0300 Subject: [PATCH 1/3] Run tests in parallel. --- run_tests.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/run_tests.py b/run_tests.py index a3ec0dca9..e42e10d2b 100755 --- a/run_tests.py +++ b/run_tests.py @@ -28,6 +28,8 @@ from mesonbuild.scripts import meson_test, meson_benchmark import argparse import xml.etree.ElementTree as ET import time +import multiprocessing +import concurrent.futures as conc from mesonbuild.mesonmain import backendlist @@ -195,7 +197,9 @@ def parse_test_args(testdir): pass return args -def run_test(testdir, extra_args, should_succeed): +def run_test(skipped, testdir, extra_args, should_succeed): + if skipped: + return None with tempfile.TemporaryDirectory(prefix='b ', dir='.') as build_dir: with tempfile.TemporaryDirectory(prefix='i ', dir=os.getcwd()) as install_dir: try: @@ -292,18 +296,24 @@ def run_tests(extra_args): build_time = 0 test_time = 0 + executor = conc.ProcessPoolExecutor(max_workers=multiprocessing.cpu_count()) + for name, test_cases, skipped in all_tests: current_suite = ET.SubElement(junit_root, 'testsuite', {'name' : name, 'tests' : str(len(test_cases))}) if skipped: print('\nNot running %s tests.\n' % name) else: print('\nRunning %s tests.\n' % name) + futures = [] for t in test_cases: # Jenkins screws us over by automatically sorting test cases by name # and getting it wrong by not doing logical number sorting. (testnum, testbase) = os.path.split(t)[-1].split(' ', 1) testname = '%.3d %s' % (int(testnum), testbase) - if skipped: + result = executor.submit(run_test, skipped, t, extra_args, name != 'failing') + for (testname, result) in futures: + futures.append((testname, result)) + if result is None: current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname, 'classname' : name}) ET.SubElement(current_test, 'skipped', {}) @@ -311,7 +321,6 @@ def run_tests(extra_args): skipped_tests += 1 else: ts = time.time() - result = run_test(t, extra_args, name != 'failing') te = time.time() conf_time += result.conftime build_time += result.buildtime From a7e93012157ed1f49b35fd4a8cf2b4719083cb08 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 1 Apr 2016 21:11:38 +0300 Subject: [PATCH 2/3] Output is all pretty again. --- run_tests.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/run_tests.py b/run_tests.py index e42e10d2b..978625ac4 100755 --- a/run_tests.py +++ b/run_tests.py @@ -209,7 +209,6 @@ def run_test(skipped, testdir, extra_args, should_succeed): def _run_test(testdir, test_build_dir, install_dir, extra_args, should_succeed): global compile_commands - print('Running test: ' + testdir) test_args = parse_test_args(testdir) gen_start = time.time() gen_command = [meson_command, '--prefix', '/usr', '--libdir', 'lib', testdir, test_build_dir]\ @@ -311,24 +310,26 @@ def run_tests(extra_args): (testnum, testbase) = os.path.split(t)[-1].split(' ', 1) testname = '%.3d %s' % (int(testnum), testbase) result = executor.submit(run_test, skipped, t, extra_args, name != 'failing') - for (testname, result) in futures: - futures.append((testname, result)) + futures.append((testname, t, result)) + for (testname, t, result) in futures: + result = result.result() if result is None: + print('Skipping:', t) current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname, 'classname' : name}) ET.SubElement(current_test, 'skipped', {}) global skipped_tests skipped_tests += 1 else: - ts = time.time() - te = time.time() + print('Running test: ' + t) conf_time += result.conftime build_time += result.buildtime test_time += result.testtime + total_time = conf_time + build_time + test_time log_text_file(logfile, t, result.msg, result.stdo, result.stde) current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname, 'classname' : name, - 'time' : '%.3f' % (te - ts)}) + 'time' : '%.3f' % total_time}) if result.msg != '': ET.SubElement(current_test, 'failure', {'message' : result.msg}) stdoel = ET.SubElement(current_test, 'system-out') From e522a9f2684e38955aefda3b4413a78997ccdbc9 Mon Sep 17 00:00:00 2001 From: Jussi Pakkanen Date: Fri, 1 Apr 2016 23:27:50 +0300 Subject: [PATCH 3/3] Fix Windows. Again. --- mesonbuild/environment.py | 1 + run_tests.py | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index c381ab506..8db0b0c37 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -58,6 +58,7 @@ class Environment(): log_dir = 'meson-logs' coredata_file = os.path.join(private_dir, 'coredata.dat') version_regex = '\d+(\.\d+)+(-[a-zA-Z0-9]+)?' + def __init__(self, source_dir, build_dir, main_script_file, options, original_cmd_line_args): assert(os.path.isabs(main_script_file)) assert(not os.path.islink(main_script_file)) diff --git a/run_tests.py b/run_tests.py index 978625ac4..52111ac41 100755 --- a/run_tests.py +++ b/run_tests.py @@ -309,10 +309,20 @@ def run_tests(extra_args): # and getting it wrong by not doing logical number sorting. (testnum, testbase) = os.path.split(t)[-1].split(' ', 1) testname = '%.3d %s' % (int(testnum), testbase) - result = executor.submit(run_test, skipped, t, extra_args, name != 'failing') + # Windows errors out when calling result.result() below with + # a bizarre error about appending None to an array that comes + # from the standard library. This is probably either because I use + # XP or the Python version is old. Anyhow, fall back to immediate + # evaluation. This causes output not to be printed until the end, + # which is unfortunate but least it works. + if mesonlib.is_windows(): + result = run_test(skipped, t, extra_args, name != 'failing') + else: + result = executor.submit(run_test, skipped, t, extra_args, name != 'failing') futures.append((testname, t, result)) for (testname, t, result) in futures: - result = result.result() + if not mesonlib.is_windows(): # See above. + result = result.result() if result is None: print('Skipping:', t) current_test = ET.SubElement(current_suite, 'testcase', {'name' : testname,