[Lldb-commits] [lldb] r203180 - This commit provides support for running the dosep.ty test driver with multiple threads.

Steve Pucci spucci at google.com
Thu Mar 6 16:01:11 PST 2014


Author: spucci
Date: Thu Mar  6 18:01:11 2014
New Revision: 203180

URL: http://llvm.org/viewvc/llvm-project?rev=203180&view=rev
Log:
This commit provides support for running the dosep.ty test driver with multiple threads.

It speeds up running the full test suite on my HP z620 Ubuntu machine with 32 hyperthreaded CPUs from 11 minutes to about 1m13s (about 9x).

The default behavior is to run single-threaded as before.  If the environment variable LLDB_TEST_THREADS is set, a Python work queue is set up with that many worker threads.

To avoid collisions within a test directory where multiple tests make use of the same prebuilt executable, the unit of work for the worker threads is a single directory (that is, all tests within a directory are processed in the normal serial way by a single thread).

tfiala & I have run this way a number of times; the only issue I found was that the TestProcessAttach.py test failed once, when attempting to attach to the process "a.out" by name.  I assume this is because some other thread was running an executable of that name at the same time, and we were attempting to attach to the wrong one, so I changed that test to use a different executable name (that change is also included in this commit).

Modified:
    lldb/trunk/test/dosep.ty
    lldb/trunk/test/functionalities/process_attach/Makefile
    lldb/trunk/test/functionalities/process_attach/TestProcessAttach.py

Modified: lldb/trunk/test/dosep.ty
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/dosep.ty?rev=203180&r1=203179&r2=203180&view=diff
==============================================================================
--- lldb/trunk/test/dosep.ty (original)
+++ lldb/trunk/test/dosep.ty Thu Mar  6 18:01:11 2014
@@ -5,32 +5,77 @@ Run the test suite using a separate proc
 """
 
 import os, sys, platform
+import Queue, threading
+
 from optparse import OptionParser
 
 # Command template of the invocation of the test driver.
 template = '%s/dotest.py %s -p %s %s'
 
-def walk_and_invoke(test_root, dotest_options):
-    """Look for matched file and invoke test driver on it."""
+def process_dir(root, files, test_root, dotest_options):
+    """Examine a directory for tests, and invoke any found within it."""
     failed = []
     passed = []
-    for root, dirs, files in os.walk(test_root, topdown=False):
-        for name in files:
-            path = os.path.join(root, name)
+    for name in files:
+        path = os.path.join(root, name)
+
+        # We're only interested in the test file with the "Test*.py" naming pattern.
+        if not name.startswith("Test") or not name.endswith(".py"):
+            continue
+
+        # Neither a symbolically linked file.
+        if os.path.islink(path):
+            continue
+
+        command = template % (test_root, dotest_options if dotest_options else "", name, root)
+        if 0 != os.system(command):
+            failed.append(name)
+        else:
+            passed.append(name)
+    return (failed, passed)
 
-            # We're only interested in the test file with the "Test*.py" naming pattern.
-            if not name.startswith("Test") or not name.endswith(".py"):
-                continue
-
-            # Neither a symbolically linked file.
-            if os.path.islink(path):
-                continue
-
-            command = template % (test_root, dotest_options if dotest_options else "", name, root)
-            if 0 != os.system(command):
-                failed.append(name) 
-            else:
-                passed.append(name)
+in_q = None
+out_q = None
+
+def process_dir_worker():
+    """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()
+
+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."""
+    failed = []
+    passed = []
+    if (num_threads > 1):
+        print "Running multithreaded with " + str(num_threads) + " 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()
+    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
     return (failed, passed)
 
 def main():
@@ -46,9 +91,16 @@ Run lldb test suite using a separate pro
 
     opts, args = parser.parse_args()
     dotest_options = opts.dotest_options
+    num_threads_str = os.environ.get("LLDB_TEST_THREADS")
+    if num_threads_str:
+        num_threads = int(num_threads_str)
+        if num_threads < 1:
+            num_threads = 1
+    else:
+        num_threads = 1
 
     system_info = " ".join(platform.uname())
-    (failed, passed) = walk_and_invoke(test_root, dotest_options)
+    (failed, passed) = walk_and_invoke(test_root, dotest_options, num_threads)
     num_tests = len(failed) + len(passed)
 
     print "Ran %d tests." % num_tests

Modified: lldb/trunk/test/functionalities/process_attach/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/process_attach/Makefile?rev=203180&r1=203179&r2=203180&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/process_attach/Makefile (original)
+++ lldb/trunk/test/functionalities/process_attach/Makefile Thu Mar  6 18:01:11 2014
@@ -2,4 +2,6 @@ LEVEL = ../../make
 
 C_SOURCES := main.c
 
+EXE := ProcessAttach
+
 include $(LEVEL)/Makefile.rules

Modified: lldb/trunk/test/functionalities/process_attach/TestProcessAttach.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/process_attach/TestProcessAttach.py?rev=203180&r1=203179&r2=203180&view=diff
==============================================================================
--- lldb/trunk/test/functionalities/process_attach/TestProcessAttach.py (original)
+++ lldb/trunk/test/functionalities/process_attach/TestProcessAttach.py Thu Mar  6 18:01:11 2014
@@ -8,6 +8,8 @@ import lldb
 from lldbtest import *
 import lldbutil
 
+exe_name = "ProcessAttach"  # Must match Makefile
+
 class ProcessAttachTestCase(TestBase):
 
     mydir = TestBase.compute_mydir(__file__)
@@ -45,7 +47,7 @@ class ProcessAttachTestCase(TestBase):
     def process_attach_by_id(self):
         """Test attach by process id"""
 
-        exe = os.path.join(os.getcwd(), "a.out")
+        exe = os.path.join(os.getcwd(), exe_name)
 
         # Spawn a new process
         popen = self.spawnSubprocess(exe)
@@ -62,13 +64,13 @@ class ProcessAttachTestCase(TestBase):
     def process_attach_by_name(self):
         """Test attach by process name"""
 
-        exe = os.path.join(os.getcwd(), "a.out")
+        exe = os.path.join(os.getcwd(), exe_name)
 
         # Spawn a new process
         popen = self.spawnSubprocess(exe)
         self.addTearDownHook(self.cleanupSubprocesses)
 
-        self.runCmd("process attach -n a.out")
+        self.runCmd("process attach -n " + exe_name)
 
         target = self.dbg.GetSelectedTarget()
 





More information about the lldb-commits mailing list