comparison tests/run-tests.py @ 27396:64c584070fc7

run-tests: show scheduling with --showchannels This gives one line of output per second with one column per -j level that allows analyzing test scheduling problems. First 24 seconds of output at -j 30 looks like this: 0 . 1 = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = s. 2 c c o c r l g r s s = c p = c h c a h c g c h c b c c l l c ss 3 h o b o e a e u u u c o a h o e o c g o l h g h u o = a o = s 4 e n s n b r n n b b m t g n l n l w n o e w e n n e r g i . 5 c t o = a g d - r r = m c w v p v . e v g c e c d v x g . m 6 k r l r s e o t e e b a h e e . e . b e . k b k l e t e . p 7 - i e e e f c e p p u n b b r . r . - r . - - - e r e f . o . 8 p b t v - i . s o o n d o d t . t . c t . c s = 2 t n i . r 9 y - e s c l . t - . d - m i - . - . o - . o y r - - s l . t 10 3 p - e h e . s s . l t b r s . s . m s . d m e f s i e . . 11 - e c t e s . . v . e e . . v . v . m v . e r n o v o s . . 12 c r h . c - . . n . 2 m . . n . n . a n . . e a r n n . . . 13 o f e . k u . . . . - p . . - . - . n - . . v m m - . . . . 14 m . c . - p . . . . e l . . s . m . d s . . . e a e . . . . 15 p . k . r d . . . . x a . . i . o . s o . . . - t n . . . . 16 a . h . e a . . . . c t . . n . v . . u . . . m . c . . . . 17 t . e . s t . . . . h e . . k . e . . r . . . e . o . . . . 18 . . a . t e . . . . a . . . . . . . . c . . . r . d . . . . 19 . . d . o . . . . . n . . . . . . . . e . . . g . i . . . . 20 . . s . r . . . . . g . . . . . . . . . . . . e . n . . . . 21 . . . . e . . . . . e . . . . . . . . . . . . 2 . g . . . . 22 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 . . . . . . . . . . . . . . . . . . . . . . . . . = . . . . ^C Test names read off vertically, beginning with '='. Idle time (not shown) appears as blank space.
author Matt Mackall <mpm@selenic.com>
date Mon, 07 Dec 2015 16:16:06 -0600
parents b4d7743e174a
children 80b53082a353
comparison
equal deleted inserted replaced
27395:0622d6e134fb 27396:64c584070fc7
265 help='run tests in random order') 265 help='run tests in random order')
266 parser.add_option('--profile-runner', action='store_true', 266 parser.add_option('--profile-runner', action='store_true',
267 help='run statprof on run-tests') 267 help='run statprof on run-tests')
268 parser.add_option('--allow-slow-tests', action='store_true', 268 parser.add_option('--allow-slow-tests', action='store_true',
269 help='allow extremely slow tests') 269 help='allow extremely slow tests')
270 parser.add_option('--showchannels', action='store_true',
271 help='show scheduling channels')
270 272
271 for option, (envvar, default) in defaults.items(): 273 for option, (envvar, default) in defaults.items():
272 defaults[option] = type(default)(os.environ.get(envvar, default)) 274 defaults[option] = type(default)(os.environ.get(envvar, default))
273 parser.set_defaults(**defaults) 275 parser.set_defaults(**defaults)
274 276
344 options.blacklist = parselistfiles(options.blacklist, 'blacklist') 346 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
345 if options.whitelist: 347 if options.whitelist:
346 options.whitelisted = parselistfiles(options.whitelist, 'whitelist') 348 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
347 else: 349 else:
348 options.whitelisted = {} 350 options.whitelisted = {}
351
352 if options.showchannels:
353 options.nodiff = True
349 354
350 return (options, args) 355 return (options, args)
351 356
352 def rename(src, dst): 357 def rename(src, dst):
353 """Like os.rename(), trade atomicity and opened files friendliness 358 """Like os.rename(), trade atomicity and opened files friendliness
1416 class TestSuite(unittest.TestSuite): 1421 class TestSuite(unittest.TestSuite):
1417 """Custom unittest TestSuite that knows how to execute Mercurial tests.""" 1422 """Custom unittest TestSuite that knows how to execute Mercurial tests."""
1418 1423
1419 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None, 1424 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None,
1420 retest=False, keywords=None, loop=False, runs_per_test=1, 1425 retest=False, keywords=None, loop=False, runs_per_test=1,
1421 loadtest=None, 1426 loadtest=None, showchannels=False,
1422 *args, **kwargs): 1427 *args, **kwargs):
1423 """Create a new instance that can run tests with a configuration. 1428 """Create a new instance that can run tests with a configuration.
1424 1429
1425 testdir specifies the directory where tests are executed from. This 1430 testdir specifies the directory where tests are executed from. This
1426 is typically the ``tests`` directory from Mercurial's source 1431 is typically the ``tests`` directory from Mercurial's source
1453 self._retest = retest 1458 self._retest = retest
1454 self._keywords = keywords 1459 self._keywords = keywords
1455 self._loop = loop 1460 self._loop = loop
1456 self._runs_per_test = runs_per_test 1461 self._runs_per_test = runs_per_test
1457 self._loadtest = loadtest 1462 self._loadtest = loadtest
1463 self._showchannels = showchannels
1458 1464
1459 def run(self, result): 1465 def run(self, result):
1460 # We have a number of filters that need to be applied. We do this 1466 # We have a number of filters that need to be applied. We do this
1461 # here instead of inside Test because it makes the running logic for 1467 # here instead of inside Test because it makes the running logic for
1462 # Test simpler. 1468 # Test simpler.
1499 1505
1500 runtests = list(tests) 1506 runtests = list(tests)
1501 done = queue.Queue() 1507 done = queue.Queue()
1502 running = 0 1508 running = 0
1503 1509
1510 channels = [""] * self._jobs
1511
1504 def job(test, result): 1512 def job(test, result):
1513 for n, v in enumerate(channels):
1514 if not v:
1515 channel = n
1516 break
1517 channels[channel] = "=" + test.name[5:].split(".")[0]
1505 try: 1518 try:
1506 test(result) 1519 test(result)
1507 done.put(None) 1520 done.put(None)
1508 except KeyboardInterrupt: 1521 except KeyboardInterrupt:
1509 pass 1522 pass
1510 except: # re-raises 1523 except: # re-raises
1511 done.put(('!', test, 'run-test raised an error, see traceback')) 1524 done.put(('!', test, 'run-test raised an error, see traceback'))
1512 raise 1525 raise
1526 channels[channel] = ''
1527
1528 def stat():
1529 count = 0
1530 while channels:
1531 d = '\n%03s ' % count
1532 for n, v in enumerate(channels):
1533 if v:
1534 d += v[0]
1535 channels[n] = v[1:] or '.'
1536 else:
1537 d += ' '
1538 d += ' '
1539 with iolock:
1540 sys.stdout.write(d + ' ')
1541 sys.stdout.flush()
1542 for x in xrange(10):
1543 if channels:
1544 time.sleep(.1)
1545 count += 1
1513 1546
1514 stoppedearly = False 1547 stoppedearly = False
1548
1549 if self._showchannels:
1550 statthread = threading.Thread(target=stat, name="stat")
1551 statthread.start()
1515 1552
1516 try: 1553 try:
1517 while tests or running: 1554 while tests or running:
1518 if not done.empty() or running == self._jobs or not tests: 1555 if not done.empty() or running == self._jobs or not tests:
1519 try: 1556 try:
1550 except queue.Empty: 1587 except queue.Empty:
1551 continue 1588 continue
1552 except KeyboardInterrupt: 1589 except KeyboardInterrupt:
1553 for test in runtests: 1590 for test in runtests:
1554 test.abort() 1591 test.abort()
1592
1593 channels = []
1555 1594
1556 return result 1595 return result
1557 1596
1558 class TextTestRunner(unittest.TextTestRunner): 1597 class TextTestRunner(unittest.TextTestRunner):
1559 """Custom unittest test runner that uses appropriate settings.""" 1598 """Custom unittest test runner that uses appropriate settings."""
1940 blacklist=self.options.blacklist, 1979 blacklist=self.options.blacklist,
1941 retest=self.options.retest, 1980 retest=self.options.retest,
1942 keywords=kws, 1981 keywords=kws,
1943 loop=self.options.loop, 1982 loop=self.options.loop,
1944 runs_per_test=self.options.runs_per_test, 1983 runs_per_test=self.options.runs_per_test,
1984 showchannels=self.options.showchannels,
1945 tests=tests, loadtest=self._gettest) 1985 tests=tests, loadtest=self._gettest)
1946 verbosity = 1 1986 verbosity = 1
1947 if self.options.verbose: 1987 if self.options.verbose:
1948 verbosity = 2 1988 verbosity = 2
1949 runner = TextTestRunner(self, verbosity=verbosity) 1989 runner = TextTestRunner(self, verbosity=verbosity)