_gcdebug.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 from __future__ import print_function
       
    19 
       
    20 import gc, types, weakref
       
    21 
       
    22 from cubicweb.schema import CubicWebRelationSchema, CubicWebEntitySchema
       
    23 try:
       
    24     from cubicweb.web.request import _NeedAuthAccessMock
       
    25 except ImportError:
       
    26     _NeedAuthAccessMock = None
       
    27 
       
    28 listiterator = type(iter([]))
       
    29 
       
    30 IGNORE_CLASSES = (
       
    31     type, tuple, dict, list, set, frozenset, type(len),
       
    32     weakref.ref, weakref.WeakKeyDictionary,
       
    33     listiterator,
       
    34     property, classmethod,
       
    35     types.ModuleType, types.FunctionType, types.MethodType,
       
    36     types.MemberDescriptorType, types.GetSetDescriptorType,
       
    37     )
       
    38 if _NeedAuthAccessMock is not None:
       
    39     IGNORE_CLASSES = IGNORE_CLASSES + (_NeedAuthAccessMock,)
       
    40 
       
    41 def _get_counted_class(obj, classes):
       
    42     for cls in classes:
       
    43         if isinstance(obj, cls):
       
    44             return cls
       
    45     raise AssertionError()
       
    46 
       
    47 def gc_info(countclasses,
       
    48             ignoreclasses=IGNORE_CLASSES,
       
    49             viewreferrersclasses=(), showobjs=False, maxlevel=1):
       
    50     gc.collect()
       
    51     gc.collect()
       
    52     counters = {}
       
    53     ocounters = {}
       
    54     for obj in gc.get_objects():
       
    55         if isinstance(obj, countclasses):
       
    56             cls = _get_counted_class(obj, countclasses)
       
    57             try:
       
    58                 counters[cls.__name__] += 1
       
    59             except KeyError:
       
    60                 counters[cls.__name__] = 1
       
    61         elif not isinstance(obj, ignoreclasses):
       
    62             try:
       
    63                 key = '%s.%s' % (obj.__class__.__module__,
       
    64                                  obj.__class__.__name__)
       
    65             except AttributeError:
       
    66                 key = str(obj)
       
    67             try:
       
    68                 ocounters[key] += 1
       
    69             except KeyError:
       
    70                 ocounters[key] = 1
       
    71         if isinstance(obj, viewreferrersclasses):
       
    72             print('   ', obj, referrers(obj, showobjs, maxlevel))
       
    73     garbage = [repr(obj) for obj in gc.garbage]
       
    74     return counters, ocounters, garbage
       
    75 
       
    76 
       
    77 def referrers(obj, showobj=False, maxlevel=1):
       
    78     objreferrers = _referrers(obj, maxlevel)
       
    79     try:
       
    80         return sorted(set((type(x), showobj and x or getattr(x, '__name__', '%#x' % id(x)))
       
    81                           for x in objreferrers))
       
    82     except TypeError:
       
    83         s = set()
       
    84         unhashable = []
       
    85         for x in objreferrers:
       
    86             try:
       
    87                 s.add(x)
       
    88             except TypeError:
       
    89                 unhashable.append(x)
       
    90         return sorted(s) + unhashable
       
    91 
       
    92 def _referrers(obj, maxlevel, _seen=None, _level=0):
       
    93     interesting = []
       
    94     if _seen is None:
       
    95         _seen = set()
       
    96     for x in gc.get_referrers(obj):
       
    97         if id(x) in _seen:
       
    98             continue
       
    99         _seen.add(id(x))
       
   100         if isinstance(x, types.FrameType):
       
   101             continue
       
   102         if isinstance(x, (CubicWebRelationSchema, CubicWebEntitySchema)):
       
   103             continue
       
   104         if isinstance(x, (list, tuple, set, dict, listiterator)):
       
   105             if _level >= maxlevel:
       
   106                 pass
       
   107                 #interesting.append(x)
       
   108             else:
       
   109                 interesting += _referrers(x, maxlevel, _seen, _level+1)
       
   110         else:
       
   111             interesting.append(x)
       
   112     return interesting