blob: dc9afa03df3ea5ce18cb235905e9c92b21646209 [file] [log] [blame]
import lit.formats
import lit.util
import lit
import os, glob, re
import shlex
import pipes
from lit.formats import FileBasedTest
from lit.TestRunner import executeScript, executeScriptInternal, parseIntegratedTestScriptCommands, getDefaultSubstitutions, applySubstitutions, getTempPaths
from lit import Test
from lit.util import to_bytes, to_string
try:
from shlex import quote # python 3.3 and above
except:
from pipes import quote # python 3.2 and earlier
def parseBenchmarkScript(test):
"""Scan a llvm-testsuite like benchmark .test script."""
def parseShellCommand(script, ln):
# Trim trailing whitespace.
ln = ln.rstrip()
# Collapse lines with trailing '\\'.
if script and script[-1][-1] == '\\':
script[-1] = script[-1][:-1] + ln
else:
script.append(ln)
# Collect the test lines from the script.
sourcepath = test.getSourcePath()
runscript = []
verifyscript = []
keywords = ['RUN:', 'VERIFY:']
for line_number, command_type, ln in \
parseIntegratedTestScriptCommands(sourcepath, keywords):
if command_type == 'RUN':
parseShellCommand(runscript, ln)
elif command_type == 'VERIFY':
parseShellCommand(verifyscript, ln)
else:
raise ValueError("unknown script command type: %r" % (
command_type,))
# Verify the script contains a run line.
if runscript == []:
return lit.Test.Result(Test.UNRESOLVED, "Test has no RUN: line!")
# Check for unterminated run lines.
for script in runscript, verifyscript:
if script and script[-1][-1] == '\\':
return lit.Test.Result(Test.UNRESOLVED,
"Test has unterminated RUN/VERIFY lines (with '\\')")
return runscript,verifyscript
def getUserTimeFromTimeOutput(f):
with open(f) as fd:
l = [l for l in fd.readlines()
if l.startswith('user')]
assert len(l) == 1
m = re.match(r'user\s+([0-9.]+)', l[0])
return float(m.group(1))
def collectCompileTime(test):
# TODO: This is not correct yet as the directory may contain .o.time files
# of multiple benchmarks in the case of SingleSource tests.
compile_time = 0.0
basepath = os.path.dirname(test.getFilePath())
for path, subdirs, files in os.walk(basepath):
for file in files:
if file.endswith('.o.time'):
compile_time += getUserTimeFromTimeOutput(os.path.join(path, file))
return compile_time
def runScript(test, litConfig, script, tmpBase, useExternalSh = True):
execdir = os.path.dirname(test.getExecPath())
if useExternalSh:
res = executeScript(test, litConfig, tmpBase, script, execdir)
else:
res = executeScriptInternal(test, litConfig, tmpBase, script, execdir)
return res
def prepareRunSafely(config, commandline, outfile):
stdin = None
stdout = None
stderr = None
workdir = None
tokens = shlex.split(commandline)
# Parse "< INPUTFILE", "> OUTFILE", "2> OUTFILE" patterns
i = 0
while i < len(tokens):
if tokens[i] == "<" and i+1 < len(tokens):
stdin = tokens[i+1]
del tokens[i+1]
del tokens[i]
continue
elif tokens[i] == ">" and i+1 < len(tokens):
stdout = tokens[i+1]
del tokens[i+1]
del tokens[i]
continue
elif tokens[i] == "2>" and i+1 < len(tokens):
stderr = tokens[i+1]
del tokens[i+1]
del tokens[i]
continue
if i+2 < len(tokens) and tokens[i] == "cd" and tokens[i+2] == ";":
workdir = tokens[i+1]
del tokens[i+2]
del tokens[i+1]
del tokens[i]
continue
i += 1
runsafely = "%s/RunSafely.sh" % config.test_suite_root
runsafely_prefix = [ runsafely ]
if workdir is not None:
runsafely_prefix += [ "-d", workdir ]
timeit = "%s/tools/timeit" % config.test_source_root
if config.remote_host:
timeit = "%s/tools/timeit-target" % config.test_source_root
runsafely_prefix += [ "-r", config.remote_host ]
if config.remote_user:
runsafely_prefix += [ "-l", config.remote_user ]
if config.remote_client:
runsafely_prefix += [ "-rc", config.remote_client ]
if config.remote_port:
runsafely_prefix += [ "-rp", config.remote_port ]
if config.run_under:
runsafely_prefix += [ "-u", config.run_under ]
if not config.traditional_output:
runsafely_prefix += [ "-n" ]
if stdout is not None:
runsafely_prefix += [ "-o", stdout ]
if stderr is not None:
runsafely_prefix += [ "-e", stderr ]
else:
if stdout is not None or stderr is not None:
raise Exception("separate stdout/stderr redirection not possible with traditional output")
timeout = "7200"
if stdin is None:
stdin = "/dev/null"
runsafely_prefix += [ "-t", timeit, timeout, stdin, outfile ]
new_commandline = " ".join(map(quote, runsafely_prefix + tokens))
return new_commandline
class TestSuiteTest(FileBasedTest):
def __init__(self):
super(TestSuiteTest, self).__init__()
def execute(self, test, litConfig):
config = test.config
if config.unsupported:
return (Test.UNSUPPORTED, 'Test is unsupported')
# Parse benchmark script
res = parseBenchmarkScript(test)
if isinstance(res, lit.Test.Result):
return res
if litConfig.noExecute:
return lit.Test.Result(Test.PASS)
runscript, verifyscript = res
tmpDir, tmpBase = getTempPaths(test)
outfile = tmpBase + ".out"
substitutions = getDefaultSubstitutions(test, tmpDir, tmpBase)
substitutions += [('%o', outfile)]
runscript = applySubstitutions(runscript, substitutions)
verifyscript = applySubstitutions(verifyscript, substitutions)
adjusted_runscript = []
for line in runscript:
line = prepareRunSafely(config, line, outfile)
adjusted_runscript.append(line)
runscript = adjusted_runscript
# Create the output directory if it does not already exist.
lit.util.mkdir_p(os.path.dirname(tmpBase))
# Execute runscript (the "RUN:" part)
output = ""
n_runs = 1
runtimes = []
for n in range(n_runs):
res = runScript(test, litConfig, runscript, tmpBase)
if isinstance(res, lit.Test.Result):
return res
output += "\n" + "\n".join(runscript)
out, err, exitCode, timeoutInfo = res
if exitCode == Test.FAIL:
# Only show command output in case of errors
output += "\n" + out
output += "\n" + err
return lit.Test.Result(Test.FAIL, output)
timefile = "%s.time" % (outfile,)
try:
runtime = getUserTimeFromTimeOutput(timefile)
runtimes.append(runtime)
except IOError:
pass
# Run verification script (the "VERIFY:" part)
if len(verifyscript) > 0:
res = runScript(test, litConfig, verifyscript, tmpBase)
if isinstance(res, lit.Test.Result):
return res
out, err, exitCode, timeoutInfo = res
output += "\n" + "\n".join(verifyscript)
if exitCode != 0:
output += "\n" + out
output += "\n" + err
return lit.Test.Result(Test.FAIL, output)
# Put metrics into the test result.
result = lit.Test.Result(Test.PASS, output)
if len(runtimes) > 0:
result.addMetric('exec_time', lit.Test.toMetricValue(runtimes[0]))
try:
compile_time = collectCompileTime(test)
result.addMetric('compile_time',
lit.Test.toMetricValue(compile_time))
except IOError:
pass
return result
config.name = 'test-suite'
config.test_format = TestSuiteTest()
config.suffixes = ['.test']
config.excludes = ['ABI-Testsuite']
config.traditional_output = True
if 'SSH_AUTH_SOCK' in os.environ:
config.environment['SSH_AUTH_SOCK'] = os.environ['SSH_AUTH_SOCK']