Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: third_party/cherrypy/lib/gctools.py

Issue 9368042: Add CherryPy to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build/
Patch Set: '' Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/cherrypy/lib/encoding.py ('k') | third_party/cherrypy/lib/http.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 import gc
2 import inspect
3 import os
4 import sys
5 import time
6
7 try:
8 import objgraph
9 except ImportError:
10 objgraph = None
11
12 import cherrypy
13 from cherrypy import _cprequest, _cpwsgi
14 from cherrypy.process.plugins import SimplePlugin
15
16
17 class ReferrerTree(object):
18 """An object which gathers all referrers of an object to a given depth."""
19
20 peek_length = 40
21
22 def __init__(self, ignore=None, maxdepth=2, maxparents=10):
23 self.ignore = ignore or []
24 self.ignore.append(inspect.currentframe().f_back)
25 self.maxdepth = maxdepth
26 self.maxparents = maxparents
27
28 def ascend(self, obj, depth=1):
29 """Return a nested list containing referrers of the given object."""
30 depth += 1
31 parents = []
32
33 # Gather all referrers in one step to minimize
34 # cascading references due to repr() logic.
35 refs = gc.get_referrers(obj)
36 self.ignore.append(refs)
37 if len(refs) > self.maxparents:
38 return [("[%s referrers]" % len(refs), [])]
39
40 try:
41 ascendcode = self.ascend.__code__
42 except AttributeError:
43 ascendcode = self.ascend.im_func.func_code
44 for parent in refs:
45 if inspect.isframe(parent) and parent.f_code is ascendcode:
46 continue
47 if parent in self.ignore:
48 continue
49 if depth <= self.maxdepth:
50 parents.append((parent, self.ascend(parent, depth)))
51 else:
52 parents.append((parent, []))
53
54 return parents
55
56 def peek(self, s):
57 """Return s, restricted to a sane length."""
58 if len(s) > (self.peek_length + 3):
59 half = self.peek_length // 2
60 return s[:half] + '...' + s[-half:]
61 else:
62 return s
63
64 def _format(self, obj, descend=True):
65 """Return a string representation of a single object."""
66 if inspect.isframe(obj):
67 filename, lineno, func, context, index = inspect.getframeinfo(obj)
68 return "<frame of function '%s'>" % func
69
70 if not descend:
71 return self.peek(repr(obj))
72
73 if isinstance(obj, dict):
74 return "{" + ", ".join(["%s: %s" % (self._format(k, descend=False),
75 self._format(v, descend=False))
76 for k, v in obj.items()]) + "}"
77 elif isinstance(obj, list):
78 return "[" + ", ".join([self._format(item, descend=False)
79 for item in obj]) + "]"
80 elif isinstance(obj, tuple):
81 return "(" + ", ".join([self._format(item, descend=False)
82 for item in obj]) + ")"
83
84 r = self.peek(repr(obj))
85 if isinstance(obj, (str, int, float)):
86 return r
87 return "%s: %s" % (type(obj), r)
88
89 def format(self, tree):
90 """Return a list of string reprs from a nested list of referrers."""
91 output = []
92 def ascend(branch, depth=1):
93 for parent, grandparents in branch:
94 output.append((" " * depth) + self._format(parent))
95 if grandparents:
96 ascend(grandparents, depth + 1)
97 ascend(tree)
98 return output
99
100
101 def get_instances(cls):
102 return [x for x in gc.get_objects() if isinstance(x, cls)]
103
104
105 class RequestCounter(SimplePlugin):
106
107 def start(self):
108 self.count = 0
109
110 def before_request(self):
111 self.count += 1
112
113 def after_request(self):
114 self.count -=1
115 request_counter = RequestCounter(cherrypy.engine)
116 request_counter.subscribe()
117
118
119 def get_context(obj):
120 if isinstance(obj, _cprequest.Request):
121 return "path=%s;stage=%s" % (obj.path_info, obj.stage)
122 elif isinstance(obj, _cprequest.Response):
123 return "status=%s" % obj.status
124 elif isinstance(obj, _cpwsgi.AppResponse):
125 return "PATH_INFO=%s" % obj.environ.get('PATH_INFO', '')
126 elif hasattr(obj, "tb_lineno"):
127 return "tb_lineno=%s" % obj.tb_lineno
128 return ""
129
130
131 class GCRoot(object):
132 """A CherryPy page handler for testing reference leaks."""
133
134 classes = [(_cprequest.Request, 2, 2,
135 "Should be 1 in this request thread and 1 in the main thread."),
136 (_cprequest.Response, 2, 2,
137 "Should be 1 in this request thread and 1 in the main thread."),
138 (_cpwsgi.AppResponse, 1, 1,
139 "Should be 1 in this request thread only."),
140 ]
141
142 def index(self):
143 return "Hello, world!"
144 index.exposed = True
145
146 def stats(self):
147 output = ["Statistics:"]
148
149 for trial in range(10):
150 if request_counter.count > 0:
151 break
152 time.sleep(0.5)
153 else:
154 output.append("\nNot all requests closed properly.")
155
156 # gc_collect isn't perfectly synchronous, because it may
157 # break reference cycles that then take time to fully
158 # finalize. Call it thrice and hope for the best.
159 gc.collect()
160 gc.collect()
161 unreachable = gc.collect()
162 if unreachable:
163 if objgraph is not None:
164 final = objgraph.by_type('Nondestructible')
165 if final:
166 objgraph.show_backrefs(final, filename='finalizers.png')
167
168 trash = {}
169 for x in gc.garbage:
170 trash[type(x)] = trash.get(type(x), 0) + 1
171 if trash:
172 output.insert(0, "\n%s unreachable objects:" % unreachable)
173 trash = [(v, k) for k, v in trash.items()]
174 trash.sort()
175 for pair in trash:
176 output.append(" " + repr(pair))
177
178 # Check declared classes to verify uncollected instances.
179 # These don't have to be part of a cycle; they can be
180 # any objects that have unanticipated referrers that keep
181 # them from being collected.
182 allobjs = {}
183 for cls, minobj, maxobj, msg in self.classes:
184 allobjs[cls] = get_instances(cls)
185
186 for cls, minobj, maxobj, msg in self.classes:
187 objs = allobjs[cls]
188 lenobj = len(objs)
189 if lenobj < minobj or lenobj > maxobj:
190 if minobj == maxobj:
191 output.append(
192 "\nExpected %s %r references, got %s." %
193 (minobj, cls, lenobj))
194 else:
195 output.append(
196 "\nExpected %s to %s %r references, got %s." %
197 (minobj, maxobj, cls, lenobj))
198
199 for obj in objs:
200 if objgraph is not None:
201 ig = [id(objs), id(inspect.currentframe())]
202 fname = "graph_%s_%s.png" % (cls.__name__, id(obj))
203 objgraph.show_backrefs(
204 obj, extra_ignore=ig, max_depth=4, too_many=20,
205 filename=fname, extra_info=get_context)
206 output.append("\nReferrers for %s (refcount=%s):" %
207 (repr(obj), sys.getrefcount(obj)))
208 t = ReferrerTree(ignore=[objs], maxdepth=3)
209 tree = t.ascend(obj)
210 output.extend(t.format(tree))
211
212 return "\n".join(output)
213 stats.exposed = True
214
OLDNEW
« no previous file with comments | « third_party/cherrypy/lib/encoding.py ('k') | third_party/cherrypy/lib/http.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698