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

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

Issue 13390: Hunt memory allocations in addition to reference leaks
Patch Set: Created 8 years, 4 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 592 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 test_count_width = len(test_count) - 1 603 test_count_width = len(test_count) - 1
604 604
605 if use_mp: 605 if use_mp:
606 try: 606 try:
607 from threading import Thread 607 from threading import Thread
608 except ImportError: 608 except ImportError:
609 print("Multiprocess option requires thread support") 609 print("Multiprocess option requires thread support")
610 sys.exit(2) 610 sys.exit(2)
611 from queue import Queue 611 from queue import Queue
612 from subprocess import Popen, PIPE 612 from subprocess import Popen, PIPE
613 debug_output_pat = re.compile(r"\[\d+ refs\]$") 613 debug_output_pat = re.compile(r"\[\d+ refs, \d+ blocks\]$")
614 output = Queue() 614 output = Queue()
615 def tests_and_args(): 615 def tests_and_args():
616 for test in tests: 616 for test in tests:
617 args_tuple = ( 617 args_tuple = (
618 (test, verbose, quiet), 618 (test, verbose, quiet),
619 dict(huntrleaks=huntrleaks, use_resources=use_resources, 619 dict(huntrleaks=huntrleaks, use_resources=use_resources,
620 debug=debug, output_on_failure=verbose3, 620 debug=debug, output_on_failure=verbose3,
621 timeout=timeout, failfast=failfast, 621 timeout=timeout, failfast=failfast,
622 match_tests=match_tests) 622 match_tests=match_tests)
623 ) 623 )
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after
1310 abcs[obj] = obj._abc_registry.copy() 1310 abcs[obj] = obj._abc_registry.copy()
1311 1311
1312 if indirect_test: 1312 if indirect_test:
1313 def run_the_test(): 1313 def run_the_test():
1314 indirect_test() 1314 indirect_test()
1315 else: 1315 else:
1316 def run_the_test(): 1316 def run_the_test():
1317 del sys.modules[the_module.__name__] 1317 del sys.modules[the_module.__name__]
1318 exec('import ' + the_module.__name__) 1318 exec('import ' + the_module.__name__)
1319 1319
1320 deltas = []
1321 nwarmup, ntracked, fname = huntrleaks 1320 nwarmup, ntracked, fname = huntrleaks
1322 fname = os.path.join(support.SAVEDCWD, fname) 1321 fname = os.path.join(support.SAVEDCWD, fname)
1323 repcount = nwarmup + ntracked 1322 repcount = nwarmup + ntracked
1323 rc_deltas = [0] * repcount
1324 alloc_deltas = [0] * repcount
1325
1324 print("beginning", repcount, "repetitions", file=sys.stderr) 1326 print("beginning", repcount, "repetitions", file=sys.stderr)
1325 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr) 1327 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr)
1326 sys.stderr.flush() 1328 sys.stderr.flush()
1327 dash_R_cleanup(fs, ps, pic, zdc, abcs)
1328 for i in range(repcount): 1329 for i in range(repcount):
1329 rc_before = sys.gettotalrefcount() 1330 alloc_before, rc_before = dash_R_cleanup(fs, ps, pic, zdc, abcs)
1330 run_the_test() 1331 run_the_test()
1332 alloc_after, rc_after = dash_R_cleanup(fs, ps, pic, zdc, abcs)
1331 sys.stderr.write('.') 1333 sys.stderr.write('.')
1332 sys.stderr.flush() 1334 sys.stderr.flush()
1333 dash_R_cleanup(fs, ps, pic, zdc, abcs)
1334 rc_after = sys.gettotalrefcount()
1335 if i >= nwarmup: 1335 if i >= nwarmup:
1336 deltas.append(rc_after - rc_before) 1336 rc_deltas[i] = rc_after - rc_before
1337 alloc_deltas[i] = alloc_after - alloc_before
1337 print(file=sys.stderr) 1338 print(file=sys.stderr)
1338 if any(deltas): 1339 # These checkers return False on success, True on failure
1339 msg = '%s leaked %s references, sum=%s' % (test, deltas, sum(deltas)) 1340 def check_rc_deltas(deltas):
1340 print(msg, file=sys.stderr) 1341 return any(deltas)
1341 sys.stderr.flush() 1342 def check_alloc_deltas(deltas):
1342 with open(fname, "a") as refrep: 1343 # At least 1/3rd of 0s
1343 print(msg, file=refrep) 1344 if 3 * deltas.count(0) < len(deltas):
1344 refrep.flush() 1345 return True
1345 return True 1346 # Nothing else than 1s, 0s and -1s
1346 return False 1347 if not set(deltas) <= {1,0,-1}:
1348 return True
1349 return False
1350 failed = False
1351 for deltas, item_name, checker in [
1352 (rc_deltas, 'references', check_rc_deltas),
1353 (alloc_deltas, 'memory blocks', check_alloc_deltas)]:
1354 if checker(deltas):
1355 msg = '%s leaked %s %s, sum=%s' % (
1356 test, deltas[nwarmup:], item_name, sum(deltas))
1357 print(msg, file=sys.stderr)
1358 sys.stderr.flush()
1359 with open(fname, "a") as refrep:
1360 print(msg, file=refrep)
1361 refrep.flush()
1362 failed = True
1363 return failed
1347 1364
1348 def dash_R_cleanup(fs, ps, pic, zdc, abcs): 1365 def dash_R_cleanup(fs, ps, pic, zdc, abcs):
1349 import gc, copyreg 1366 import gc, copyreg
1350 import _strptime, linecache 1367 import _strptime, linecache
1351 import urllib.parse, urllib.request, mimetypes, doctest 1368 import urllib.parse, urllib.request, mimetypes, doctest
1352 import struct, filecmp, collections.abc 1369 import struct, filecmp, collections.abc
1353 from distutils.dir_util import _path_created 1370 from distutils.dir_util import _path_created
1354 from weakref import WeakSet 1371 from weakref import WeakSet
1355 1372
1356 # Clear the warnings registry, so they can be displayed again 1373 # Clear the warnings registry, so they can be displayed again
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1395 re.purge() 1412 re.purge()
1396 _strptime._regex_cache.clear() 1413 _strptime._regex_cache.clear()
1397 urllib.parse.clear_cache() 1414 urllib.parse.clear_cache()
1398 urllib.request.urlcleanup() 1415 urllib.request.urlcleanup()
1399 linecache.clearcache() 1416 linecache.clearcache()
1400 mimetypes._default_mime_types() 1417 mimetypes._default_mime_types()
1401 filecmp._cache.clear() 1418 filecmp._cache.clear()
1402 struct._clearcache() 1419 struct._clearcache()
1403 doctest.master = None 1420 doctest.master = None
1404 1421
1405 # Collect cyclic trash. 1422 # Collect cyclic trash and read memory statistics immediately after.
1423 func1 = sys.getallocatedblocks
1424 func2 = sys.gettotalrefcount
1406 gc.collect() 1425 gc.collect()
1426 return func1(), func2()
1407 1427
1408 def warm_char_cache(): 1428 def warm_char_cache():
1409 s = bytes(range(256)) 1429 s = bytes(range(256))
1410 for i in range(256): 1430 for i in range(256):
1411 s[i:i+1] 1431 s[i:i+1]
1412 1432
1413 def findtestdir(path=None): 1433 def findtestdir(path=None):
1414 return path or os.path.dirname(__file__) or os.curdir 1434 return path or os.path.dirname(__file__) or os.curdir
1415 1435
1416 def removepy(names): 1436 def removepy(names):
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
1771 assert __file__ == os.path.abspath(sys.argv[0]) 1791 assert __file__ == os.path.abspath(sys.argv[0])
1772 1792
1773 TEMPDIR, TESTCWD = _make_temp_dir_for_build(TEMPDIR) 1793 TEMPDIR, TESTCWD = _make_temp_dir_for_build(TEMPDIR)
1774 1794
1775 # Run the tests in a context manager that temporary changes the CWD to a 1795 # Run the tests in a context manager that temporary changes the CWD to a
1776 # temporary and writable directory. If it's not possible to create or 1796 # temporary and writable directory. If it's not possible to create or
1777 # change the CWD, the original CWD will be used. The original CWD is 1797 # change the CWD, the original CWD will be used. The original CWD is
1778 # available from support.SAVEDCWD. 1798 # available from support.SAVEDCWD.
1779 with support.temp_cwd(TESTCWD, quiet=True): 1799 with support.temp_cwd(TESTCWD, quiet=True):
1780 main() 1800 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+