[llvm] r189554 - [lit] Refactor test execution logic into lit.run.Run.

Daniel Dunbar daniel at zuster.org
Wed Aug 28 17:54:15 PDT 2013


Author: ddunbar
Date: Wed Aug 28 19:54:15 2013
New Revision: 189554

URL: http://llvm.org/viewvc/llvm-project?rev=189554&view=rev
Log:
[lit] Refactor test execution logic into lit.run.Run.

Modified:
    llvm/trunk/utils/lit/lit/main.py
    llvm/trunk/utils/lit/lit/run.py

Modified: llvm/trunk/utils/lit/lit/main.py
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/lit/lit/main.py?rev=189554&r1=189553&r2=189554&view=diff
==============================================================================
--- llvm/trunk/utils/lit/lit/main.py (original)
+++ llvm/trunk/utils/lit/lit/main.py Wed Aug 28 19:54:15 2013
@@ -7,17 +7,16 @@ See lit.pod for more information.
 """
 
 from __future__ import absolute_import
-import math, os, platform, random, re, sys, time, threading, traceback
+import math, os, platform, random, re, sys, time
 
 import lit.ProgressBar
 import lit.LitConfig
 import lit.Test
 import lit.run
 import lit.util
-
 import lit.discovery
 
-class TestingProgressDisplay:
+class TestingProgressDisplay(object):
     def __init__(self, opts, numTests, progressBar=None):
         self.opts = opts
         self.numTests = numTests
@@ -57,107 +56,6 @@ class TestingProgressDisplay:
 
         sys.stdout.flush()
 
-class TestProvider:
-    def __init__(self, tests, maxTime):
-        self.maxTime = maxTime
-        self.iter = iter(range(len(tests)))
-        self.lock = threading.Lock()
-        self.startTime = time.time()
-        self.canceled = False
-
-    def cancel(self):
-        self.lock.acquire()
-        self.canceled = True
-        self.lock.release()
-
-    def get(self):
-        # Check if we have run out of time.
-        if self.maxTime is not None:
-            if time.time() - self.startTime > self.maxTime:
-                return None
-
-        # Otherwise take the next test.
-        self.lock.acquire()
-        if self.canceled:
-          self.lock.release()
-          return None
-        for item in self.iter:
-            break
-        else:
-            item = None
-        self.lock.release()
-        return item
-
-class Tester(object):
-    def __init__(self, run_instance, provider, consumer):
-        self.run_instance = run_instance
-        self.provider = provider
-        self.consumer = consumer
-
-    def run(self):
-        while 1:
-            item = self.provider.get()
-            if item is None:
-                break
-            self.runTest(item)
-        self.consumer.taskFinished()
-
-    def runTest(self, test_index):
-        test = self.run_instance.tests[test_index]
-        try:
-            self.run_instance.execute_test(test)
-        except KeyboardInterrupt:
-            # This is a sad hack. Unfortunately subprocess goes
-            # bonkers with ctrl-c and we start forking merrily.
-            print('\nCtrl-C detected, goodbye.')
-            os.kill(0,9)
-        self.consumer.update(test_index, test)
-
-class ThreadResultsConsumer(object):
-    def __init__(self, display):
-        self.display = display
-        self.lock = threading.Lock()
-
-    def update(self, test_index, test):
-        self.lock.acquire()
-        try:
-            self.display.update(test)
-        finally:
-            self.lock.release()
-
-    def taskFinished(self):
-        pass
-
-    def handleResults(self):
-        pass
-
-def run_one_tester(run, provider, display):
-    tester = Tester(run, provider, display)
-    tester.run()
-
-def runTests(numThreads, run, provider, display):
-    consumer = ThreadResultsConsumer(display)
-
-    # If only using one testing thread, don't use tasks at all; this lets us
-    # profile, among other things.
-    if numThreads == 1:
-        run_one_tester(run, provider, consumer)
-        return
-
-    # Start all of the tasks.
-    tasks = [threading.Thread(target=run_one_tester,
-                              args=(run, provider, consumer))
-             for i in range(numThreads)]
-    for t in tasks:
-        t.start()
-
-    # Allow the consumer to handle results, if necessary.
-    consumer.handleResults()
-
-    # Wait for all the tasks to complete.
-    for t in tasks:
-        t.join()
-
 def main(builtinParameters = {}):
     # Bump the GIL check interval, its more important to get any one thread to a
     # blocking operation (hopefully exec) than to try and unblock other threads.
@@ -365,19 +263,8 @@ def main(builtinParameters = {}):
 
     startTime = time.time()
     display = TestingProgressDisplay(opts, len(run.tests), progressBar)
-    provider = TestProvider(run.tests, opts.maxTime)
-
     try:
-      import win32api
-    except ImportError:
-      pass
-    else:
-      def console_ctrl_handler(type):
-        provider.cancel()
-        return True
-      win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
-    try:
-        runTests(opts.numThreads, run, provider, display)
+        run.execute_tests(display, opts.numThreads, opts.maxTime)
     except KeyboardInterrupt:
         sys.exit(2)
     display.finish()
@@ -385,11 +272,6 @@ def main(builtinParameters = {}):
     if not opts.quiet:
         print('Testing Time: %.2fs'%(time.time() - startTime))
 
-    # Update results for any tests which weren't run.
-    for test in run.tests:
-        if test.result is None:
-            test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0))
-
     # List test results organized by kind.
     hasFailures = False
     byCode = {}

Modified: llvm/trunk/utils/lit/lit/run.py
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/lit/lit/run.py?rev=189554&r1=189553&r2=189554&view=diff
==============================================================================
--- llvm/trunk/utils/lit/lit/run.py (original)
+++ llvm/trunk/utils/lit/lit/run.py Wed Aug 28 19:54:15 2013
@@ -1,8 +1,98 @@
+import os
+import threading
 import time
 import traceback
 
+try:
+    import win32api
+except ImportError:
+    win32api = None
+
 import lit.Test
 
+###
+# Test Execution Implementation
+
+class TestProvider(object):
+    def __init__(self, tests, max_time):
+        self.max_time = max_time
+        self.iter = iter(range(len(tests)))
+        self.lock = threading.Lock()
+        self.start_time = time.time()
+        self.canceled = False
+
+    def cancel(self):
+        self.lock.acquire()
+        self.canceled = True
+        self.lock.release()
+
+    def get(self):
+        # Check if we have run out of time.
+        if self.max_time is not None:
+            if time.time() - self.start_time > self.max_time:
+                return None
+
+        # Otherwise take the next test.
+        self.lock.acquire()
+        if self.canceled:
+          self.lock.release()
+          return None
+        for item in self.iter:
+            break
+        else:
+            item = None
+        self.lock.release()
+        return item
+
+class Tester(object):
+    def __init__(self, run_instance, provider, consumer):
+        self.run_instance = run_instance
+        self.provider = provider
+        self.consumer = consumer
+
+    def run(self):
+        while 1:
+            item = self.provider.get()
+            if item is None:
+                break
+            self.run_test(item)
+        self.consumer.task_finished()
+
+    def run_test(self, test_index):
+        test = self.run_instance.tests[test_index]
+        try:
+            self.run_instance.execute_test(test)
+        except KeyboardInterrupt:
+            # This is a sad hack. Unfortunately subprocess goes
+            # bonkers with ctrl-c and we start forking merrily.
+            print('\nCtrl-C detected, goodbye.')
+            os.kill(0,9)
+        self.consumer.update(test_index, test)
+
+class ThreadResultsConsumer(object):
+    def __init__(self, display):
+        self.display = display
+        self.lock = threading.Lock()
+
+    def update(self, test_index, test):
+        self.lock.acquire()
+        try:
+            self.display.update(test)
+        finally:
+            self.lock.release()
+
+    def task_finished(self):
+        pass
+
+    def handle_results(self):
+        pass
+
+def run_one_tester(run, provider, display):
+    tester = Tester(run, provider, display)
+    tester.run()
+
+###
+
 class Run(object):
     """
     This class represents a concrete, configured testing run.
@@ -14,7 +104,7 @@ class Run(object):
 
     def execute_test(self, test):
         result = None
-        startTime = time.time()
+        start_time = time.time()
         try:
             result = test.config.test_format.execute(test, self.lit_config)
 
@@ -34,6 +124,69 @@ class Run(object):
             output += traceback.format_exc()
             output += '\n'
             result = lit.Test.Result(lit.Test.UNRESOLVED, output)
-        result.elapsed = time.time() - startTime
+        result.elapsed = time.time() - start_time
 
         test.setResult(result)
+
+    def execute_tests(self, display, jobs, max_time=None):
+        """
+        execute_tests(display, jobs, [max_time])
+
+        Execute each of the tests in the run, using up to jobs number of
+        parallel tasks, and inform the display of each individual result. The
+        provided tests should be a subset of the tests available in this run
+        object.
+
+        If max_time is non-None, it should be a time in seconds after which to
+        stop executing tests.
+
+        The display object will have its update method called with each test as
+        it is completed. The calls are guaranteed to be locked with respect to
+        one another, but are *not* guaranteed to be called on the same thread as
+        this method was invoked on.
+
+        Upon completion, each test in the run will have its result
+        computed. Tests which were not actually executed (for any reason) will
+        be given an UNRESOLVED result.
+        """
+
+        # Create the test provider object.
+        provider = TestProvider(self.tests, max_time)
+
+        # Install a console-control signal handler on Windows.
+        if win32api is not None:
+            def console_ctrl_handler(type):
+                provider.cancel()
+                return True
+            win32api.SetConsoleCtrlHandler(console_ctrl_handler, True)
+
+        # Actually execute the tests.
+        self._execute_tests_with_provider(provider, display, jobs)
+
+        # Update results for any tests which weren't run.
+        for test in self.tests:
+            if test.result is None:
+                test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0))
+
+    def _execute_tests_with_provider(self, provider, display, jobs):
+        consumer = ThreadResultsConsumer(display)
+
+        # If only using one testing thread, don't use tasks at all; this lets us
+        # profile, among other things.
+        if jobs == 1:
+            run_one_tester(self, provider, consumer)
+            return
+
+        # Start all of the tasks.
+        tasks = [threading.Thread(target=run_one_tester,
+                                  args=(self, provider, consumer))
+                 for i in range(jobs)]
+        for t in tasks:
+            t.start()
+
+        # Allow the consumer to handle results, if necessary.
+        consumer.handle_results()
+
+        # Wait for all the tasks to complete.
+        for t in tasks:
+            t.join()





More information about the llvm-commits mailing list