@@ -615,7 +615,7 @@ def test_forever(tests=list(selected)):
615615 sys .exit (2 )
616616 from queue import Queue
617617 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 \]$" )
619619 output = Queue ()
620620 pending = MultiprocessTests (tests )
621621 opt_args = support .args_from_interpreter_flags ()
@@ -1320,33 +1320,50 @@ def run_the_test():
13201320 del sys .modules [the_module .__name__ ]
13211321 exec ('import ' + the_module .__name__ )
13221322
1323- deltas = []
13241323 nwarmup , ntracked , fname = huntrleaks
13251324 fname = os .path .join (support .SAVEDCWD , fname )
13261325 repcount = nwarmup + ntracked
1326+ rc_deltas = [0 ] * repcount
1327+ alloc_deltas = [0 ] * repcount
1328+
13271329 print ("beginning" , repcount , "repetitions" , file = sys .stderr )
13281330 print (("1234567890" * (repcount // 10 + 1 ))[:repcount ], file = sys .stderr )
13291331 sys .stderr .flush ()
1330- dash_R_cleanup (fs , ps , pic , zdc , abcs )
13311332 for i in range (repcount ):
1332- rc_before = sys .gettotalrefcount ()
13331333 run_the_test ()
1334+ alloc_after , rc_after = dash_R_cleanup (fs , ps , pic , zdc , abcs )
13341335 sys .stderr .write ('.' )
13351336 sys .stderr .flush ()
1336- dash_R_cleanup (fs , ps , pic , zdc , abcs )
1337- rc_after = sys .gettotalrefcount ()
13381337 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
13401341 print (file = sys .stderr )
1341- if any (deltas ):
1342- msg = '%s leaked %s references, sum=%s' % (test , deltas , sum (deltas ))
1343- print (msg , file = sys .stderr )
1344- sys .stderr .flush ()
1345- with open (fname , "a" ) as refrep :
1346- print (msg , file = refrep )
1347- refrep .flush ()
1348- return True
1349- return False
1342+ # These checkers return False on success, True on failure
1343+ def check_rc_deltas (deltas ):
1344+ return any (deltas )
1345+ def check_alloc_deltas (deltas ):
1346+ # At least 1/3rd of 0s
1347+ if 3 * deltas .count (0 ) < len (deltas ):
1348+ return True
1349+ # Nothing else than 1s, 0s and -1s
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
13501367
13511368def dash_R_cleanup (fs , ps , pic , zdc , abcs ):
13521369 import gc , copyreg
@@ -1412,8 +1429,11 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
14121429 else :
14131430 ctypes ._reset_cache ()
14141431
1415- # Collect cyclic trash.
1432+ # Collect cyclic trash and read memory statistics immediately after.
1433+ func1 = sys .getallocatedblocks
1434+ func2 = sys .gettotalrefcount
14161435 gc .collect ()
1436+ return func1 (), func2 ()
14171437
14181438def warm_caches ():
14191439 # char cache
0 commit comments