Commit 33b3f651 authored by Ian Lynagh's avatar Ian Lynagh
Browse files

Allow threading to be completely disabled with USETHREADS=0

I had to pull the global classes and instances out into their own module
as there was a catch-22: testlib needed to know if threading was enabled,
but we don't know that until we have gone through the argument, but going
through the arguments required changing things like config in testlib.
parent a67606ed
......@@ -10,18 +10,12 @@ import sys
import os
import string
import getopt
import threading
from testlib import *
from testutil import *
from testglobals import *
global config
config = getConfig() # get it from testlib
global testopts_local
testopts_local.x = TestOptions()
global thisdir_testopts
thisdir_testopts = getThisDirTestOpts()
config = getConfig() # get it from testglobals
# -----------------------------------------------------------------------------
# cmd-line options
......@@ -65,6 +59,22 @@ for opt,arg in opts:
if opt == '--threads':
config.threads = int(arg)
# Can't import this earlier as we need to know if threading will be
# enabled or not
from testlib import *
global testopts_local
testopts_local.x = TestOptions()
global thisdir_testopts
thisdir_testopts = getThisDirTestOpts()
if config.use_threads:
t.lock = threading.Lock()
t.thread_pool = threading.Condition(t.lock)
t.running_threads = 0
# -----------------------------------------------------------------------------
# The main dude
......@@ -85,12 +95,14 @@ for file in t_files:
print '====> Running', file
newTestDir(os.path.dirname(file))
try:
t.running_threads=0
if config.use_threads:
t.running_threads=0
execfile(file)
t.thread_pool.acquire()
while t.running_threads>0:
t.thread_pool.wait()
t.thread_pool.release()
if config.use_threads:
t.thread_pool.acquire()
while t.running_threads>0:
t.thread_pool.wait()
t.thread_pool.release()
except:
print '*** found an error while executing ', file, ':'
traceback.print_exc()
......
#
# (c) Simon Marlow 2002
#
# -----------------------------------------------------------------------------
# Configuration info
# There is a single global instance of this structure, stored in the
# variable config below. The fields of the structure are filled in by
# the appropriate config script(s) for this compiler/platform, in
# ../config.
#
# Bits of the structure may also be filled in from the command line,
# via the build system, using the '-e' option to runtests.
class TestConfig:
def __init__(self):
# Directory below which to look for test description files (foo.T)
self.rootdir = '.'
# Run these tests only (run all tests if empty)
self.only = []
# Accept new output which differs from the sample?
self.accept = 0
# File in which to save the summary
self.output_summary = ''
# What platform are we running on?
self.platform = ''
# What is the wordsize (in bits) of this platform?
self.wordsize = ''
# Verbosity level
self.verbose = 1
# run the "fast" version of the test suite
self.fast = 0
# Compiler type (ghc, hugs, nhc, etc.)
self.compiler_type = ''
# Path to the compiler
self.compiler = ''
# Flags we always give to this compiler
self.compiler_always_flags = []
# Which ways to run tests (when compiling and running respectively)
# Other ways are added from the command line if we have the appropriate
# libraries.
self.compile_ways = []
self.run_ways = []
# Lists of flags for each way
self.way_flags = {}
self.way_rts_flags = {}
# the timeout program
self.timeout_prog = ''
self.timeout = 300
# threads
self.threads = 1
self.use_threads = 1
global config
config = TestConfig()
def getConfig():
return config
# -----------------------------------------------------------------------------
# Information about the current test run
class TestRun:
def __init__(self):
self.start_time = ''
self.total_tests = 0
self.total_test_cases = 0
self.n_framework_failures = 0
self.framework_failures = {}
self.n_tests_skipped = 0
self.tests_skipped = {}
self.n_expected_passes = 0
self.expected_passes = {}
self.n_expected_failures = 0
self.expected_failures = {}
self.n_unexpected_passes = 0
self.unexpected_passes = {}
self.n_unexpected_failures = 0
self.unexpected_failures = {}
global t
t = TestRun()
def getTestRun():
return t
# -----------------------------------------------------------------------------
# Information about the current test
class TestOptions:
def __init__(self):
# skip this test?
self.skip = 0;
# skip these ways
self.omit_ways = []
# skip all ways except these ([] == do all ways)
self.only_ways = []
# the result we normally expect for this test
self.expect = 'pass';
# override the expected result for certain ways
self.expect_fail_for = [];
# the stdin file that this test will use (empty for <name>.stdin)
self.stdin = ''
# compile this test to .hc only
self.compile_to_hc = 0
# extra compiler opts for this test
self.extra_hc_opts = ''
# extra run opts for this test
self.extra_run_opts = ''
# expected exit code
self.exit_code = 0
# should we clean up after ourselves?
self.cleanup = ''
# should we run this test alone, i.e. not run it in parallel with
# any other threads
self.alone = 0
# The default set of options
global default_testopts
default_testopts = TestOptions()
......@@ -9,158 +9,14 @@ import re
import traceback
import copy
import glob
import threading
import thread
from string import join
from testglobals import *
from testutil import *
# -----------------------------------------------------------------------------
# Configuration info
# There is a single global instance of this structure, stored in the
# variable config below. The fields of the structure are filled in by
# the appropriate config script(s) for this compiler/platform, in
# ../config.
#
# Bits of the structure may also be filled in from the command line,
# via the build system, using the '-e' option to runtests.
class TestConfig:
def __init__(self):
# Directory below which to look for test description files (foo.T)
self.rootdir = '.'
# Run these tests only (run all tests if empty)
self.only = []
# Accept new output which differs from the sample?
self.accept = 0
# File in which to save the summary
self.output_summary = ''
# What platform are we running on?
self.platform = ''
# What is the wordsize (in bits) of this platform?
self.wordsize = ''
# Verbosity level
self.verbose = 1
# run the "fast" version of the test suite
self.fast = 0
# Compiler type (ghc, hugs, nhc, etc.)
self.compiler_type = ''
# Path to the compiler
self.compiler = ''
# Flags we always give to this compiler
self.compiler_always_flags = []
# Which ways to run tests (when compiling and running respectively)
# Other ways are added from the command line if we have the appropriate
# libraries.
self.compile_ways = []
self.run_ways = []
# Lists of flags for each way
self.way_flags = {}
self.way_rts_flags = {}
# the timeout program
self.timeout_prog = ''
self.timeout = 300
# threads
self.threads = 1
global config
config = TestConfig()
def getConfig():
return config
# -----------------------------------------------------------------------------
# Information about the current test run
class TestRun:
def __init__(self):
self.start_time = ''
self.total_tests = 0
self.total_test_cases = 0
self.n_framework_failures = 0
self.framework_failures = {}
self.n_tests_skipped = 0
self.tests_skipped = {}
self.n_expected_passes = 0
self.expected_passes = {}
self.n_expected_failures = 0
self.expected_failures = {}
self.n_unexpected_passes = 0
self.unexpected_passes = {}
self.n_unexpected_failures = 0
self.unexpected_failures = {}
self.lock = threading.Lock()
self.thread_pool = threading.Condition(self.lock)
self.running_threads = 0
global t
t = TestRun()
def getTestRun():
return t
# -----------------------------------------------------------------------------
# Information about the current test
class TestOptions:
def __init__(self):
# skip this test?
self.skip = 0;
# skip these ways
self.omit_ways = []
# skip all ways except these ([] == do all ways)
self.only_ways = []
# the result we normally expect for this test
self.expect = 'pass';
# override the expected result for certain ways
self.expect_fail_for = [];
# the stdin file that this test will use (empty for <name>.stdin)
self.stdin = ''
# compile this test to .hc only
self.compile_to_hc = 0
# extra compiler opts for this test
self.extra_hc_opts = ''
# extra run opts for this test
self.extra_run_opts = ''
# expected exit code
self.exit_code = 0
# should we clean up after ourselves?
self.cleanup = ''
# should we run this test alone, ie disable THREADS
self.nothreads = 0
# The default set of options
global default_testopts
default_testopts = TestOptions()
if config.use_threads:
import threading
import thread
# Options valid for all the tests in the current "directory". After
# each test, we reset the options to these. To change the options for
......@@ -174,8 +30,14 @@ def getThisDirTestOpts():
# Options valid for the current test only (these get reset to
# testdir_testopts after each test).
global testopts_local
testopts_local = threading.local()
if config.use_threads:
testopts_local = threading.local()
else:
class TestOpts_Local:
pass
testopts_local = TestOpts_Local()
def getTestOpts():
return testopts_local.x
......@@ -309,8 +171,8 @@ def skip_if_fast(opts):
opts.skip = 1
# ---
def nothreads(opts):
opts.nothreads=1
def alone(opts):
opts.alone = 1
# ----
# Function for composing two opt-fns together
......@@ -343,43 +205,40 @@ def getTestDir():
# name :: String
# setup :: TestOpts -> IO ()
def test ( name, setup, func, args):
return test_common(0,name,setup,func,args)
def test_alone (name, setup, func, args):
return test_common(1,name,setup,func,args)
def test_common (ser, name, setup, func, args):
n = 1
opts = copy.copy(thisdir_testopts)
setup(opts)
if ser or opts.nothreads:
if opts.alone:
n = config.threads
ok = 0
t.thread_pool.acquire()
try:
while config.threads<(t.running_threads+n):
t.thread_pool.wait()
t.running_threads = t.running_threads+n
ok=1
t.thread_pool.release()
thread.start_new_thread(test_common_thread, (n, name, opts, func, args))
except:
if not ok:
t.thread_pool.release()
def test_common_thread(n, name, opts, func, args):
t.lock.acquire()
try:
test_common_work(name,opts,func,args)
finally:
t.lock.release()
if config.use_threads:
t.thread_pool.acquire()
t.running_threads = t.running_threads - n
t.thread_pool.notify()
t.thread_pool.release()
try:
while config.threads<(t.running_threads+n):
t.thread_pool.wait()
t.running_threads = t.running_threads+n
ok=1
t.thread_pool.release()
thread.start_new_thread(test_common_thread, (n, name, opts, func, args))
except:
if not ok:
t.thread_pool.release()
else:
test_common_work (name, opts, func, args)
if config.use_threads:
def test_common_thread(n, name, opts, func, args):
t.lock.acquire()
try:
test_common_work(name,opts,func,args)
finally:
t.lock.release()
t.thread_pool.acquire()
t.running_threads = t.running_threads - n
t.thread_pool.notify()
t.thread_pool.release()
def test_common_work (name, opts, func, args):
t.total_tests = t.total_tests+1
......@@ -445,11 +304,13 @@ def do_test(name, way, func, args):
try:
print '=====>', full_name
t.lock.release()
if config.use_threads:
t.lock.release()
try:
result = apply(func, [name,way] + args)
finally:
t.lock.acquire()
if config.use_threads:
t.lock.acquire()
if getTestOpts().expect != 'pass' and getTestOpts().expect != 'fail' or \
result != 'pass' and result != 'fail':
......
......@@ -93,10 +93,12 @@ RUNTEST_OPTS += \
-e config.platform=\"$(TARGETPLATFORM)\" \
-e config.wordsize=\"$(WORDSIZE)\" \
-e default_testopts.cleanup=\"$(CLEANUP)\" \
-e "if '$(USETHREADS)': config.use_threads=int($(USETHREADS))" \
-e config.timeout="int($(TIMEOUT)) or config.timeout" \
-e config.timeout_prog=\"$(TOP)/timeout/timeout\" \
$(EXTRA_RUNTEST_OPTS)
ifeq "$(fast)" "YES"
setfast = -e config.fast=1
else
......
setTestOpts(compose(nothreads,only_compiler_types(['ghc'])))
setTestOpts(compose(alone,only_compiler_types(['ghc'])))
test('ghcpkg01', skip_if_fast, run_command_ignore_output, ['$MAKE ghcpkg01'])
test('ghcpkg02', skip_if_fast, run_command_ignore_output, ['$MAKE ghcpkg02'])
......
setTestOpts(compose(nothreads, only_compiler_types(['ghc'])))
setTestOpts(compose(alone, only_compiler_types(['ghc'])))
test('driver011', normal, run_command_ignore_output, ['$MAKE test011'])
test('driver012', normal, run_command_ignore_output, ['$MAKE test012'])
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment