bpo-36560: Fix reference leak hunting in regrtest (GH-12744) · python/cpython@5aaac94

@@ -18,7 +18,7 @@ def _get_dump(cls):

1818

cls._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):

3232

raise 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.

3640

fs = warnings.filters[:]

3741

ps = copyreg.dispatch_table.copy()

@@ -57,31 +61,50 @@ def dash_R(the_module, test, indirect_test, huntrleaks):

5761

def get_pooled_int(value):

5862

return int_pool.setdefault(value, value)

596360-

nwarmup, ntracked, fname = huntrleaks

64+

nwarmup, ntracked, fname = ns.huntrleaks

6165

fname = os.path.join(support.SAVEDCWD, fname)

6266

repcount = nwarmup + ntracked

67+68+

# Pre-allocate to ensure that the loop doesn't allocate anything new

69+

rep_range = list(range(repcount))

6370

rc_deltas = [0] * repcount

6471

alloc_deltas = [0] * repcount

6572

fd_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

7178

rc_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+81102

alloc_before = alloc_after

82103

rc_before = rc_after

83104

fd_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

87110

def check_rc_deltas(deltas):

@@ -112,7 +135,7 @@ def check_fd_deltas(deltas):

112135

deltas = deltas[nwarmup:]

113136

if checker(deltas):

114137

msg = '%s leaked %s %s, sum=%s' % (

115-

test, deltas, item_name, sum(deltas))

138+

test_name, deltas, item_name, sum(deltas))

116139

print(msg, file=sys.stderr, flush=True)

117140

with open(fname, "a") as refrep:

118141

print(msg, file=refrep)

@@ -122,7 +145,7 @@ def check_fd_deltas(deltas):

122145123146124147

def dash_R_cleanup(fs, ps, pic, zdc, abcs):

125-

import gc, copyreg

148+

import copyreg

126149

import collections.abc

127150128151

# Restore some original values.

@@ -154,16 +177,8 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):

154177155178

clear_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-163180164181

def clear_caches():

165-

import gc

166-167182

# Clear the warnings registry, so they can be displayed again

168183

for mod in sys.modules.values():

169184

if hasattr(mod, '__warningregistry__'):

@@ -256,7 +271,7 @@ def clear_caches():

256271

for f in typing._cleanups:

257272

f()

258273259-

gc.collect()

274+

support.gc_collect()

260275261276262277

def warm_caches():