blob: 59dc49fe77cc75ae353b59fb630eb9937d89e59e [file] [log] [blame]
Victor Stinner076fc872015-10-03 00:20:56 +02001import errno
Victor Stinner3844fe52015-09-26 10:38:01 +02002import os
3import re
4import sys
5import warnings
6from inspect import isabstract
7from test import support
8
9
Victor Stinner076fc872015-10-03 00:20:56 +020010try:
11 MAXFD = os.sysconf("SC_OPEN_MAX")
12except Exception:
13 MAXFD = 256
14
15
16def fd_count():
17 """Count the number of open file descriptors"""
18 if sys.platform.startswith(('linux', 'freebsd')):
19 try:
20 names = os.listdir("/proc/self/fd")
21 return len(names)
22 except FileNotFoundError:
23 pass
24
25 count = 0
26 for fd in range(MAXFD):
27 try:
28 # Prefer dup() over fstat(). fstat() can require input/output
29 # whereas dup() doesn't.
30 fd2 = os.dup(fd)
31 except OSError as e:
32 if e.errno != errno.EBADF:
33 raise
34 else:
35 os.close(fd2)
36 count += 1
37 return count
38
39
Victor Stinner3844fe52015-09-26 10:38:01 +020040def dash_R(the_module, test, indirect_test, huntrleaks):
41 """Run a test multiple times, looking for reference leaks.
42
43 Returns:
44 False if the test didn't leak references; True if we detected refleaks.
45 """
46 # This code is hackish and inelegant, but it seems to do the job.
47 import copyreg
48 import collections.abc
49
50 if not hasattr(sys, 'gettotalrefcount'):
51 raise Exception("Tracking reference leaks requires a debug build "
52 "of Python")
53
54 # Save current values for dash_R_cleanup() to restore.
55 fs = warnings.filters[:]
56 ps = copyreg.dispatch_table.copy()
57 pic = sys.path_importer_cache.copy()
58 try:
59 import zipimport
60 except ImportError:
61 zdc = None # Run unmodified on platforms without zipimport support
62 else:
63 zdc = zipimport._zip_directory_cache.copy()
64 abcs = {}
65 for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
66 if not isabstract(abc):
67 continue
68 for obj in abc.__subclasses__() + [abc]:
69 abcs[obj] = obj._abc_registry.copy()
70
71 nwarmup, ntracked, fname = huntrleaks
72 fname = os.path.join(support.SAVEDCWD, fname)
73 repcount = nwarmup + ntracked
74 rc_deltas = [0] * repcount
75 alloc_deltas = [0] * repcount
Victor Stinner076fc872015-10-03 00:20:56 +020076 fd_deltas = [0] * repcount
Victor Stinner3844fe52015-09-26 10:38:01 +020077
78 print("beginning", repcount, "repetitions", file=sys.stderr)
Victor Stinnerf33536c2015-09-30 00:48:27 +020079 print(("1234567890"*(repcount//10 + 1))[:repcount], file=sys.stderr,
80 flush=True)
Victor Stinner9a142142015-09-30 13:51:17 +020081 # initialize variables to make pyflakes quiet
Victor Stinner076fc872015-10-03 00:20:56 +020082 rc_before = alloc_before = fd_before = 0
Victor Stinner3844fe52015-09-26 10:38:01 +020083 for i in range(repcount):
84 indirect_test()
Victor Stinner076fc872015-10-03 00:20:56 +020085 alloc_after, rc_after, fd_after = dash_R_cleanup(fs, ps, pic, zdc,
86 abcs)
Victor Stinnerf33536c2015-09-30 00:48:27 +020087 print('.', end='', flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +020088 if i >= nwarmup:
89 rc_deltas[i] = rc_after - rc_before
90 alloc_deltas[i] = alloc_after - alloc_before
Victor Stinner076fc872015-10-03 00:20:56 +020091 fd_deltas[i] = fd_after - fd_before
92 alloc_before = alloc_after
93 rc_before = rc_after
94 fd_before = fd_after
Victor Stinner3844fe52015-09-26 10:38:01 +020095 print(file=sys.stderr)
96 # These checkers return False on success, True on failure
97 def check_rc_deltas(deltas):
98 return any(deltas)
99 def check_alloc_deltas(deltas):
100 # At least 1/3rd of 0s
101 if 3 * deltas.count(0) < len(deltas):
102 return True
103 # Nothing else than 1s, 0s and -1s
104 if not set(deltas) <= {1,0,-1}:
105 return True
106 return False
107 failed = False
108 for deltas, item_name, checker in [
109 (rc_deltas, 'references', check_rc_deltas),
Victor Stinner076fc872015-10-03 00:20:56 +0200110 (alloc_deltas, 'memory blocks', check_alloc_deltas),
111 (fd_deltas, 'file descriptors', check_rc_deltas)]:
Victor Stinner3844fe52015-09-26 10:38:01 +0200112 if checker(deltas):
113 msg = '%s leaked %s %s, sum=%s' % (
114 test, deltas[nwarmup:], item_name, sum(deltas))
Victor Stinnerf33536c2015-09-30 00:48:27 +0200115 print(msg, file=sys.stderr, flush=True)
Victor Stinner3844fe52015-09-26 10:38:01 +0200116 with open(fname, "a") as refrep:
117 print(msg, file=refrep)
118 refrep.flush()
119 failed = True
120 return failed
121
122
123def dash_R_cleanup(fs, ps, pic, zdc, abcs):
124 import gc, copyreg
125 import _strptime, linecache
126 import urllib.parse, urllib.request, mimetypes, doctest
127 import struct, filecmp, collections.abc
128 from distutils.dir_util import _path_created
129 from weakref import WeakSet
130
131 # Clear the warnings registry, so they can be displayed again
132 for mod in sys.modules.values():
133 if hasattr(mod, '__warningregistry__'):
134 del mod.__warningregistry__
135
136 # Restore some original values.
137 warnings.filters[:] = fs
138 copyreg.dispatch_table.clear()
139 copyreg.dispatch_table.update(ps)
140 sys.path_importer_cache.clear()
141 sys.path_importer_cache.update(pic)
142 try:
143 import zipimport
144 except ImportError:
145 pass # Run unmodified on platforms without zipimport support
146 else:
147 zipimport._zip_directory_cache.clear()
148 zipimport._zip_directory_cache.update(zdc)
149
150 # clear type cache
151 sys._clear_type_cache()
152
153 # Clear ABC registries, restoring previously saved ABC registries.
154 for abc in [getattr(collections.abc, a) for a in collections.abc.__all__]:
155 if not isabstract(abc):
156 continue
157 for obj in abc.__subclasses__() + [abc]:
158 obj._abc_registry = abcs.get(obj, WeakSet()).copy()
159 obj._abc_cache.clear()
160 obj._abc_negative_cache.clear()
161
162 # Flush standard output, so that buffered data is sent to the OS and
163 # associated Python objects are reclaimed.
164 for stream in (sys.stdout, sys.stderr, sys.__stdout__, sys.__stderr__):
165 if stream is not None:
166 stream.flush()
167
168 # Clear assorted module caches.
169 _path_created.clear()
170 re.purge()
171 _strptime._regex_cache.clear()
172 urllib.parse.clear_cache()
173 urllib.request.urlcleanup()
174 linecache.clearcache()
175 mimetypes._default_mime_types()
176 filecmp._cache.clear()
177 struct._clearcache()
178 doctest.master = None
179 try:
180 import ctypes
181 except ImportError:
182 # Don't worry about resetting the cache if ctypes is not supported
183 pass
184 else:
185 ctypes._reset_cache()
186
187 # Collect cyclic trash and read memory statistics immediately after.
188 func1 = sys.getallocatedblocks
189 func2 = sys.gettotalrefcount
190 gc.collect()
Victor Stinner076fc872015-10-03 00:20:56 +0200191 return func1(), func2(), fd_count()
Victor Stinner3844fe52015-09-26 10:38:01 +0200192
193
194def warm_caches():
195 # char cache
196 s = bytes(range(256))
197 for i in range(256):
198 s[i:i+1]
199 # unicode cache
Victor Stinner9a142142015-09-30 13:51:17 +0200200 [chr(i) for i in range(256)]
Victor Stinner3844fe52015-09-26 10:38:01 +0200201 # int cache
Victor Stinner9a142142015-09-30 13:51:17 +0200202 list(range(-5, 257))