Enable multi-process testing for MacOSX.

This change modifies the way the multi-threaded test runner works.
It uses the Python multiprocessing library rather than the threading
library.  Investigation showed that all MacOSX threads were waiting on
the global python lock when using the threading approach.  Not sure
why that differed from the Linux/FreeBSD implementations.

The new approach uses the multiprocessing library's Pool class.  It's
mildly cleaner than the other version, runs multithreaded on MacOSX,
and seems to have caused no performance regression on Linux.  The
worker thread logic is simpler with the Pool managing the worker
processes.

This also includes a minor change to the test runner's python
lldb dir logic using the -P option.  It now looks at the last line
of output rather than the first line.  This covers part of the issue
of extra options validation logic getting spit out.  The test runner
will now pick up the right python library directory.  It does not
fix all the issues, though, as a ton of tests (50+ on Linux) are
failing due to unexpected output when running lldb.

llvm-svn: 212513
This commit is contained in:
Todd Fiala 2014-07-08 06:42:37 +00:00
parent c4ebb129b7
commit 3f0a360f18
2 changed files with 31 additions and 35 deletions

View File

@ -4,9 +4,10 @@
Run the test suite using a separate process for each test file.
"""
import os, sys, platform
import Queue, threading
import multiprocessing
import os
import platform
import sys
from optparse import OptionParser
@ -38,47 +39,41 @@ def process_dir(root, files, test_root, dotest_options):
in_q = None
out_q = None
def process_dir_worker():
def process_dir_worker(arg_tuple):
"""Worker thread main loop when in multithreaded mode.
Takes one directory specification at a time and works on it."""
while True:
(root, files, test_root, dotest_options) = in_q.get()
(dir_failed, dir_passed) = process_dir(root, files, test_root, dotest_options)
out_q.put((dir_failed, dir_passed))
in_q.task_done()
(root, files, test_root, dotest_options) = arg_tuple
return process_dir(root, files, test_root, dotest_options)
def walk_and_invoke(test_root, dotest_options, num_threads):
"""Look for matched files and invoke test driver on each one.
In single-threaded mode, each test driver is invoked directly.
In multi-threaded mode, submit each test driver to a worker
queue, and then wait for all to complete."""
# Collect the test files that we'll run.
test_work_items = []
for root, dirs, files in os.walk(test_root, topdown=False):
test_work_items.append((root, files, test_root, dotest_options))
# Run the items, either in a pool (for multicore speedup) or
# calling each individually.
if num_threads > 1:
pool = multiprocessing.Pool(num_threads)
test_results = pool.map(process_dir_worker, test_work_items)
else:
test_results = []
for work_item in test_work_items:
test_results.append(process_dir_worker(work_item))
failed = []
passed = []
if (num_threads > 1):
print("Running multithreaded with %d threads" % num_threads)
global in_q
global out_q
in_q = Queue.Queue()
out_q = Queue.Queue()
for i in range(num_threads):
t = threading.Thread(target=process_dir_worker)
t.daemon = True
t.start()
else:
print("Running single-threaded")
for root, dirs, files in os.walk(test_root, topdown=False):
if (num_threads > 1):
in_q.put((root, files, test_root, dotest_options))
else:
(dir_failed, dir_passed) = process_dir(root, files, test_root, dotest_options)
failed += dir_failed
passed += dir_passed
if (num_threads > 1):
in_q.join()
while not out_q.empty():
(dir_failed, dir_passed) = out_q.get()
failed += dir_failed
passed += dir_passed
for test_result in test_results:
(dir_failed, dir_passed) = test_result
failed += dir_failed
passed += dir_passed
return (failed, passed)
def main():

View File

@ -1010,8 +1010,9 @@ def setupSysPath():
if lldb_dash_p_result and not lldb_dash_p_result.startswith(("<", "lldb: invalid option:")):
lines = lldb_dash_p_result.splitlines()
if len(lines) == 1 and os.path.isfile(os.path.join(lines[0], init_in_python_dir)):
lldbPath = lines[0]
# Assume the last line of output is the path. Generally there should only be one.
if os.path.isfile(os.path.join(lines[-1], init_in_python_dir)):
lldbPath = lines[-1]
if "freebsd" in sys.platform or "linux" in sys.platform:
os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPath, '..', '..')