ObjectReport.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. """
  2. >>> from direct.showbase import ObjectReport
  3. >>> o=ObjectReport.ObjectReport('baseline')
  4. >>> run()
  5. ...
  6. >>> o2=ObjectReport.ObjectReport('')
  7. >>> o.diff(o2)
  8. """
  9. __all__ = ['ExclusiveObjectPool', 'ObjectReport']
  10. from direct.directnotify.DirectNotifyGlobal import directNotify
  11. from direct.showbase import DirectObject, ObjectPool, GarbageReport
  12. from direct.showbase.PythonUtil import makeList, Sync
  13. import gc
  14. import sys
  15. import builtins
  16. class ExclusiveObjectPool(DirectObject.DirectObject):
  17. # ObjectPool specialization that excludes particular objects
  18. # IDs of objects to globally exclude from reporting
  19. _ExclObjs = []
  20. _ExclObjIds = {}
  21. _SyncMaster = Sync('ExclusiveObjectPool.ExcludedObjectList')
  22. _SerialNumGen = SerialNumGen()
  23. @classmethod
  24. def addExclObjs(cls, *objs):
  25. for obj in makeList(objs):
  26. if id(obj) not in cls._ExclObjIds:
  27. cls._ExclObjs.append(obj)
  28. cls._ExclObjIds.setdefault(id(obj), 0)
  29. cls._ExclObjIds[id(obj)] += 1
  30. cls._SyncMaster.change()
  31. @classmethod
  32. def removeExclObjs(cls, *objs):
  33. for obj in makeList(objs):
  34. assert id(obj) in cls._ExclObjIds
  35. cls._ExclObjIds[id(obj)] -= 1
  36. if cls._ExclObjIds[id(obj)] == 0:
  37. del cls._ExclObjIds[id(obj)]
  38. cls._ExclObjs.remove(obj)
  39. cls._SyncMaster.change()
  40. def __init__(self, objects):
  41. self._objects = list(objects)
  42. self._postFilterObjs = []
  43. self._sync = Sync('%s-%s' % (self.__class__.__name__,
  44. self._SerialNumGen.next()),
  45. self._SyncMaster)
  46. self._sync.invalidate()
  47. ExclusiveObjectPool.addExclObjs(self._objects, self._postFilterObjs,
  48. self._sync)
  49. def destroy(self):
  50. self.ignoreAll()
  51. ExclusiveObjectPool.removeExclObjs(self._objects, self._postFilterObjs,
  52. self._sync)
  53. del self._objects
  54. del self._postFilterObjs
  55. del self._sync
  56. def _resync(self):
  57. if self._sync.isSynced(self._SyncMaster):
  58. return
  59. if hasattr(self, '_filteredPool'):
  60. ExclusiveObjectPool.removeExclObjs(*self._filteredPool._getInternalObjs())
  61. ExclusiveObjectPool.removeExclObjs(self._filteredPool)
  62. del self._filteredPool
  63. del self._postFilterObjs[:]
  64. for obj in self._objects:
  65. if id(obj) not in ExclusiveObjectPool._ExclObjIds:
  66. self._postFilterObjs.append(obj)
  67. self._filteredPool = ExclusiveObjectPool(self._postFilterObjs)
  68. ExclusiveObjectPool.addExclObjs(self._filteredPool)
  69. ExclusiveObjectPool.addExclObjs(*self._filteredPool._getInternalObjs())
  70. self._sync.sync(self._SyncMaster)
  71. def getObjsOfType(self, type):
  72. self._resync()
  73. return self._filteredPool.getObjsOfType(type)
  74. def printObjsOfType(self, type):
  75. self._resync()
  76. return self._filteredPool.printObjsOfType(type)
  77. def diff(self, other):
  78. self._resync()
  79. return self._filteredPool.diff(other._filteredPool)
  80. def typeFreqStr(self):
  81. self._resync()
  82. return self._filteredPool.typeFreqStr()
  83. def __len__(self):
  84. self._resync()
  85. return len(self._filteredPool)
  86. class ObjectReport:
  87. """report on every Python object in the current process"""
  88. notify = directNotify.newCategory('ObjectReport')
  89. def __init__(self, name, log=True):
  90. gr = GarbageReport.GarbageReport('ObjectReport\'s GarbageReport: %s' % name, log=log)
  91. gr.destroy()
  92. del gr
  93. self._name = name
  94. self._pool = ObjectPool.ObjectPool(self._getObjectList())
  95. #ExclusiveObjectPool.addExclObjs(self, self._pool, self._name)
  96. if log:
  97. self.notify.info('===== ObjectReport: \'%s\' =====\n%s' % (self._name, self.typeFreqStr()))
  98. def destroy(self):
  99. #ExclusiveObjectPool.removeExclObjs(self, self._pool, self._name)
  100. self._pool.destroy()
  101. del self._pool
  102. del self._name
  103. def typeFreqStr(self):
  104. return self._pool.typeFreqStr()
  105. def diff(self, other):
  106. return self._pool.diff(other._pool)
  107. def getObjectPool(self):
  108. return self._pool
  109. def _getObjectList(self):
  110. if hasattr(sys, 'getobjects'):
  111. return sys.getobjects(0)
  112. else:
  113. gc.collect()
  114. # grab gc's object list
  115. gc_objects = gc.get_objects()
  116. # use get_referents to find everything else
  117. objects = gc_objects
  118. objects.append(builtins.__dict__)
  119. nextObjList = gc_objects
  120. found = set()
  121. found.add(id(objects))
  122. found.add(id(found))
  123. found.add(id(gc_objects))
  124. for obj in objects:
  125. found.add(id(obj))
  126. # repeatedly call get_referents until we can't find any more objects
  127. while len(nextObjList):
  128. curObjList = nextObjList
  129. nextObjList = []
  130. for obj in curObjList:
  131. refs = gc.get_referents(obj)
  132. for ref in refs:
  133. if id(ref) not in found:
  134. found.add(id(ref))
  135. objects.append(ref)
  136. nextObjList.append(ref)
  137. return objects
  138. """
  139. if hasattr(sys, 'getobjects'):
  140. return sys.getobjects(0)
  141. else:
  142. objs = []
  143. stateStack = Stack()
  144. root = builtins
  145. objIds = set([id(root)])
  146. stateStack.push((root, None, 0))
  147. while True:
  148. if len(stateStack) == 0:
  149. break
  150. obj, adjacents, resumeIndex = stateStack.pop()
  151. objs.append(obj)
  152. print id(obj)
  153. if adjacents is None:
  154. adjacents = gc.get_referents(obj)
  155. adjacents.extend(gc.get_referrers(obj))
  156. # pare the list down to the ones that have not already been visited
  157. # to minimize calls to get_referents/get_referrers
  158. newObjs = []
  159. for adj in adjacents:
  160. adjId = id(adj)
  161. if adjId not in objIds:
  162. objIds.add(adjId)
  163. newObjs.append(adj)
  164. adjacents = newObjs
  165. if len(adjacents) == 0:
  166. print 'DEAD END'
  167. for i in range(resumeIndex, len(adjacents)):
  168. adj = adjacents[i]
  169. stateStack.push((obj, adjacents, i+1))
  170. stateStack.push((adj, None, 0))
  171. continue
  172. """