if slaveargs is not None:
args, kwargs = json.loads(slaveargs)
- if kwargs['huntrleaks']:
- warm_caches()
if testdir:
kwargs['testdir'] = testdir
try:
print json.dumps(result)
sys.exit(0)
- if huntrleaks:
- warm_caches()
-
good = []
bad = []
skipped = []
indirect_test = getattr(the_module, "test_main", None)
if huntrleaks:
refleak = dash_R(the_module, test, indirect_test,
- huntrleaks)
+ huntrleaks, quiet)
else:
if indirect_test is not None:
indirect_test()
print >> sys.stderr, ("%r left behind %s %r and it couldn't be "
"removed: %s" % (testname, kind, name, msg))
-def dash_R(the_module, test, indirect_test, huntrleaks):
+def dash_R(the_module, test, indirect_test, huntrleaks, quiet):
"""Run a test multiple times, looking for reference leaks.
Returns:
raise Exception("Tracking reference leaks requires a debug build "
"of Python")
+ # Avoid false positives due to various caches
+ # filling slowly with random data:
+ warm_caches()
+
# Save current values for dash_R_cleanup() to restore.
fs = warnings.filters[:]
ps = copy_reg.dispatch_table.copy()
for obj in abc.__subclasses__() + [abc]:
abcs[obj] = obj._abc_registry.copy()
+ # bpo-31217: Integer pool to get a single integer object for the same
+ # value. The pool is used to prevent false alarm when checking for memory
+ # block leaks. Fill the pool with values in -1000..1000 which are the most
+ # common (reference, memory block, file descriptor) differences.
+ int_pool = {value: value for value in range(-1000, 1000)}
+ def get_pooled_int(value):
+ return int_pool.setdefault(value, value)
+
if indirect_test:
def run_the_test():
indirect_test()
deltas = []
nwarmup, ntracked, fname = huntrleaks
fname = os.path.join(support.SAVEDCWD, fname)
+
+ # Pre-allocate to ensure that the loop doesn't allocate anything new
repcount = nwarmup + ntracked
- rc_deltas = [0] * ntracked
- fd_deltas = [0] * ntracked
+ rc_deltas = [0] * repcount
+ fd_deltas = [0] * repcount
+ rep_range = list(range(repcount))
+
+ if not quiet:
+ print >> sys.stderr, "beginning", repcount, "repetitions"
+ print >> sys.stderr, ("1234567890"*(repcount//10 + 1))[:repcount]
- print >> sys.stderr, "beginning", repcount, "repetitions"
- print >> sys.stderr, ("1234567890"*(repcount//10 + 1))[:repcount]
dash_R_cleanup(fs, ps, pic, zdc, abcs)
+
# initialize variables to make pyflakes quiet
rc_before = fd_before = 0
- for i in range(repcount):
+
+ for i in rep_range:
run_the_test()
- sys.stderr.write('.')
+
+ if not quiet:
+ sys.stderr.write('.')
+
dash_R_cleanup(fs, ps, pic, zdc, abcs)
+
rc_after = sys.gettotalrefcount()
fd_after = support.fd_count()
- if i >= nwarmup:
- rc_deltas[i - nwarmup] = rc_after - rc_before
- fd_deltas[i - nwarmup] = fd_after - fd_before
+ rc_deltas[i] = get_pooled_int(rc_after - rc_before)
+ fd_deltas[i] = get_pooled_int(fd_after - fd_before)
rc_before = rc_after
fd_before = fd_after
- print >> sys.stderr
+
+ if not quiet:
+ print >> sys.stderr
# These checkers return False on success, True on failure
def check_rc_deltas(deltas):
(rc_deltas, 'references', check_rc_deltas),
(fd_deltas, 'file descriptors', check_fd_deltas)
]:
+ deltas = deltas[nwarmup:]
if checker(deltas):
msg = '%s leaked %s %s, sum=%s' % (test, deltas, item_name, sum(deltas))
print >> sys.stderr, msg
ctypes._reset_cache()
# Collect cyclic trash.
- gc.collect()
+ support.gc_collect()
def warm_caches():
"""Create explicitly internal singletons which are created on demand