diff --git a/llvm/utils/lit/lit/Test.py b/llvm/utils/lit/lit/Test.py index 000bcf8fc38fe..c809783dae7e6 100644 --- a/llvm/utils/lit/lit/Test.py +++ b/llvm/utils/lit/lit/Test.py @@ -230,6 +230,20 @@ def __init__(self, suite, path_in_suite, config, file_path = None): def setResult(self, result): assert self.result is None, "result already set" assert isinstance(result, Result), "unexpected result type" + try: + expected_to_fail = self.isExpectedToFail() + except ValueError as err: + # Syntax error in an XFAIL line. + result.code = UNRESOLVED + result.output = str(err) + else: + if expected_to_fail: + # pass -> unexpected pass + if result.code is PASS: + result.code = XPASS + # fail -> expected fail + elif result.code is FAIL: + result.code = XFAIL self.result = result def isFailure(self): diff --git a/llvm/utils/lit/lit/run.py b/llvm/utils/lit/lit/run.py index 65495ed9dd352..e15eb38cb076e 100644 --- a/llvm/utils/lit/lit/run.py +++ b/llvm/utils/lit/lit/run.py @@ -67,15 +67,13 @@ def execute(self): # TODO(yln): as the comment says.. this is racing with the main thread waiting # for results - def _process_result(self, test, result): + def _process_completed(self, test): # Don't add any more test results after we've hit the maximum failure # count. Otherwise we're racing with the main thread, which is going # to terminate the process pool soon. if self.hit_max_failures: return - test.setResult(result) - # Use test.isFailure() for correct XFAIL and XPASS handling if test.isFailure(): self.failure_count += 1 @@ -93,7 +91,8 @@ def _execute(self, deadline): # TODO(yln): ignores deadline for test in self.tests: result = lit.worker._execute(test, self.lit_config) - self._process_result(test, result) + test.setResult(result) + self._process_completed(test) if self.hit_max_failures: break @@ -121,10 +120,14 @@ def _execute(self, deadline): self._install_win32_signal_handler(pool) + def process_completed(test, idx): + self.tests[idx] = test + self._process_completed(test) + async_results = [ pool.apply_async(lit.worker.execute, args=[test], - callback=lambda r, t=test: self._process_result(t, r)) - for test in self.tests] + callback=lambda t, i=idx: process_completed(t, i)) + for idx, test in enumerate(self.tests)] pool.close() for ar in async_results: diff --git a/llvm/utils/lit/lit/worker.py b/llvm/utils/lit/lit/worker.py index 02fcc20caaf20..d4364c3dcca41 100644 --- a/llvm/utils/lit/lit/worker.py +++ b/llvm/utils/lit/lit/worker.py @@ -11,9 +11,11 @@ import lit.Test import lit.util + _lit_config = None _parallelism_semaphores = None + def initialize(lit_config, parallelism_semaphores): """Copy data shared by all test executions into worker processes""" global _lit_config @@ -21,6 +23,7 @@ def initialize(lit_config, parallelism_semaphores): _lit_config = lit_config _parallelism_semaphores = parallelism_semaphores + def execute(test): """Run one test in a multiprocessing.Pool @@ -31,14 +34,17 @@ def execute(test): to copy. """ try: - return _execute_in_parallelism_group(test, _lit_config, - _parallelism_semaphores) + result = _execute_in_parallelism_group(test, _lit_config, + _parallelism_semaphores) + test.setResult(result) + return test except KeyboardInterrupt: # If a worker process gets an interrupt, abort it immediately. lit.util.abort_now() except: traceback.print_exc() + def _execute_in_parallelism_group(test, lit_config, parallelism_semaphores): pg = test.config.parallelism_group if callable(pg): @@ -56,39 +62,16 @@ def _execute_in_parallelism_group(test, lit_config, parallelism_semaphores): def _execute(test, lit_config): - """Execute one test""" start = time.time() result = _execute_test_handle_errors(test, lit_config) - end = time.time() - - result.elapsed = end - start - resolve_result_code(result, test) - + result.elapsed = time.time() - start return result -# TODO(yln): is this the right place to deal with this? -# isExpectedToFail() only works after the test has been executed. -def resolve_result_code(result, test): - try: - expected_to_fail = test.isExpectedToFail() - except ValueError as e: - # Syntax error in an XFAIL line. - result.code = lit.Test.UNRESOLVED - result.output = str(e) - else: - if expected_to_fail: - # pass -> unexpected pass - if result.code is lit.Test.PASS: - result.code = lit.Test.XPASS - # fail -> expected fail - if result.code is lit.Test.FAIL: - result.code = lit.Test.XFAIL - - def _execute_test_handle_errors(test, lit_config): try: - return _adapt_result(test.config.test_format.execute(test, lit_config)) + result = test.config.test_format.execute(test, lit_config) + return _adapt_result(result) except KeyboardInterrupt: raise except: