Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Unified Diff: third_party/lit/lit/main.py

Issue 1663053003: [fusl] Add llvm's lit tool to third_party (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: move down a dir Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/lit/lit/formats/shtest.py ('k') | third_party/lit/lit/run.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/lit/lit/main.py
diff --git a/third_party/lit/lit/main.py b/third_party/lit/lit/main.py
new file mode 100755
index 0000000000000000000000000000000000000000..630cb54f96d5f162f5187921e1ed5547f1d98d5f
--- /dev/null
+++ b/third_party/lit/lit/main.py
@@ -0,0 +1,474 @@
+#!/usr/bin/env python
+
+"""
+lit - LLVM Integrated Tester.
+
+See lit.pod for more information.
+"""
+
+from __future__ import absolute_import
+import math, os, platform, random, re, sys, time
+
+import lit.ProgressBar
+import lit.LitConfig
+import lit.Test
+import lit.run
+import lit.util
+import lit.discovery
+
+class TestingProgressDisplay(object):
+ def __init__(self, opts, numTests, progressBar=None):
+ self.opts = opts
+ self.numTests = numTests
+ self.current = None
+ self.progressBar = progressBar
+ self.completed = 0
+
+ def finish(self):
+ if self.progressBar:
+ self.progressBar.clear()
+ elif self.opts.quiet:
+ pass
+ elif self.opts.succinct:
+ sys.stdout.write('\n')
+
+ 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())
+
+ shouldShow = test.result.code.isFailure or \
+ (not self.opts.quiet and not self.opts.succinct)
+ if not shouldShow:
+ return
+
+ if self.progressBar:
+ self.progressBar.clear()
+
+ # Show the test result line.
+ test_name = test.getFullName()
+ print('%s: %s (%d of %d)' % (test.result.code.name, test_name,
+ self.completed, self.numTests))
+
+ # Show the test failure output, if requested.
+ if test.result.code.isFailure and self.opts.showOutput:
+ print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(),
+ '*'*20))
+ print(test.result.output)
+ print("*" * 20)
+
+ # Report test metrics, if present.
+ if test.result.metrics:
+ print("%s TEST '%s' RESULTS %s" % ('*'*10, test.getFullName(),
+ '*'*10))
+ items = sorted(test.result.metrics.items())
+ for metric_name, value in items:
+ print('%s: %s ' % (metric_name, value.format()))
+ print("*" * 10)
+
+ # Ensure the output is flushed.
+ sys.stdout.flush()
+
+def write_test_results(run, lit_config, testing_time, output_path):
+ try:
+ import json
+ except ImportError:
+ lit_config.fatal('test output unsupported with Python 2.5')
+
+ # Construct the data we will write.
+ data = {}
+ # Encode the current lit version as a schema version.
+ data['__version__'] = lit.__versioninfo__
+ data['elapsed'] = testing_time
+ # FIXME: Record some information on the lit configuration used?
+ # FIXME: Record information from the individual test suites?
+
+ # Encode the tests.
+ data['tests'] = tests_data = []
+ for test in run.tests:
+ test_data = {
+ 'name' : test.getFullName(),
+ 'code' : test.result.code.name,
+ 'output' : test.result.output,
+ 'elapsed' : test.result.elapsed }
+
+ # Add test metrics, if present.
+ if test.result.metrics:
+ test_data['metrics'] = metrics_data = {}
+ for key, value in test.result.metrics.items():
+ metrics_data[key] = value.todata()
+
+ tests_data.append(test_data)
+
+ # Write the output.
+ f = open(output_path, 'w')
+ try:
+ json.dump(data, f, indent=2, sort_keys=True)
+ f.write('\n')
+ 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):
+ def sortIndex(test):
+ fname = test.getFilePath()
+ try:
+ return -os.path.getmtime(fname)
+ except:
+ return 0
+ run.tests.sort(key = lambda t: sortIndex(t))
+
+def main(builtinParameters = {}):
+ # Use processes by default on Unix platforms.
+ isWindows = platform.system() == 'Windows'
+ useProcessesIsDefault = not isWindows
+
+ global options
+ from optparse import OptionParser, OptionGroup
+ parser = OptionParser("usage: %prog [options] {file-or-path}")
+
+ parser.add_option("", "--version", dest="show_version",
+ help="Show version and exit",
+ action="store_true", default=False)
+ parser.add_option("-j", "--threads", dest="numThreads", metavar="N",
+ help="Number of testing threads",
+ type=int, action="store", default=None)
+ parser.add_option("", "--config-prefix", dest="configPrefix",
+ metavar="NAME", help="Prefix for 'lit' config files",
+ action="store", default=None)
+ parser.add_option("-D", "--param", dest="userParameters",
+ metavar="NAME=VAL",
+ help="Add 'NAME' = 'VAL' to the user defined parameters",
+ type=str, action="append", default=[])
+
+ group = OptionGroup(parser, "Output Format")
+ # FIXME: I find these names very confusing, although I like the
+ # functionality.
+ group.add_option("-q", "--quiet", dest="quiet",
+ help="Suppress no error output",
+ action="store_true", default=False)
+ group.add_option("-s", "--succinct", dest="succinct",
+ help="Reduce amount of output",
+ action="store_true", default=False)
+ group.add_option("-v", "--verbose", dest="showOutput",
+ help="Show all test output",
+ action="store_true", default=False)
+ group.add_option("-o", "--output", dest="output_path",
+ help="Write test results to the provided path",
+ action="store", type=str, metavar="PATH")
+ group.add_option("", "--no-progress-bar", dest="useProgressBar",
+ help="Do not use curses based progress bar",
+ action="store_false", default=True)
+ group.add_option("", "--show-unsupported", dest="show_unsupported",
+ help="Show unsupported tests",
+ action="store_true", default=False)
+ group.add_option("", "--show-xfail", dest="show_xfail",
+ help="Show tests that were expected to fail",
+ action="store_true", default=False)
+ parser.add_option_group(group)
+
+ group = OptionGroup(parser, "Test Execution")
+ group.add_option("", "--path", dest="path",
+ help="Additional paths to add to testing environment",
+ action="append", type=str, default=[])
+ group.add_option("", "--vg", dest="useValgrind",
+ help="Run tests under valgrind",
+ action="store_true", default=False)
+ group.add_option("", "--vg-leak", dest="valgrindLeakCheck",
+ help="Check for memory leaks under valgrind",
+ action="store_true", default=False)
+ group.add_option("", "--vg-arg", dest="valgrindArgs", metavar="ARG",
+ help="Specify an extra argument for valgrind",
+ type=str, action="append", default=[])
+ group.add_option("", "--time-tests", dest="timeTests",
+ help="Track elapsed wall time for each test",
+ action="store_true", default=False)
+ group.add_option("", "--no-execute", dest="noExecute",
+ help="Don't execute any tests (assume PASS)",
+ action="store_true", default=False)
+ group.add_option("", "--xunit-xml-output", dest="xunit_output_file",
+ help=("Write XUnit-compatible XML test reports to the"
+ " specified file"), default=None)
+ parser.add_option_group(group)
+
+ group = OptionGroup(parser, "Test Selection")
+ group.add_option("", "--max-tests", dest="maxTests", metavar="N",
+ help="Maximum number of tests to run",
+ action="store", type=int, default=None)
+ group.add_option("", "--max-time", dest="maxTime", metavar="N",
+ help="Maximum time to spend testing (in seconds)",
+ action="store", type=float, default=None)
+ 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"),
+ action="store", default=None)
+ parser.add_option_group(group)
+
+ group = OptionGroup(parser, "Debug and Experimental Options")
+ group.add_option("", "--debug", dest="debug",
+ help="Enable debugging (for 'lit' development)",
+ action="store_true", default=False)
+ group.add_option("", "--show-suites", dest="showSuites",
+ help="Show discovered test suites",
+ action="store_true", default=False)
+ group.add_option("", "--show-tests", dest="showTests",
+ help="Show all discovered tests",
+ action="store_true", default=False)
+ group.add_option("", "--use-processes", dest="useProcesses",
+ help="Run tests in parallel with processes (not threads)",
+ action="store_true", default=useProcessesIsDefault)
+ group.add_option("", "--use-threads", dest="useProcesses",
+ help="Run tests in parallel with threads (not processes)",
+ action="store_false", default=useProcessesIsDefault)
+ parser.add_option_group(group)
+
+ (opts, args) = parser.parse_args()
+
+ if opts.show_version:
+ print("lit %s" % (lit.__version__,))
+ return
+
+ if not args:
+ parser.error('No inputs specified')
+
+ if opts.numThreads is None:
+# Python <2.5 has a race condition causing lit to always fail with numThreads>1
+# http://bugs.python.org/issue1731717
+# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple
+# threads by default there.
+ if sys.hexversion >= 0x2050200:
+ opts.numThreads = lit.util.detectCPUs()
+ else:
+ opts.numThreads = 1
+
+ inputs = args
+
+ # Create the user defined parameters.
+ userParams = dict(builtinParameters)
+ for entry in opts.userParameters:
+ if '=' not in entry:
+ name,val = entry,''
+ else:
+ name,val = entry.split('=', 1)
+ userParams[name] = val
+
+ # Create the global config object.
+ litConfig = lit.LitConfig.LitConfig(
+ progname = os.path.basename(sys.argv[0]),
+ path = opts.path,
+ quiet = opts.quiet,
+ useValgrind = opts.useValgrind,
+ valgrindLeakCheck = opts.valgrindLeakCheck,
+ valgrindArgs = opts.valgrindArgs,
+ noExecute = opts.noExecute,
+ debug = opts.debug,
+ isWindows = isWindows,
+ params = userParams,
+ config_prefix = opts.configPrefix)
+
+ # Perform test discovery.
+ run = lit.run.Run(litConfig,
+ lit.discovery.find_tests_for_inputs(litConfig, inputs))
+
+ if opts.showSuites or opts.showTests:
+ # Aggregate the tests by suite.
+ suitesAndTests = {}
+ for result_test in run.tests:
+ if result_test.suite not in suitesAndTests:
+ suitesAndTests[result_test.suite] = []
+ suitesAndTests[result_test.suite].append(result_test)
+ suitesAndTests = list(suitesAndTests.items())
+ suitesAndTests.sort(key = lambda item: item[0].name)
+
+ # Show the suites, if requested.
+ if opts.showSuites:
+ print('-- Test Suites --')
+ for ts,ts_tests in suitesAndTests:
+ print(' %s - %d tests' %(ts.name, len(ts_tests)))
+ print(' Source Root: %s' % ts.source_root)
+ print(' Exec Root : %s' % ts.exec_root)
+
+ # Show the tests, if requested.
+ if opts.showTests:
+ print('-- Available Tests --')
+ for ts,ts_tests in suitesAndTests:
+ ts_tests.sort(key = lambda test: test.path_in_suite)
+ for test in ts_tests:
+ print(' %s' % (test.getFullName(),))
+
+ # Exit.
+ sys.exit(0)
+
+ # Select and order the tests.
+ numTotalTests = len(run.tests)
+
+ # First, select based on the filter expression if given.
+ if opts.filter:
+ try:
+ rex = re.compile(opts.filter)
+ except:
+ parser.error("invalid regular expression for --filter: %r" % (
+ opts.filter))
+ run.tests = [result_test for result_test in run.tests
+ if rex.search(result_test.getFullName())]
+
+ # Then select the order.
+ if opts.shuffle:
+ random.shuffle(run.tests)
+ elif opts.incremental:
+ sort_by_incremental_cache(run)
+ else:
+ run.tests.sort(key = lambda result_test: result_test.getFullName())
+
+ # Finally limit the number of tests, if desired.
+ if opts.maxTests is not None:
+ run.tests = run.tests[:opts.maxTests]
+
+ # Don't create more threads than tests.
+ opts.numThreads = min(len(run.tests), opts.numThreads)
+
+ extra = ''
+ if len(run.tests) != numTotalTests:
+ extra = ' of %d' % numTotalTests
+ header = '-- Testing: %d%s tests, %d threads --'%(len(run.tests), extra,
+ opts.numThreads)
+
+ progressBar = None
+ if not opts.quiet:
+ if opts.succinct and opts.useProgressBar:
+ try:
+ tc = lit.ProgressBar.TerminalController()
+ progressBar = lit.ProgressBar.ProgressBar(tc, header)
+ except ValueError:
+ print(header)
+ progressBar = lit.ProgressBar.SimpleProgressBar('Testing: ')
+ else:
+ print(header)
+
+ startTime = time.time()
+ display = TestingProgressDisplay(opts, len(run.tests), progressBar)
+ try:
+ run.execute_tests(display, opts.numThreads, opts.maxTime,
+ opts.useProcesses)
+ except KeyboardInterrupt:
+ sys.exit(2)
+ display.finish()
+
+ testing_time = time.time() - startTime
+ if not opts.quiet:
+ print('Testing Time: %.2fs' % (testing_time,))
+
+ # Write out the test data, if requested.
+ if opts.output_path is not None:
+ write_test_results(run, litConfig, testing_time, opts.output_path)
+
+ # List test results organized by kind.
+ hasFailures = False
+ byCode = {}
+ for test in run.tests:
+ if test.result.code not in byCode:
+ byCode[test.result.code] = []
+ byCode[test.result.code].append(test)
+ if test.result.code.isFailure:
+ hasFailures = True
+
+ # Print each test in any of the failing groups.
+ for title,code in (('Unexpected Passing Tests', lit.Test.XPASS),
+ ('Failing Tests', lit.Test.FAIL),
+ ('Unresolved Tests', lit.Test.UNRESOLVED),
+ ('Unsupported Tests', lit.Test.UNSUPPORTED),
+ ('Expected Failing Tests', lit.Test.XFAIL)):
+ if (lit.Test.XFAIL == code and not opts.show_xfail) or \
+ (lit.Test.UNSUPPORTED == code and not opts.show_unsupported):
+ continue
+ elts = byCode.get(code)
+ if not elts:
+ continue
+ print('*'*20)
+ print('%s (%d):' % (title, len(elts)))
+ for test in elts:
+ print(' %s' % test.getFullName())
+ sys.stdout.write('\n')
+
+ if opts.timeTests and run.tests:
+ # Order by time.
+ test_times = [(test.getFullName(), test.result.elapsed)
+ for test in run.tests]
+ lit.util.printHistogram(test_times, title='Tests')
+
+ for name,code in (('Expected Passes ', lit.Test.PASS),
+ ('Passes With Retry ', lit.Test.FLAKYPASS),
+ ('Expected Failures ', lit.Test.XFAIL),
+ ('Unsupported Tests ', lit.Test.UNSUPPORTED),
+ ('Unresolved Tests ', lit.Test.UNRESOLVED),
+ ('Unexpected Passes ', lit.Test.XPASS),
+ ('Unexpected Failures', lit.Test.FAIL)):
+ if opts.quiet and not code.isFailure:
+ continue
+ N = len(byCode.get(code,[]))
+ if N:
+ print(' %s: %d' % (name,N))
+
+ if opts.xunit_output_file:
+ # Collect the tests, indexed by test suite
+ by_suite = {}
+ for result_test in run.tests:
+ suite = result_test.suite.config.name
+ if suite not in by_suite:
+ by_suite[suite] = {
+ 'passes' : 0,
+ 'failures' : 0,
+ 'tests' : [] }
+ by_suite[suite]['tests'].append(result_test)
+ if result_test.result.code.isFailure:
+ by_suite[suite]['failures'] += 1
+ else:
+ by_suite[suite]['passes'] += 1
+ xunit_output_file = open(opts.xunit_output_file, "w")
+ xunit_output_file.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n")
+ xunit_output_file.write("<testsuites>\n")
+ for suite_name, suite in by_suite.items():
+ safe_suite_name = suite_name.replace(".", "-")
+ xunit_output_file.write("<testsuite name='" + safe_suite_name + "'")
+ xunit_output_file.write(" tests='" + str(suite['passes'] +
+ suite['failures']) + "'")
+ xunit_output_file.write(" failures='" + str(suite['failures']) +
+ "'>\n")
+ for result_test in suite['tests']:
+ xunit_output_file.write(result_test.getJUnitXML() + "\n")
+ xunit_output_file.write("</testsuite>\n")
+ xunit_output_file.write("</testsuites>")
+ xunit_output_file.close()
+
+ # If we encountered any additional errors, exit abnormally.
+ if litConfig.numErrors:
+ sys.stderr.write('\n%d error(s), exiting.\n' % litConfig.numErrors)
+ sys.exit(2)
+
+ # Warn about warnings.
+ if litConfig.numWarnings:
+ sys.stderr.write('\n%d warning(s) in tests.\n' % litConfig.numWarnings)
+
+ if hasFailures:
+ sys.exit(1)
+ sys.exit(0)
+
+if __name__=='__main__':
+ main()
« no previous file with comments | « third_party/lit/lit/formats/shtest.py ('k') | third_party/lit/lit/run.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698