diff options
Diffstat (limited to 'llvm/utils')
-rw-r--r-- | llvm/utils/lit/lit/Test.py | 16 | ||||
-rw-r--r-- | llvm/utils/lit/lit/TestRunner.py | 54 | ||||
-rw-r--r-- | llvm/utils/lit/lit/run.py | 20 |
3 files changed, 51 insertions, 39 deletions
diff --git a/llvm/utils/lit/lit/Test.py b/llvm/utils/lit/lit/Test.py index 1a9e3fe80fb..dc82670358a 100644 --- a/llvm/utils/lit/lit/Test.py +++ b/llvm/utils/lit/lit/Test.py @@ -172,7 +172,7 @@ class TestSuite: return os.path.join(self.source_root, *components) def getExecPath(self, components): - return os.path.join(self.exec_root, *components) + return os.path.join(self.exec_root, "Output", *components) class Test: """Test - Information on a single test instance.""" @@ -222,10 +222,13 @@ class Test: # Syntax error in an XFAIL line. self.result.code = UNRESOLVED self.result.output = str(e) - + def getFullName(self): return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite) + def getTestBaseName(self): + return self.path_in_suite[-1] + def getFilePath(self): if self.file_path: return self.file_path @@ -234,8 +237,11 @@ class Test: def getSourcePath(self): return self.suite.getSourcePath(self.path_in_suite) - def getExecPath(self): - return self.suite.getExecPath(self.path_in_suite) + def getTempFilePrefix(self): + return self.suite.getExecPath(self.path_in_suite) + ".tmp" + + def getTempFileDir(self): + return os.path.dirname(self.getTempFilePrefix()) def isExpectedToFail(self): """ @@ -347,7 +353,7 @@ class Test: safe_name = self.suite.name.replace(".","-") if safe_test_path: - class_name = safe_name + "." + "/".join(safe_test_path) + class_name = safe_name + "." + "/".join(safe_test_path) else: class_name = safe_name + "." + safe_name diff --git a/llvm/utils/lit/lit/TestRunner.py b/llvm/utils/lit/lit/TestRunner.py index 37b03cc19f8..e72be025308 100644 --- a/llvm/utils/lit/lit/TestRunner.py +++ b/llvm/utils/lit/lit/TestRunner.py @@ -123,7 +123,7 @@ class ShellCommandResult(object): self.exitCode = exitCode self.timeoutReached = timeoutReached self.outputFiles = list(outputFiles) - + def executeShCmd(cmd, shenv, results, timeout=0): """ Wrapper around _executeShCmd that handles @@ -501,7 +501,7 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper): data = None if data is not None: output_files.append((name, path, data)) - + results.append(ShellCommandResult( cmd.commands[i], out, err, res, timeoutHelper.timeoutReached(), output_files)) @@ -573,7 +573,7 @@ def executeScriptInternal(test, litConfig, tmpBase, commands, cwd): else: out += data out += "\n" - + if result.stdout.strip(): out += '# command output:\n%s\n' % (result.stdout,) if result.stderr.strip(): @@ -690,37 +690,28 @@ def parseIntegratedTestScriptCommands(source_path, keywords): finally: f.close() -def getTempPaths(test): - """Get the temporary location, this is always relative to the test suite - root, not test source root.""" - execpath = test.getExecPath() - execdir,execbase = os.path.split(execpath) - tmpDir = os.path.join(execdir, 'Output') - tmpBase = os.path.join(tmpDir, execbase) - return tmpDir, tmpBase - -def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False): +def getDefaultSubstitutions(test, normalize_slashes=False): sourcepath = test.getSourcePath() sourcedir = os.path.dirname(sourcepath) + tmpDir = test.getTempFileDir() + tmpPrefix = test.getTempFilePrefix() + baseName = test.getTestBaseName() # Normalize slashes, if requested. if normalize_slashes: sourcepath = sourcepath.replace('\\', '/') sourcedir = sourcedir.replace('\\', '/') tmpDir = tmpDir.replace('\\', '/') - tmpBase = tmpBase.replace('\\', '/') # We use #_MARKER_# to hide %% while we do the other substitutions. substitutions = [] substitutions.extend([('%%', '#_MARKER_#')]) substitutions.extend(test.config.substitutions) - tmpName = tmpBase + '.tmp' - baseName = os.path.basename(tmpBase) substitutions.extend([('%s', sourcepath), ('%S', sourcedir), ('%p', sourcedir), ('%{pathsep}', os.pathsep), - ('%t', tmpName), + ('%t', tmpPrefix), ('%basename_t', baseName), ('%T', tmpDir), ('#_MARKER_#', '%')]) @@ -730,7 +721,7 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False): ('%/s', sourcepath.replace('\\', '/')), ('%/S', sourcedir.replace('\\', '/')), ('%/p', sourcedir.replace('\\', '/')), - ('%/t', tmpBase.replace('\\', '/') + '.tmp'), + ('%/t', tmpPrefix.replace('\\', '/')), ('%/T', tmpDir.replace('\\', '/')), ]) @@ -740,7 +731,7 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False): ('%:s', re.sub(r'^(.):', r'\1', sourcepath)), ('%:S', re.sub(r'^(.):', r'\1', sourcedir)), ('%:p', re.sub(r'^(.):', r'\1', sourcedir)), - ('%:t', re.sub(r'^(.):', r'\1', tmpBase) + '.tmp'), + ('%:t', re.sub(r'^(.):', r'\1', tmpPrefix)), ('%:T', re.sub(r'^(.):', r'\1', tmpDir)), ]) else: @@ -748,7 +739,7 @@ def getDefaultSubstitutions(test, tmpDir, tmpBase, normalize_slashes=False): ('%:s', sourcepath), ('%:S', sourcedir), ('%:p', sourcedir), - ('%:t', tmpBase + '.tmp'), + ('%:t', tmpPrefix), ('%:T', tmpDir), ]) return substitutions @@ -779,7 +770,7 @@ class ParserKind(object): TAG: A keyword taking no value. Ex 'END.' COMMAND: A keyword taking a list of shell commands. Ex 'RUN:' LIST: A keyword taking a comma-separated list of values. - BOOLEAN_EXPR: A keyword taking a comma-separated list of + BOOLEAN_EXPR: A keyword taking a comma-separated list of boolean expressions. Ex 'XFAIL:' CUSTOM: A keyword with custom parsing semantics. """ @@ -951,14 +942,14 @@ def parseIntegratedTestScript(test, additional_parsers=[], IntegratedTestKeywordParser('REQUIRES:', ParserKind.BOOLEAN_EXPR, initial_value=test.requires), IntegratedTestKeywordParser('REQUIRES-ANY:', ParserKind.CUSTOM, - IntegratedTestKeywordParser._handleRequiresAny, - initial_value=test.requires), + IntegratedTestKeywordParser._handleRequiresAny, + initial_value=test.requires), IntegratedTestKeywordParser('UNSUPPORTED:', ParserKind.BOOLEAN_EXPR, initial_value=test.unsupported), IntegratedTestKeywordParser('END.', ParserKind.TAG) ] keyword_parsers = {p.keyword: p for p in builtin_parsers} - + # Install user-defined additional parsers. for parser in additional_parsers: if not isinstance(parser, IntegratedTestKeywordParser): @@ -968,7 +959,7 @@ def parseIntegratedTestScript(test, additional_parsers=[], raise ValueError("Parser for keyword '%s' already exists" % parser.keyword) keyword_parsers[parser.keyword] = parser - + # Collect the test lines from the script. sourcepath = test.getSourcePath() for line_number, command_type, ln in \ @@ -1014,12 +1005,8 @@ def parseIntegratedTestScript(test, additional_parsers=[], return script - def _runShTest(test, litConfig, useExternalSh, script, tmpBase): - # Create the output directory if it does not already exist. - lit.util.mkdir_p(os.path.dirname(tmpBase)) - - execdir = os.path.dirname(test.getExecPath()) + execdir = os.path.dirname(test.getTempFileDir()) if useExternalSh: res = executeScript(test, litConfig, tmpBase, script, execdir) else: @@ -1063,10 +1050,8 @@ def executeShTest(test, litConfig, useExternalSh, return script if litConfig.noExecute: return lit.Test.Result(Test.PASS) - - tmpDir, tmpBase = getTempPaths(test) substitutions = list(extra_substitutions) - substitutions += getDefaultSubstitutions(test, tmpDir, tmpBase, + substitutions += getDefaultSubstitutions(test, normalize_slashes=useExternalSh) script = applySubstitutions(script, substitutions) @@ -1075,7 +1060,8 @@ def executeShTest(test, litConfig, useExternalSh, if hasattr(test.config, 'test_retry_attempts'): attempts += test.config.test_retry_attempts for i in range(attempts): - res = _runShTest(test, litConfig, useExternalSh, script, tmpBase) + res = _runShTest(test, litConfig, useExternalSh, script, + test.getTempFilePrefix()) if res.code != Test.FAIL: break # If we had to run the test more than once, count it as a flaky pass. These diff --git a/llvm/utils/lit/lit/run.py b/llvm/utils/lit/lit/run.py index 1290c142c83..bdaf1415a1c 100644 --- a/llvm/utils/lit/lit/run.py +++ b/llvm/utils/lit/lit/run.py @@ -1,4 +1,5 @@ import os +import shutil import sys import threading import time @@ -74,6 +75,25 @@ class Run(object): if not self.tests or jobs == 0: return + # Create fresh output directories for each test we're going to run. + # This guarantees that test runs will not remnants of previous test + # runs' output. + clean_paths = set() + for test in self.tests: + clean_paths.add(os.path.normpath(test.getTempFileDir())) + clean_paths = list(clean_paths) + # Sort by number of path components, to ensure that parent directories + # get deleted and re-created before child directories. + clean_paths.sort(key=lambda x: len(x.split(os.sep))) + for base in clean_paths: + if os.path.exists(base): + if not os.path.islink(base) and os.path.isdir(base): + shutil.rmtree(base, True) + else: + os.unlink(os.path) + if not os.path.exists(base): + lit.util.mkdir_p(base) + # Set up semaphores to limit parallelism of certain classes of tests. # For example, some ASan tests require lots of virtual memory and run # faster with less parallelism on OS X. |