--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/_gcdebug.py Thu Mar 11 16:49:07 2010 +0100
@@ -0,0 +1,87 @@
+
+import gc, types, weakref
+
+from cubicweb.schema import CubicWebRelationSchema, CubicWebEntitySchema
+
+listiterator = type(iter([]))
+
+IGNORE_CLASSES = (
+ type, tuple, dict, list, set, frozenset, type(len),
+ weakref.ref, weakref.WeakKeyDictionary,
+ listiterator,
+ property, classmethod,
+ types.ModuleType, types.FunctionType, types.MethodType,
+ types.MemberDescriptorType, types.GetSetDescriptorType,
+ )
+
+def _get_counted_class(obj, classes):
+ for cls in classes:
+ if isinstance(obj, cls):
+ return cls
+ raise AssertionError()
+
+def gc_info(countclasses,
+ ignoreclasses=IGNORE_CLASSES,
+ viewreferrersclasses=(), showobjs=False):
+ gc.collect()
+ gc.collect()
+ counters = {}
+ ocounters = {}
+ for obj in gc.get_objects():
+ if isinstance(obj, countclasses):
+ cls = _get_counted_class(obj, countclasses)
+ try:
+ counters[cls.__name__] += 1
+ except KeyError:
+ counters[cls.__name__] = 1
+ elif not isinstance(obj, ignoreclasses):
+ try:
+ key = '%s.%s' % (obj.__class__.__module__,
+ obj.__class__.__name__)
+ except AttributeError:
+ key = str(obj)
+ try:
+ ocounters[key] += 1
+ except KeyError:
+ ocounters[key] = 1
+ if isinstance(obj, viewreferrersclasses):
+ print ' ', obj, referrers(obj, showobjs)
+ return counters, ocounters, gc.garbage
+
+
+def referrers(obj, showobj=False, maxlevel=1):
+ objreferrers = _referrers(obj, maxlevel)
+ try:
+ return sorted(set((type(x), showobj and x or getattr(x, '__name__', '%#x' % id(x)))
+ for x in objreferrers))
+ except TypeError:
+ s = set()
+ unhashable = []
+ for x in objreferrers:
+ try:
+ s.add(x)
+ except TypeError:
+ unhashable.append(x)
+ return sorted(s) + unhashable
+
+def _referrers(obj, maxlevel, _seen=None, _level=0):
+ interesting = []
+ if _seen is None:
+ _seen = set()
+ for x in gc.get_referrers(obj):
+ if id(x) in _seen:
+ continue
+ _seen.add(id(x))
+ if isinstance(x, types.FrameType):
+ continue
+ if isinstance(x, (CubicWebRelationSchema, CubicWebEntitySchema)):
+ continue
+ if isinstance(x, (list, tuple, set, dict, listiterator)):
+ if _level >= maxlevel:
+ pass
+ #interesting.append(x)
+ else:
+ interesting += _referrers(x, maxlevel, _seen, _level+1)
+ else:
+ interesting.append(x)
+ return interesting
--- a/web/views/debug.py Thu Mar 11 16:48:38 2010 +0100
+++ b/web/views/debug.py Thu Mar 11 16:49:07 2010 +0100
@@ -130,3 +130,40 @@
for key, val in values])
else:
self.w(u'<p>Empty</p>\n')
+
+
+class GCView(StartupView):
+ """display garbage collector information"""
+ __regid__ = 'gc'
+ __select__ = StartupView.__select__ & match_user_groups('managers')
+ title = _('garbage')
+
+ def call(self, **kwargs):
+ from cubicweb._gcdebug import gc_info
+ from rql.stmts import Union
+ from cubicweb.appobject import AppObject
+ from cubicweb.rset import ResultSet
+ from cubicweb.dbapi import Connection, Cursor
+ from cubicweb.web.request import CubicWebRequestBase
+ lookupclasses = (AppObject,
+ Union, ResultSet,
+ Connection, Cursor,
+ CubicWebRequestBase)
+ try:
+ from cubicweb.server.session import Session, ChildSession, InternalSession
+ lookupclasses += (InternalSession, ChildSession, Session)
+ except ImportError:
+ pass # no server part installed
+ self.w(u'<h1>%s</h1>' % _('Garbage collection information'))
+ counters, ocounters, garbage = gc_info(lookupclasses,
+ viewreferrersclasses=())
+ self.w(u'<h3>%s</h3>' % _('Looked up classes'))
+ values = sorted(counters.iteritems(), key=lambda x: x[1], reverse=True)
+ self.wview('pyvaltable', pyvalue=values)
+ self.w(u'<h3>%s</h3>' % _('Most referenced classes'))
+ values = sorted(ocounters.iteritems(), key=lambda x: x[1], reverse=True)
+ self.wview('pyvaltable', pyvalue=values[:self._cw.form.get('nb', 20)])
+ if garbage:
+ self.w(u'<h3>%s</h3>' % _('Unreachable objects'))
+ values = sorted(xml_escape(repr(o) for o in garbage))
+ self.wview('pyvallist', pyvalue=values)