main.py revision 4ac723b53f2eb69e604891853ca87d1e2b3ee788
1#!/usr/bin/env python 2 3""" 4lit - LLVM Integrated Tester. 5 6See lit.pod for more information. 7""" 8 9from __future__ import absolute_import 10import math, os, platform, random, re, sys, time 11 12import lit.ProgressBar 13import lit.LitConfig 14import lit.Test 15import lit.run 16import lit.util 17import lit.discovery 18 19class TestingProgressDisplay(object): 20 def __init__(self, opts, numTests, progressBar=None): 21 self.opts = opts 22 self.numTests = numTests 23 self.current = None 24 self.progressBar = progressBar 25 self.completed = 0 26 27 def finish(self): 28 if self.progressBar: 29 self.progressBar.clear() 30 elif self.opts.quiet: 31 pass 32 elif self.opts.succinct: 33 sys.stdout.write('\n') 34 35 def update(self, test): 36 self.completed += 1 37 if self.progressBar: 38 self.progressBar.update(float(self.completed)/self.numTests, 39 test.getFullName()) 40 41 if not test.result.code.isFailure and \ 42 (self.opts.quiet or self.opts.succinct): 43 return 44 45 if self.progressBar: 46 self.progressBar.clear() 47 48 print('%s: %s (%d of %d)' % (test.result.code.name, test.getFullName(), 49 self.completed, self.numTests)) 50 51 if test.result.code.isFailure and self.opts.showOutput: 52 print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(), 53 '*'*20)) 54 print(test.result.output) 55 print("*" * 20) 56 57 sys.stdout.flush() 58 59def main(builtinParameters = {}): 60 # Bump the GIL check interval, its more important to get any one thread to a 61 # blocking operation (hopefully exec) than to try and unblock other threads. 62 # 63 # FIXME: This is a hack. 64 sys.setcheckinterval(1000) 65 66 global options 67 from optparse import OptionParser, OptionGroup 68 parser = OptionParser("usage: %prog [options] {file-or-path}") 69 70 parser.add_option("-j", "--threads", dest="numThreads", metavar="N", 71 help="Number of testing threads", 72 type=int, action="store", default=None) 73 parser.add_option("", "--config-prefix", dest="configPrefix", 74 metavar="NAME", help="Prefix for 'lit' config files", 75 action="store", default=None) 76 parser.add_option("", "--param", dest="userParameters", 77 metavar="NAME=VAL", 78 help="Add 'NAME' = 'VAL' to the user defined parameters", 79 type=str, action="append", default=[]) 80 81 group = OptionGroup(parser, "Output Format") 82 # FIXME: I find these names very confusing, although I like the 83 # functionality. 84 group.add_option("-q", "--quiet", dest="quiet", 85 help="Suppress no error output", 86 action="store_true", default=False) 87 group.add_option("-s", "--succinct", dest="succinct", 88 help="Reduce amount of output", 89 action="store_true", default=False) 90 group.add_option("-v", "--verbose", dest="showOutput", 91 help="Show all test output", 92 action="store_true", default=False) 93 group.add_option("", "--no-progress-bar", dest="useProgressBar", 94 help="Do not use curses based progress bar", 95 action="store_false", default=True) 96 parser.add_option_group(group) 97 98 group = OptionGroup(parser, "Test Execution") 99 group.add_option("", "--path", dest="path", 100 help="Additional paths to add to testing environment", 101 action="append", type=str, default=[]) 102 group.add_option("", "--vg", dest="useValgrind", 103 help="Run tests under valgrind", 104 action="store_true", default=False) 105 group.add_option("", "--vg-leak", dest="valgrindLeakCheck", 106 help="Check for memory leaks under valgrind", 107 action="store_true", default=False) 108 group.add_option("", "--vg-arg", dest="valgrindArgs", metavar="ARG", 109 help="Specify an extra argument for valgrind", 110 type=str, action="append", default=[]) 111 group.add_option("", "--time-tests", dest="timeTests", 112 help="Track elapsed wall time for each test", 113 action="store_true", default=False) 114 group.add_option("", "--no-execute", dest="noExecute", 115 help="Don't execute any tests (assume PASS)", 116 action="store_true", default=False) 117 parser.add_option_group(group) 118 119 group = OptionGroup(parser, "Test Selection") 120 group.add_option("", "--max-tests", dest="maxTests", metavar="N", 121 help="Maximum number of tests to run", 122 action="store", type=int, default=None) 123 group.add_option("", "--max-time", dest="maxTime", metavar="N", 124 help="Maximum time to spend testing (in seconds)", 125 action="store", type=float, default=None) 126 group.add_option("", "--shuffle", dest="shuffle", 127 help="Run tests in random order", 128 action="store_true", default=False) 129 group.add_option("", "--filter", dest="filter", metavar="REGEX", 130 help=("Only run tests with paths matching the given " 131 "regular expression"), 132 action="store", default=None) 133 parser.add_option_group(group) 134 135 group = OptionGroup(parser, "Debug and Experimental Options") 136 group.add_option("", "--debug", dest="debug", 137 help="Enable debugging (for 'lit' development)", 138 action="store_true", default=False) 139 group.add_option("", "--show-suites", dest="showSuites", 140 help="Show discovered test suites", 141 action="store_true", default=False) 142 group.add_option("", "--show-tests", dest="showTests", 143 help="Show all discovered tests", 144 action="store_true", default=False) 145 group.add_option("", "--use-processes", dest="useProcesses", 146 help="Run tests in parallel with processes (not threads)", 147 action="store_true", default=False) 148 group.add_option("", "--use-threads", dest="useProcesses", 149 help="Run tests in parallel with threads (not processes)", 150 action="store_false", default=False) 151 parser.add_option_group(group) 152 153 (opts, args) = parser.parse_args() 154 155 if not args: 156 parser.error('No inputs specified') 157 158 if opts.numThreads is None: 159# Python <2.5 has a race condition causing lit to always fail with numThreads>1 160# http://bugs.python.org/issue1731717 161# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple 162# threads by default there. 163 if sys.hexversion >= 0x2050200: 164 opts.numThreads = lit.util.detectCPUs() 165 else: 166 opts.numThreads = 1 167 168 inputs = args 169 170 # Create the user defined parameters. 171 userParams = dict(builtinParameters) 172 for entry in opts.userParameters: 173 if '=' not in entry: 174 name,val = entry,'' 175 else: 176 name,val = entry.split('=', 1) 177 userParams[name] = val 178 179 # Create the global config object. 180 litConfig = lit.LitConfig.LitConfig( 181 progname = os.path.basename(sys.argv[0]), 182 path = opts.path, 183 quiet = opts.quiet, 184 useValgrind = opts.useValgrind, 185 valgrindLeakCheck = opts.valgrindLeakCheck, 186 valgrindArgs = opts.valgrindArgs, 187 noExecute = opts.noExecute, 188 debug = opts.debug, 189 isWindows = (platform.system()=='Windows'), 190 params = userParams, 191 config_prefix = opts.configPrefix) 192 193 # Perform test discovery. 194 run = lit.run.Run(litConfig, 195 lit.discovery.find_tests_for_inputs(litConfig, inputs)) 196 197 if opts.showSuites or opts.showTests: 198 # Aggregate the tests by suite. 199 suitesAndTests = {} 200 for t in run.tests: 201 if t.suite not in suitesAndTests: 202 suitesAndTests[t.suite] = [] 203 suitesAndTests[t.suite].append(t) 204 suitesAndTests = list(suitesAndTests.items()) 205 suitesAndTests.sort(key = lambda item: item[0].name) 206 207 # Show the suites, if requested. 208 if opts.showSuites: 209 print('-- Test Suites --') 210 for ts,ts_tests in suitesAndTests: 211 print(' %s - %d tests' %(ts.name, len(ts_tests))) 212 print(' Source Root: %s' % ts.source_root) 213 print(' Exec Root : %s' % ts.exec_root) 214 215 # Show the tests, if requested. 216 if opts.showTests: 217 print('-- Available Tests --') 218 for ts,ts_tests in suitesAndTests: 219 ts_tests.sort(key = lambda test: test.path_in_suite) 220 for test in ts_tests: 221 print(' %s' % (test.getFullName(),)) 222 223 # Exit. 224 sys.exit(0) 225 226 # Select and order the tests. 227 numTotalTests = len(run.tests) 228 229 # First, select based on the filter expression if given. 230 if opts.filter: 231 try: 232 rex = re.compile(opts.filter) 233 except: 234 parser.error("invalid regular expression for --filter: %r" % ( 235 opts.filter)) 236 run.tests = [t for t in run.tests 237 if rex.search(t.getFullName())] 238 239 # Then select the order. 240 if opts.shuffle: 241 random.shuffle(run.tests) 242 else: 243 run.tests.sort(key = lambda t: t.getFullName()) 244 245 # Finally limit the number of tests, if desired. 246 if opts.maxTests is not None: 247 run.tests = run.tests[:opts.maxTests] 248 249 # Don't create more threads than tests. 250 opts.numThreads = min(len(run.tests), opts.numThreads) 251 252 extra = '' 253 if len(run.tests) != numTotalTests: 254 extra = ' of %d' % numTotalTests 255 header = '-- Testing: %d%s tests, %d threads --'%(len(run.tests), extra, 256 opts.numThreads) 257 258 progressBar = None 259 if not opts.quiet: 260 if opts.succinct and opts.useProgressBar: 261 try: 262 tc = lit.ProgressBar.TerminalController() 263 progressBar = lit.ProgressBar.ProgressBar(tc, header) 264 except ValueError: 265 print(header) 266 progressBar = lit.ProgressBar.SimpleProgressBar('Testing: ') 267 else: 268 print(header) 269 270 startTime = time.time() 271 display = TestingProgressDisplay(opts, len(run.tests), progressBar) 272 try: 273 run.execute_tests(display, opts.numThreads, opts.maxTime, 274 opts.useProcesses) 275 except KeyboardInterrupt: 276 sys.exit(2) 277 display.finish() 278 279 if not opts.quiet: 280 print('Testing Time: %.2fs'%(time.time() - startTime)) 281 282 # List test results organized by kind. 283 hasFailures = False 284 byCode = {} 285 for test in run.tests: 286 if test.result.code not in byCode: 287 byCode[test.result.code] = [] 288 byCode[test.result.code].append(test) 289 if test.result.code.isFailure: 290 hasFailures = True 291 292 # Print each test in any of the failing groups. 293 for title,code in (('Unexpected Passing Tests', lit.Test.XPASS), 294 ('Failing Tests', lit.Test.FAIL), 295 ('Unresolved Tests', lit.Test.UNRESOLVED)): 296 elts = byCode.get(code) 297 if not elts: 298 continue 299 print('*'*20) 300 print('%s (%d):' % (title, len(elts))) 301 for test in elts: 302 print(' %s' % test.getFullName()) 303 sys.stdout.write('\n') 304 305 if opts.timeTests and run.tests: 306 # Order by time. 307 test_times = [(test.getFullName(), test.result.elapsed) 308 for test in run.tests] 309 lit.util.printHistogram(test_times, title='Tests') 310 311 for name,code in (('Expected Passes ', lit.Test.PASS), 312 ('Expected Failures ', lit.Test.XFAIL), 313 ('Unsupported Tests ', lit.Test.UNSUPPORTED), 314 ('Unresolved Tests ', lit.Test.UNRESOLVED), 315 ('Unexpected Passes ', lit.Test.XPASS), 316 ('Unexpected Failures', lit.Test.FAIL),): 317 if opts.quiet and not code.isFailure: 318 continue 319 N = len(byCode.get(code,[])) 320 if N: 321 print(' %s: %d' % (name,N)) 322 323 # If we encountered any additional errors, exit abnormally. 324 if litConfig.numErrors: 325 sys.stderr.write('\n%d error(s), exiting.\n' % litConfig.numErrors) 326 sys.exit(2) 327 328 # Warn about warnings. 329 if litConfig.numWarnings: 330 sys.stderr.write('\n%d warning(s) in tests.\n' % litConfig.numWarnings) 331 332 if hasFailures: 333 sys.exit(1) 334 sys.exit(0) 335 336if __name__=='__main__': 337 main() 338