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 |
|