| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- """
- >>> from direct.showbase import ObjectReport
- >>> o=ObjectReport.ObjectReport('baseline')
- >>> run()
- ...
- >>> o2=ObjectReport.ObjectReport('')
- >>> o.diff(o2)
- """
- __all__ = ['ExclusiveObjectPool', 'ObjectReport']
- from direct.directnotify.DirectNotifyGlobal import directNotify
- from direct.showbase import DirectObject, ObjectPool, GarbageReport
- from direct.showbase.PythonUtil import makeList, Sync
- import gc
- import sys
- import builtins
- class ExclusiveObjectPool(DirectObject.DirectObject):
- # ObjectPool specialization that excludes particular objects
- # IDs of objects to globally exclude from reporting
- _ExclObjs = []
- _ExclObjIds = {}
- _SyncMaster = Sync('ExclusiveObjectPool.ExcludedObjectList')
- _SerialNumGen = SerialNumGen()
- @classmethod
- def addExclObjs(cls, *objs):
- for obj in makeList(objs):
- if id(obj) not in cls._ExclObjIds:
- cls._ExclObjs.append(obj)
- cls._ExclObjIds.setdefault(id(obj), 0)
- cls._ExclObjIds[id(obj)] += 1
- cls._SyncMaster.change()
- @classmethod
- def removeExclObjs(cls, *objs):
- for obj in makeList(objs):
- assert id(obj) in cls._ExclObjIds
- cls._ExclObjIds[id(obj)] -= 1
- if cls._ExclObjIds[id(obj)] == 0:
- del cls._ExclObjIds[id(obj)]
- cls._ExclObjs.remove(obj)
- cls._SyncMaster.change()
- def __init__(self, objects):
- self._objects = list(objects)
- self._postFilterObjs = []
- self._sync = Sync('%s-%s' % (self.__class__.__name__,
- self._SerialNumGen.next()),
- self._SyncMaster)
- self._sync.invalidate()
- ExclusiveObjectPool.addExclObjs(self._objects, self._postFilterObjs,
- self._sync)
- def destroy(self):
- self.ignoreAll()
- ExclusiveObjectPool.removeExclObjs(self._objects, self._postFilterObjs,
- self._sync)
- del self._objects
- del self._postFilterObjs
- del self._sync
- def _resync(self):
- if self._sync.isSynced(self._SyncMaster):
- return
- if hasattr(self, '_filteredPool'):
- ExclusiveObjectPool.removeExclObjs(*self._filteredPool._getInternalObjs())
- ExclusiveObjectPool.removeExclObjs(self._filteredPool)
- del self._filteredPool
- del self._postFilterObjs[:]
- for obj in self._objects:
- if id(obj) not in ExclusiveObjectPool._ExclObjIds:
- self._postFilterObjs.append(obj)
- self._filteredPool = ExclusiveObjectPool(self._postFilterObjs)
- ExclusiveObjectPool.addExclObjs(self._filteredPool)
- ExclusiveObjectPool.addExclObjs(*self._filteredPool._getInternalObjs())
- self._sync.sync(self._SyncMaster)
- def getObjsOfType(self, type):
- self._resync()
- return self._filteredPool.getObjsOfType(type)
- def printObjsOfType(self, type):
- self._resync()
- return self._filteredPool.printObjsOfType(type)
- def diff(self, other):
- self._resync()
- return self._filteredPool.diff(other._filteredPool)
- def typeFreqStr(self):
- self._resync()
- return self._filteredPool.typeFreqStr()
- def __len__(self):
- self._resync()
- return len(self._filteredPool)
- class ObjectReport:
- """report on every Python object in the current process"""
- notify = directNotify.newCategory('ObjectReport')
- def __init__(self, name, log=True):
- gr = GarbageReport.GarbageReport('ObjectReport\'s GarbageReport: %s' % name, log=log)
- gr.destroy()
- del gr
- self._name = name
- self._pool = ObjectPool.ObjectPool(self._getObjectList())
- #ExclusiveObjectPool.addExclObjs(self, self._pool, self._name)
- if log:
- self.notify.info('===== ObjectReport: \'%s\' =====\n%s' % (self._name, self.typeFreqStr()))
- def destroy(self):
- #ExclusiveObjectPool.removeExclObjs(self, self._pool, self._name)
- self._pool.destroy()
- del self._pool
- del self._name
- def typeFreqStr(self):
- return self._pool.typeFreqStr()
- def diff(self, other):
- return self._pool.diff(other._pool)
- def getObjectPool(self):
- return self._pool
- def _getObjectList(self):
- if hasattr(sys, 'getobjects'):
- return sys.getobjects(0)
- else:
- gc.collect()
- # grab gc's object list
- gc_objects = gc.get_objects()
- # use get_referents to find everything else
- objects = gc_objects
- objects.append(builtins.__dict__)
- nextObjList = gc_objects
- found = set()
- found.add(id(objects))
- found.add(id(found))
- found.add(id(gc_objects))
- for obj in objects:
- found.add(id(obj))
- # repeatedly call get_referents until we can't find any more objects
- while len(nextObjList):
- curObjList = nextObjList
- nextObjList = []
- for obj in curObjList:
- refs = gc.get_referents(obj)
- for ref in refs:
- if id(ref) not in found:
- found.add(id(ref))
- objects.append(ref)
- nextObjList.append(ref)
- return objects
- """
- if hasattr(sys, 'getobjects'):
- return sys.getobjects(0)
- else:
- objs = []
- stateStack = Stack()
- root = builtins
- objIds = set([id(root)])
- stateStack.push((root, None, 0))
- while True:
- if len(stateStack) == 0:
- break
- obj, adjacents, resumeIndex = stateStack.pop()
- objs.append(obj)
- print id(obj)
- if adjacents is None:
- adjacents = gc.get_referents(obj)
- adjacents.extend(gc.get_referrers(obj))
- # pare the list down to the ones that have not already been visited
- # to minimize calls to get_referents/get_referrers
- newObjs = []
- for adj in adjacents:
- adjId = id(adj)
- if adjId not in objIds:
- objIds.add(adjId)
- newObjs.append(adj)
- adjacents = newObjs
- if len(adjacents) == 0:
- print 'DEAD END'
- for i in range(resumeIndex, len(adjacents)):
- adj = adjacents[i]
- stateStack.push((obj, adjacents, i+1))
- stateStack.push((adj, None, 0))
- continue
- """
|