From: Victor Stinner Date: Thu, 15 Jun 2017 22:08:39 +0000 (+0200) Subject: bpo-30675: Fix multiprocessing code in regrtest (#2220) X-Git-Tag: v3.5.4rc1~70 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=33cf0c4cd6e8abe138c3469ca9ec1502410945f0;p=python bpo-30675: Fix multiprocessing code in regrtest (#2220) * Rewrite code to pass slaveargs from the master process to worker processes: reuse the same code of the Python master branch * Move code to initialize tests in a new setup_tests() function, similar change was done in the master branch * In a worker process, call setup_tests() with the namespace built from slaveargs to initialize correctly tests Before this change, warm_caches() was not called in worker processes because the setup was done before rebuilding the namespace from slaveargs. As a consequence, the huntrleaks feature was unstable. For example, test_zipfile reported randomly false positive on reference leaks. --- diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 6cb9d5ae0e..e5aa3e3f7d 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -140,6 +140,7 @@ import sysconfig import tempfile import time import traceback +import types import unittest import warnings from inspect import isabstract @@ -448,17 +449,15 @@ def run_test_in_subprocess(testname, ns): # required to spawn a new process with PGO flag on/off if ns.pgo: base_cmd = base_cmd + ['--pgo'] - slaveargs = ( - (testname, ns.verbose, ns.quiet), - dict(huntrleaks=ns.huntrleaks, - use_resources=ns.use_resources, - output_on_failure=ns.verbose3, - timeout=ns.timeout, failfast=ns.failfast, - match_tests=ns.match_tests, pgo=ns.pgo)) + + ns_dict = vars(ns) + slaveargs = (ns_dict, testname) + slaveargs = json.dumps(slaveargs) + # Running the child from the same working directory as regrtest's original # invocation ensures that TEMPDIR for the child is the same when # sysconfig.is_python_build() is true. See issue 15300. - popen = Popen(base_cmd + ['--slaveargs', json.dumps(slaveargs)], + popen = Popen(base_cmd + ['--slaveargs', slaveargs], stdout=PIPE, stderr=PIPE, universal_newlines=True, close_fds=(os.name != 'nt'), @@ -468,6 +467,43 @@ def run_test_in_subprocess(testname, ns): return retcode, stdout, stderr +def setup_tests(ns): + if ns.huntrleaks: + # Avoid false positives due to various caches + # filling slowly with random data: + warm_caches() + if ns.memlimit is not None: + support.set_memlimit(ns.memlimit) + if ns.threshold is not None: + import gc + gc.set_threshold(ns.threshold) + if ns.nowindows: + print('The --nowindows (-n) option is deprecated. ' + 'Use -vv to display assertions in stderr.') + try: + import msvcrt + except ImportError: + pass + else: + msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS| + msvcrt.SEM_NOALIGNMENTFAULTEXCEPT| + msvcrt.SEM_NOGPFAULTERRORBOX| + msvcrt.SEM_NOOPENFILEERRORBOX) + try: + msvcrt.CrtSetReportMode + except AttributeError: + # release build + pass + else: + for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: + if ns.verbose and ns.verbose >= 2: + msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) + msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) + else: + msvcrt.CrtSetReportMode(m, 0) + + + def main(tests=None, **kwargs): """Execute a test suite. @@ -509,58 +545,38 @@ def main(tests=None, **kwargs): ns = _parse_args(sys.argv[1:], **kwargs) - if ns.huntrleaks: - # Avoid false positives due to various caches - # filling slowly with random data: - warm_caches() - if ns.memlimit is not None: - support.set_memlimit(ns.memlimit) - if ns.threshold is not None: - import gc - gc.set_threshold(ns.threshold) - if ns.nowindows: - print('The --nowindows (-n) option is deprecated. ' - 'Use -vv to display assertions in stderr.') - try: - import msvcrt - except ImportError: - pass - else: - msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS| - msvcrt.SEM_NOALIGNMENTFAULTEXCEPT| - msvcrt.SEM_NOGPFAULTERRORBOX| - msvcrt.SEM_NOOPENFILEERRORBOX) - try: - msvcrt.CrtSetReportMode - except AttributeError: - # release build - pass - else: - for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: - if ns.verbose and ns.verbose >= 2: - msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) - msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) - else: - msvcrt.CrtSetReportMode(m, 0) - if ns.wait: - input("Press any key to continue...") - if ns.slaveargs is not None: - args, kwargs = json.loads(ns.slaveargs) - if kwargs.get('huntrleaks'): + ns_dict, testname = json.loads(ns.slaveargs) + ns = types.SimpleNamespace(**ns_dict) + + setup_tests(ns) + + if ns.huntrleaks: unittest.BaseTestSuite._cleanup = False + try: - result = runtest(*args, **kwargs) + result = runtest(testname, ns.verbose, ns.quiet, + ns.huntrleaks, + output_on_failure=ns.verbose3, + timeout=ns.timeout, failfast=ns.failfast, + match_tests=ns.match_tests, pgo=ns.pgo, + use_resources=ns.use_resources) except KeyboardInterrupt: result = INTERRUPTED, '' except BaseException as e: traceback.print_exc() result = CHILD_ERROR, str(e) + sys.stdout.flush() print() # Force a newline (just in case) print(json.dumps(result)) sys.exit(0) + setup_tests(ns) + + if ns.wait: + input("Press any key to continue...") + good = [] bad = [] skipped = []