Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(32876)

Side by Side Diff: Lib/test/regrtest.py

Issue 13390: Hunt memory allocations in addition to reference leaks
Patch Set: Created 6 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Include/objimpl.h ('k') | Lib/test/support.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #! /usr/bin/env python3 1 #! /usr/bin/env python3
2 2
3 """ 3 """
4 Usage: 4 Usage:
5 5
6 python -m test [options] [test_name1 [test_name2 ...]] 6 python -m test [options] [test_name1 [test_name2 ...]]
7 python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]] 7 python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]]
8 8
9 9
10 If no arguments or options are provided, finds all files matching 10 If no arguments or options are provided, finds all files matching
(...skipping 597 matching lines...) Expand 10 before | Expand all | Expand 10 after
608 test_count_width = len(test_count) - 1 608 test_count_width = len(test_count) - 1
609 609
610 if use_mp: 610 if use_mp:
611 try: 611 try:
612 from threading import Thread 612 from threading import Thread
613 except ImportError: 613 except ImportError:
614 print("Multiprocess option requires thread support") 614 print("Multiprocess option requires thread support")
615 sys.exit(2) 615 sys.exit(2)
616 from queue import Queue 616 from queue import Queue
617 from subprocess import Popen, PIPE 617 from subprocess import Popen, PIPE
618 debug_output_pat = re.compile(r"\[\d+ refs\]$") 618 debug_output_pat = re.compile(r"\[\d+ refs, \d+ blocks\]$")
619 output = Queue() 619 output = Queue()
620 pending = MultiprocessTests(tests) 620 pending = MultiprocessTests(tests)
621 opt_args = support.args_from_interpreter_flags() 621 opt_args = support.args_from_interpreter_flags()
622 base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest'] 622 base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest']
623 def work(): 623 def work():
624 # A worker thread. 624 # A worker thread.
625 try: 625 try:
626 while True: 626 while True:
627 try: 627 try:
628 test = next(pending) 628 test = next(pending)
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after
1313 abcs[obj] = obj._abc_registry.copy() 1313 abcs[obj] = obj._abc_registry.copy()
1314 1314
1315 if indirect_test: 1315 if indirect_test:
1316 def run_the_test(): 1316 def run_the_test():
1317 indirect_test() 1317 indirect_test()
1318 else: 1318 else:
1319 def run_the_test(): 1319 def run_the_test():
1320 del sys.modules[the_module.__name__] 1320 del sys.modules[the_module.__name__]
1321 exec('import ' + the_module.__name__) 1321 exec('import ' + the_module.__name__)
1322 1322
1323 deltas = []
1324 nwarmup, ntracked, fname = huntrleaks 1323 nwarmup, ntracked, fname = huntrleaks
1325 fname = os.path.join(support.SAVEDCWD, fname) 1324 fname = os.path.join(support.SAVEDCWD, fname)
1326 repcount = nwarmup + ntracked 1325 repcount = nwarmup + ntracked
1326 rc_deltas = [0] * repcount
1327 alloc_deltas = [0] * repcount
1328
1327 print("beginning", repcount, "repetitions", file=sys.stderr) 1329 print("beginning", repcount, "repetitions", file=sys.stderr)
1328 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr) 1330 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr)
1329 sys.stderr.flush() 1331 sys.stderr.flush()
1330 dash_R_cleanup(fs, ps, pic, zdc, abcs)
1331 for i in range(repcount): 1332 for i in range(repcount):
1332 rc_before = sys.gettotalrefcount()
1333 run_the_test() 1333 run_the_test()
1334 alloc_after, rc_after = dash_R_cleanup(fs, ps, pic, zdc, abcs)
1334 sys.stderr.write('.') 1335 sys.stderr.write('.')
1335 sys.stderr.flush() 1336 sys.stderr.flush()
1336 dash_R_cleanup(fs, ps, pic, zdc, abcs)
1337 rc_after = sys.gettotalrefcount()
1338 if i >= nwarmup: 1337 if i >= nwarmup:
1339 deltas.append(rc_after - rc_before) 1338 rc_deltas[i] = rc_after - rc_before
1339 alloc_deltas[i] = alloc_after - alloc_before
1340 alloc_before, rc_before = alloc_after, rc_after
1340 print(file=sys.stderr) 1341 print(file=sys.stderr)
1341 if any(deltas): 1342 # These checkers return False on success, True on failure
1342 msg = '%s leaked %s references, sum=%s' % (test, deltas, sum(deltas)) 1343 def check_rc_deltas(deltas):
1343 print(msg, file=sys.stderr) 1344 return any(deltas)
1344 sys.stderr.flush() 1345 def check_alloc_deltas(deltas):
1345 with open(fname, "a") as refrep: 1346 # At least 1/3rd of 0s
1346 print(msg, file=refrep) 1347 if 3 * deltas.count(0) < len(deltas):
1347 refrep.flush() 1348 return True
1348 return True 1349 # Nothing else than 1s, 0s and -1s
1349 return False 1350 if not set(deltas) <= {1,0,-1}:
1351 return True
1352 return False
1353 failed = False
1354 for deltas, item_name, checker in [
1355 (rc_deltas, 'references', check_rc_deltas),
1356 (alloc_deltas, 'memory blocks', check_alloc_deltas)]:
1357 if checker(deltas):
1358 msg = '%s leaked %s %s, sum=%s' % (
1359 test, deltas[nwarmup:], item_name, sum(deltas))
1360 print(msg, file=sys.stderr)
1361 sys.stderr.flush()
1362 with open(fname, "a") as refrep:
1363 print(msg, file=refrep)
1364 refrep.flush()
1365 failed = True
1366 return failed
1350 1367
1351 def dash_R_cleanup(fs, ps, pic, zdc, abcs): 1368 def dash_R_cleanup(fs, ps, pic, zdc, abcs):
1352 import gc, copyreg 1369 import gc, copyreg
1353 import _strptime, linecache 1370 import _strptime, linecache
1354 import urllib.parse, urllib.request, mimetypes, doctest 1371 import urllib.parse, urllib.request, mimetypes, doctest
1355 import struct, filecmp, collections.abc 1372 import struct, filecmp, collections.abc
1356 from distutils.dir_util import _path_created 1373 from distutils.dir_util import _path_created
1357 from weakref import WeakSet 1374 from weakref import WeakSet
1358 1375
1359 # Clear the warnings registry, so they can be displayed again 1376 # Clear the warnings registry, so they can be displayed again
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1405 struct._clearcache() 1422 struct._clearcache()
1406 doctest.master = None 1423 doctest.master = None
1407 try: 1424 try:
1408 import ctypes 1425 import ctypes
1409 except ImportError: 1426 except ImportError:
1410 # Don't worry about resetting the cache if ctypes is not supported 1427 # Don't worry about resetting the cache if ctypes is not supported
1411 pass 1428 pass
1412 else: 1429 else:
1413 ctypes._reset_cache() 1430 ctypes._reset_cache()
1414 1431
1415 # Collect cyclic trash. 1432 # Collect cyclic trash and read memory statistics immediately after.
1433 func1 = sys.getallocatedblocks
1434 func2 = sys.gettotalrefcount
1416 gc.collect() 1435 gc.collect()
1436 return func1(), func2()
1417 1437
1418 def warm_caches(): 1438 def warm_caches():
1419 # char cache 1439 # char cache
1420 s = bytes(range(256)) 1440 s = bytes(range(256))
1421 for i in range(256): 1441 for i in range(256):
1422 s[i:i+1] 1442 s[i:i+1]
1423 # unicode cache 1443 # unicode cache
1424 x = [chr(i) for i in range(256)] 1444 x = [chr(i) for i in range(256)]
1425 # int cache 1445 # int cache
1426 x = list(range(-5, 257)) 1446 x = list(range(-5, 257))
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1500 assert __file__ == os.path.abspath(sys.argv[0]) 1520 assert __file__ == os.path.abspath(sys.argv[0])
1501 1521
1502 TEMPDIR, TESTCWD = _make_temp_dir_for_build(TEMPDIR) 1522 TEMPDIR, TESTCWD = _make_temp_dir_for_build(TEMPDIR)
1503 1523
1504 # Run the tests in a context manager that temporary changes the CWD to a 1524 # Run the tests in a context manager that temporary changes the CWD to a
1505 # temporary and writable directory. If it's not possible to create or 1525 # temporary and writable directory. If it's not possible to create or
1506 # change the CWD, the original CWD will be used. The original CWD is 1526 # change the CWD, the original CWD will be used. The original CWD is
1507 # available from support.SAVEDCWD. 1527 # available from support.SAVEDCWD.
1508 with support.temp_cwd(TESTCWD, quiet=True): 1528 with support.temp_cwd(TESTCWD, quiet=True):
1509 main() 1529 main()
OLDNEW
« no previous file with comments | « Include/objimpl.h ('k') | Lib/test/support.py » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+