From d9b41f72d4b2d545b2600aff7bd8a27ed0093750 Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Wed, 29 May 2019 11:33:57 -0400 Subject: [PATCH 2/3] Parallelize the valgrind tests This considerably reduces the time needed to perform the valgrind memory tests on systems with multiple available processors. In the case of my laptop, the duration was reduced from ~200s to 90s. Signed-off-by: Stephen Gallagher --- modulemd/common/tests/test-valgrind.py | 74 ++++++++++++++------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/modulemd/common/tests/test-valgrind.py b/modulemd/common/tests/test-valgrind.py index 9be72c705fde79aa305d831eaa4f31f7e2cc663f..9349749658ccca0529776f3d534664d614c1cb4d 100644 --- a/modulemd/common/tests/test-valgrind.py +++ b/modulemd/common/tests/test-valgrind.py @@ -16,13 +16,16 @@ import os import sys import subprocess import tempfile import xml.etree.ElementTree as ET +from multiprocessing import Pool, TimeoutError + if os.getenv('MMD_SKIP_VALGRIND'): sys.exit(77) + failed = False # Get the list of tests to run proc_result = subprocess.run(['meson', 'test', '--list'], stdout=subprocess.PIPE, @@ -47,13 +50,13 @@ for test in unfiltered_tests: test == 'test_dirty_repo' or test == 'valgrind'): continue tests.append(test) + with tempfile.TemporaryDirectory(prefix="libmodulemd_valgrind_") as tmpdirname: - for test in tests: - # TODO: auto-detect the location of the suppression file + def exec_valgrind(test): valgrind_command = "/usr/bin/valgrind " \ "--leak-check=full " \ "--suppressions=/usr/share/glib-2.0/valgrind/glib.supp " \ "--xml=yes " \ "--xml-file=%s/%s.xml " % (tmpdirname, test) @@ -64,45 +67,50 @@ with tempfile.TemporaryDirectory(prefix="libmodulemd_valgrind_") as tmpdirname: '-t', '10', '--logbase=%s' % test, '--wrap=%s' % valgrind_command, test]) - if proc_result.returncode != 0: - print("Valgrind exited with an error on %s" % test, - file=sys.stderr) - failed = True - continue + return proc_result.returncode, test - # Process the XML for leaks - tree = ET.parse('%s/%s.xml' % (tmpdirname, test)) - root = tree.getroot() + with Pool() as pool: + for returncode, test in pool.map(exec_valgrind, tests): + if returncode != 0: + print("Valgrind exited with an error on %s" % test, + file=sys.stderr) + failed = True + continue - for root_child in root: - if (root_child.tag == "error"): - for error_child in root_child: - if error_child.tag == 'kind': - if error_child.text == 'Leak_DefinitelyLost': - print("Memory leak detected in %s" % test, - file=sys.stderr) - failed = True + # Process the XML for leaks + tree = ET.parse('%s/%s.xml' % (tmpdirname, test)) + root = tree.getroot() - elif error_child.text == 'InvalidFree': - print("Invalid free() detected in %s" % test, - file=sys.stderr) - failed = True + for root_child in root: + if (root_child.tag == "error"): + for error_child in root_child: + if error_child.tag == 'kind': + if error_child.text == 'Leak_DefinitelyLost': + print("Memory leak detected in %s" % test, + file=sys.stderr) + failed = True - elif error_child.text == 'InvalidRead': - print("Invalid read detected in %s" % test, - file=sys.stderr) - failed = True + elif error_child.text == 'InvalidFree': + print("Invalid free() detected in %s" % test, + file=sys.stderr) + failed = True - elif error_child.text == 'UninitCondition': - print("Uninitialized usage detected in %s" % test, - file=sys.stderr) - failed = True - if failed: - with open('%s/%s.xml' % (tmpdirname, test), 'r') as xml: - print(xml.read()) + elif error_child.text == 'InvalidRead': + print("Invalid read detected in %s" % test, + file=sys.stderr) + failed = True + + elif error_child.text == 'UninitCondition': + print( + "Uninitialized usage detected in %s" % + test, file=sys.stderr) + failed = True + if failed: + with open('%s/%s.xml' % (tmpdirname, test), 'r') as xml: + print(xml.read()) if failed: sys.exit(1) -- 2.21.0