From 9ad6e339c3235401eeeed9c3ec982ee1b02901f2 Mon Sep 17 00:00:00 2001 From: Alp Toker Date: Sun, 29 Dec 2013 05:09:05 +0000 Subject: lit: Incremental test scheduling Add option -i to prioritize test runs by source file modification time and previous failure state. This optimal scheduling reduces typical test-and-fix iteration times to a matter of seconds by rapidly answering the questions: 1) Did my recent change fix tests that were previously failing? 2) Do the tests I just wrote / modified still work? The current implementation requires write permissions to the source tree because it uses mtimes to track failures. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198150 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/lit/lit/Test.py | 8 +++++++- utils/lit/lit/formats/googletest.py | 2 +- utils/lit/lit/main.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) (limited to 'utils/lit/lit') diff --git a/utils/lit/lit/Test.py b/utils/lit/lit/Test.py index b4988f530d..e51bf12977 100644 --- a/utils/lit/lit/Test.py +++ b/utils/lit/lit/Test.py @@ -128,10 +128,11 @@ class TestSuite: class Test: """Test - Information on a single test instance.""" - def __init__(self, suite, path_in_suite, config): + def __init__(self, suite, path_in_suite, config, file_path = None): self.suite = suite self.path_in_suite = path_in_suite self.config = config + self.file_path = file_path # A list of conditions under which this test is expected to fail. These # can optionally be provided by test format handlers, and will be # honored when the test result is supplied. @@ -157,6 +158,11 @@ class Test: def getFullName(self): return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite) + def getFilePath(self): + if self.file_path: + return self.file_path + return self.getSourcePath() + def getSourcePath(self): return self.suite.getSourcePath(self.path_in_suite) diff --git a/utils/lit/lit/formats/googletest.py b/utils/lit/lit/formats/googletest.py index b77e184d2f..3d14b729ed 100644 --- a/utils/lit/lit/formats/googletest.py +++ b/utils/lit/lit/formats/googletest.py @@ -66,7 +66,7 @@ class GoogleTest(TestFormat): # Discover the tests in this executable. for testname in self.getGTestTests(execpath, litConfig, localConfig): testPath = path_in_suite + (basename, testname) - yield lit.Test.Test(testSuite, testPath, localConfig) + yield lit.Test.Test(testSuite, testPath, localConfig, file_path=execpath) def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, localConfig): diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py index 6f672a01eb..3c49e85406 100755 --- a/utils/lit/lit/main.py +++ b/utils/lit/lit/main.py @@ -34,6 +34,10 @@ class TestingProgressDisplay(object): def update(self, test): self.completed += 1 + + if self.opts.incremental: + update_incremental_cache(test) + if self.progressBar: self.progressBar.update(float(self.completed)/self.numTests, test.getFullName()) @@ -108,6 +112,24 @@ def write_test_results(run, lit_config, testing_time, output_path): finally: f.close() +def update_incremental_cache(test): + if not test.result.code.isFailure: + return + fname = test.getFilePath() + os.utime(fname, None) + +def sort_by_incremental_cache(run, litConfig): + def sortIndex(test): + index = 0 + fname = test.getFilePath() + try: + index = -os.path.getmtime(fname) + except os.error as e: + if litConfig.debug: + litConfig.note(e) + return index + run.tests.sort(key = lambda t: sortIndex(t)) + def main(builtinParameters = {}): # Use processes by default on Unix platforms. isWindows = platform.system() == 'Windows' @@ -179,6 +201,10 @@ def main(builtinParameters = {}): group.add_option("", "--shuffle", dest="shuffle", help="Run tests in random order", action="store_true", default=False) + group.add_option("-i", "--incremental", dest="incremental", + help="Run modified and failing tests first (updates " + "mtimes)", + action="store_true", default=False) group.add_option("", "--filter", dest="filter", metavar="REGEX", help=("Only run tests with paths matching the given " "regular expression"), @@ -292,6 +318,8 @@ def main(builtinParameters = {}): # Then select the order. if opts.shuffle: random.shuffle(run.tests) + elif opts.incremental: + sort_by_incremental_cache(run, litConfig) else: run.tests.sort(key = lambda t: t.getFullName()) -- cgit v1.2.3