[Lldb-commits] [lldb] r212513 - Enable multi-process testing for MacOSX.

Todd Fiala todd.fiala at gmail.com
Mon Jul 7 23:42:37 PDT 2014


Author: tfiala
Date: Tue Jul  8 01:42:37 2014
New Revision: 212513

URL: http://llvm.org/viewvc/llvm-project?rev=212513&view=rev
Log:
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.

Modified:
    lldb/trunk/test/dosep.ty
    lldb/trunk/test/dotest.py

Modified: lldb/trunk/test/dosep.ty
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dosep.ty?rev=212513&r1=212512&r2=212513&view=diff
==============================================================================
--- lldb/trunk/test/dosep.ty (original)
+++ lldb/trunk/test/dosep.ty Tue Jul  8 01:42:37 2014
@@ -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,
 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():

Modified: lldb/trunk/test/dotest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dotest.py?rev=212513&r1=212512&r2=212513&view=diff
==============================================================================
--- lldb/trunk/test/dotest.py (original)
+++ lldb/trunk/test/dotest.py Tue Jul  8 01:42:37 2014
@@ -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, '..', '..')
         





More information about the lldb-commits mailing list