mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-05-19 13:38:56 +00:00
[lit] Refactor test execution logic into lit.run.Run.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@189554 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b11b690d3f
commit
07f0f16bfd
@ -7,17 +7,16 @@ See lit.pod for more information.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import absolute_import
|
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.ProgressBar
|
||||||
import lit.LitConfig
|
import lit.LitConfig
|
||||||
import lit.Test
|
import lit.Test
|
||||||
import lit.run
|
import lit.run
|
||||||
import lit.util
|
import lit.util
|
||||||
|
|
||||||
import lit.discovery
|
import lit.discovery
|
||||||
|
|
||||||
class TestingProgressDisplay:
|
class TestingProgressDisplay(object):
|
||||||
def __init__(self, opts, numTests, progressBar=None):
|
def __init__(self, opts, numTests, progressBar=None):
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.numTests = numTests
|
self.numTests = numTests
|
||||||
@ -57,107 +56,6 @@ class TestingProgressDisplay:
|
|||||||
|
|
||||||
sys.stdout.flush()
|
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 = {}):
|
def main(builtinParameters = {}):
|
||||||
# Bump the GIL check interval, its more important to get any one thread to a
|
# 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.
|
# blocking operation (hopefully exec) than to try and unblock other threads.
|
||||||
@ -365,19 +263,8 @@ def main(builtinParameters = {}):
|
|||||||
|
|
||||||
startTime = time.time()
|
startTime = time.time()
|
||||||
display = TestingProgressDisplay(opts, len(run.tests), progressBar)
|
display = TestingProgressDisplay(opts, len(run.tests), progressBar)
|
||||||
provider = TestProvider(run.tests, opts.maxTime)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import win32api
|
run.execute_tests(display, opts.numThreads, opts.maxTime)
|
||||||
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)
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
display.finish()
|
display.finish()
|
||||||
@ -385,11 +272,6 @@ def main(builtinParameters = {}):
|
|||||||
if not opts.quiet:
|
if not opts.quiet:
|
||||||
print('Testing Time: %.2fs'%(time.time() - startTime))
|
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.
|
# List test results organized by kind.
|
||||||
hasFailures = False
|
hasFailures = False
|
||||||
byCode = {}
|
byCode = {}
|
||||||
|
@ -1,8 +1,98 @@
|
|||||||
|
import os
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
try:
|
||||||
|
import win32api
|
||||||
|
except ImportError:
|
||||||
|
win32api = None
|
||||||
|
|
||||||
import lit.Test
|
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):
|
class Run(object):
|
||||||
"""
|
"""
|
||||||
This class represents a concrete, configured testing run.
|
This class represents a concrete, configured testing run.
|
||||||
@ -14,7 +104,7 @@ class Run(object):
|
|||||||
|
|
||||||
def execute_test(self, test):
|
def execute_test(self, test):
|
||||||
result = None
|
result = None
|
||||||
startTime = time.time()
|
start_time = time.time()
|
||||||
try:
|
try:
|
||||||
result = test.config.test_format.execute(test, self.lit_config)
|
result = test.config.test_format.execute(test, self.lit_config)
|
||||||
|
|
||||||
@ -34,6 +124,69 @@ class Run(object):
|
|||||||
output += traceback.format_exc()
|
output += traceback.format_exc()
|
||||||
output += '\n'
|
output += '\n'
|
||||||
result = lit.Test.Result(lit.Test.UNRESOLVED, output)
|
result = lit.Test.Result(lit.Test.UNRESOLVED, output)
|
||||||
result.elapsed = time.time() - startTime
|
result.elapsed = time.time() - start_time
|
||||||
|
|
||||||
test.setResult(result)
|
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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user