1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """
21 Debugging helper code
22 """
23
24
25 import gc
26 import sys
27 import re
28 import linecache
29 import types
30
31 from twisted.python.reflect import filenameToModuleName
32
33
34 _tracing = 0
35 _indent = ''
36
37 -def trace_start(func_filter=None, ignore_files_re=None, print_returns=False,
38 write=None):
39 global _tracing, _indent
40
41 if func_filter:
42 func_filter = re.compile(func_filter)
43
44 if ignore_files_re:
45 ignore_files_re = re.compile(ignore_files_re)
46
47 if not write:
48 def write(indent, str, *args):
49 print (indent + str) % args
50
51 def do_trace(frame, event, arg):
52 global _tracing, _indent
53
54 if not _tracing:
55 print '[tracing stopped]'
56 return None
57
58 co = frame.f_code
59
60 if event == 'line':
61 return do_trace
62 if func_filter and not func_filter.search(co.co_name):
63 return None
64 if ignore_files_re and ignore_files_re.search(co.co_filename):
65 return None
66 elif event == 'call' or event == 'c_call':
67 if co.co_name == '?':
68 return None
69 module = filenameToModuleName(co.co_filename)
70 write(_indent, '%s:%d:%s():', module, frame.f_lineno, co.co_name)
71 _indent += ' '
72 return do_trace
73 elif event == 'return' or event == 'c_return':
74 if print_returns:
75 write(_indent, 'return %r', arg)
76 _indent = _indent[:-2]
77 return None
78 elif event == 'exception' or event == 'c_exception':
79 if arg:
80 write(_indent, 'Exception: %s:%d: %s (%s)', co.co_filename,
81 frame.f_lineno, arg[0].__name__, arg[1])
82 else:
83 write(_indent, 'Exception: (from C)')
84 return do_trace
85 else:
86 write(_indent, 'unknown event: %s', event)
87 return None
88
89 _tracing += 1
90 if _tracing == 1:
91 assert _indent == ''
92 sys.settrace(do_trace)
93
101
103 f = sys._getframe(1)
104 output = []
105 while f:
106 co = f.f_code
107 filename = co.co_filename
108 lineno = f.f_lineno
109 name = co.co_name
110 linecache.checkcache(filename)
111 line = linecache.getline(filename, lineno)
112
113 if f.f_locals:
114 for k, v in f.f_locals.items():
115 output.append(' %s = %r\n' % (k, v))
116 output.append(' Locals:\n')
117 if line:
118 output.append(' %s\n' % line.strip())
119 output.append(' File "%s", line %d, in %s\n' % (filename,lineno,name))
120 f = f.f_back
121 output.reverse()
122 if file is None:
123 file = sys.stdout
124 for line in output:
125 file.write(line)
126
129 known = {}
130
131
132
133
134
135
136
137
138 from twisted.internet import reactor
139
140 def sample():
141 gc.collect()
142 for o in gc.garbage:
143 if o not in known:
144 known[o] = True
145 self.uncollectable(o)
146 reactor.callLater(period, sample)
147
148 reactor.callLater(period, sample)
149
151 print '\nUncollectable object cycle in gc.garbage:'
152
153 print "Parents:"
154 self._printParents(obj, 2)
155 print "Kids:"
156 self._printKids(obj, 2)
157
159 print indent, self._shortRepr(obj)
160 if level > 0:
161 for p in gc.get_referrers(obj):
162 self._printParents(p, level - 1, indent + ' ')
163
165 print indent, self._shortRepr(obj)
166 if level > 0:
167 for kid in gc.get_referents(obj):
168 self._printKids(kid, level - 1, indent + ' ')
169
171 if not isinstance(obj, dict):
172 return '%s %r @ 0x%x' % (type(obj).__name__, obj, id(obj))
173 else:
174 keys = obj.keys()
175 keys.sort()
176 return 'dict with keys %r @ 0x%x' % (keys, id(obj))
177
179 - def __init__(self, period=10, analyze=None, allocPrint=None):
180 self.period = period
181 self.objset = None
182
183 from sizer import scanner, annotate
184
185 from twisted.internet import reactor
186
187 if analyze is not None:
188 self.analyze = analyze
189 if allocPrint is not None:
190 self.allocPrint = allocPrint
191
192 def sample():
193 objset = scanner.Objects()
194 annotate.markparents(objset)
195
196 if self.objset:
197 self.analyze(self.objset, objset)
198
199 self.objset = objset
200 reactor.callLater(self.period, sample)
201
202 reactor.callLater(self.period, sample)
203
205 from sizer import operations
206
207 size = 0
208
209 for k in operations.diff(new, old):
210 size -= old[k].size
211
212 allocators = {}
213 diff = operations.diff(old, new)
214 for k in diff:
215 w = new[k]
216 size += w.size
217 if not w.parents:
218 print "Unreferenced object %r, what?" % (w,)
219 for p in w.parents:
220 if id(p.obj) == id(self.__dict__):
221 continue
222 if id(p.obj) not in diff:
223
224 if p not in allocators:
225 allocators[p] = []
226 allocators[p].append(w)
227 print "Total alloc size:", size
228 for p in allocators:
229 if p.obj == old or p.obj == new:
230 print 'foo'
231 else:
232 self.allocPrint(p, allocators[p])
233 for o in gc.garbage:
234 print '\nUncollectable object cycle in gc.garbage:'
235 self._printCycle(new[id(o)])
236
242
244 print indent, self._wrapperRepr(wrap)
245 if level > 0:
246 for p in wrap.parents:
247 self._printParents(p, level - 1, indent + ' ')
248
250 print indent, self._wrapperRepr(wrap)
251 if level > 0:
252 for kid in wrap.children:
253 self._printKids(kid, level - 1, indent + ' ')
254
256 stack.append(wrap)
257 for p in wrap.parents:
258 if (isinstance(p.obj, types.ModuleType)
259 or isinstance(p.obj, type)
260 or isinstance(p.obj, types.InstanceType)):
261 stack.append(p)
262 return stack
263 if len(wrap.parents) == 1:
264 return self._allocStack(wrap.parents[0], stack)
265 return stack
266
268 o = wrap.obj
269 if wrap.type != dict:
270 return '%s %r @ 0x%x' % (wrap.type.__name__, o, id(o))
271 else:
272 keys = o.keys()
273 keys.sort()
274 return 'dict with keys %r @ 0x%x' % (keys, id(o))
275
277 allocStack = self._allocStack(allocator, [])
278
279 print '\nAlloc by ' + self._wrapperRepr(allocStack.pop(0))
280 while allocStack:
281 print ' referenced by ' + self._wrapperRepr(allocStack.pop(0))
282
283 print "%d new %s:" % (len(directAllocs),
284 len(directAllocs) == 1 and "object" or "objects")
285 for wrap in directAllocs:
286 print ' ' + self._wrapperRepr(wrap)
287