bpo-36560: Fix reference leak hunting in regrtest (GH-12744) · python/cpython@5aaac94
@@ -18,7 +18,7 @@ def _get_dump(cls):
1818cls._abc_negative_cache, cls._abc_negative_cache_version)
1919202021-def dash_R(the_module, test, indirect_test, huntrleaks):
21+def dash_R(ns, the_module, test_name, test_func):
2222"""Run a test multiple times, looking for reference leaks.
23232424 Returns:
@@ -32,6 +32,10 @@ def dash_R(the_module, test, indirect_test, huntrleaks):
3232raise Exception("Tracking reference leaks requires a debug build "
3333"of Python")
343435+# Avoid false positives due to various caches
36+# filling slowly with random data:
37+warm_caches()
38+3539# Save current values for dash_R_cleanup() to restore.
3640fs = warnings.filters[:]
3741ps = copyreg.dispatch_table.copy()
@@ -57,31 +61,50 @@ def dash_R(the_module, test, indirect_test, huntrleaks):
5761def get_pooled_int(value):
5862return int_pool.setdefault(value, value)
596360-nwarmup, ntracked, fname = huntrleaks
64+nwarmup, ntracked, fname = ns.huntrleaks
6165fname = os.path.join(support.SAVEDCWD, fname)
6266repcount = nwarmup + ntracked
67+68+# Pre-allocate to ensure that the loop doesn't allocate anything new
69+rep_range = list(range(repcount))
6370rc_deltas = [0] * repcount
6471alloc_deltas = [0] * repcount
6572fd_deltas = [0] * repcount
73+getallocatedblocks = sys.getallocatedblocks
74+gettotalrefcount = sys.gettotalrefcount
75+fd_count = support.fd_count
667667-print("beginning", repcount, "repetitions", file=sys.stderr)
68-print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
69-flush=True)
7077# initialize variables to make pyflakes quiet
7178rc_before = alloc_before = fd_before = 0
72-for i in range(repcount):
73-indirect_test()
74-alloc_after, rc_after, fd_after = dash_R_cleanup(fs, ps, pic, zdc,
75-abcs)
76-print('.', end='', file=sys.stderr, flush=True)
77-if i >= nwarmup:
78-rc_deltas[i] = get_pooled_int(rc_after - rc_before)
79-alloc_deltas[i] = get_pooled_int(alloc_after - alloc_before)
80-fd_deltas[i] = get_pooled_int(fd_after - fd_before)
79+80+if not ns.quiet:
81+print("beginning", repcount, "repetitions", file=sys.stderr)
82+print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
83+flush=True)
84+85+for i in rep_range:
86+test_func()
87+dash_R_cleanup(fs, ps, pic, zdc, abcs)
88+89+# Collect cyclic trash and read memory statistics immediately after.
90+support.gc_collect()
91+alloc_after = getallocatedblocks()
92+rc_after = gettotalrefcount()
93+fd_after = fd_count()
94+95+if not ns.quiet:
96+print('.', end='', file=sys.stderr, flush=True)
97+98+rc_deltas[i] = get_pooled_int(rc_after - rc_before)
99+alloc_deltas[i] = get_pooled_int(alloc_after - alloc_before)
100+fd_deltas[i] = get_pooled_int(fd_after - fd_before)
101+81102alloc_before = alloc_after
82103rc_before = rc_after
83104fd_before = fd_after
84-print(file=sys.stderr)
105+106+if not ns.quiet:
107+print(file=sys.stderr)
8510886109# These checkers return False on success, True on failure
87110def check_rc_deltas(deltas):
@@ -112,7 +135,7 @@ def check_fd_deltas(deltas):
112135deltas = deltas[nwarmup:]
113136if checker(deltas):
114137msg = '%s leaked %s %s, sum=%s' % (
115-test, deltas, item_name, sum(deltas))
138+test_name, deltas, item_name, sum(deltas))
116139print(msg, file=sys.stderr, flush=True)
117140with open(fname, "a") as refrep:
118141print(msg, file=refrep)
@@ -122,7 +145,7 @@ def check_fd_deltas(deltas):
122145123146124147def dash_R_cleanup(fs, ps, pic, zdc, abcs):
125-import gc, copyreg
148+import copyreg
126149import collections.abc
127150128151# Restore some original values.
@@ -154,16 +177,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
154177155178clear_caches()
156179157-# Collect cyclic trash and read memory statistics immediately after.
158-func1 = sys.getallocatedblocks
159-func2 = sys.gettotalrefcount
160-gc.collect()
161-return func1(), func2(), support.fd_count()
162-163180164181def clear_caches():
165-import gc
166-167182# Clear the warnings registry, so they can be displayed again
168183for mod in sys.modules.values():
169184if hasattr(mod, '__warningregistry__'):
@@ -256,7 +271,7 @@ def clear_caches():
256271for f in typing._cleanups:
257272f()
258273259-gc.collect()
274+support.gc_collect()
260275261276262277def warm_caches():