ObjectPool.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. """Contains the ObjectPool utility class."""
  2. __all__ = ['Diff', 'ObjectPool']
  3. from direct.directnotify.DirectNotifyGlobal import directNotify
  4. from direct.showbase.PythonUtil import invertDictLossless, makeList, safeRepr, itype
  5. from direct.showbase.PythonUtil import getNumberedTypedString, getNumberedTypedSortedString
  6. import gc
  7. class Diff:
  8. def __init__(self, lost, gained):
  9. self.lost = lost
  10. self.gained = gained
  11. def printOut(self, full=False):
  12. print('lost %s objects, gained %s objects' % (len(self.lost), len(self.gained)))
  13. print('\n\nself.lost\n')
  14. print(self.lost.typeFreqStr())
  15. print('\n\nself.gained\n')
  16. print(self.gained.typeFreqStr())
  17. if full:
  18. self.gained.printObjsByType()
  19. print('\n\nGAINED-OBJECT REFERRERS\n')
  20. self.gained.printReferrers(1)
  21. class ObjectPool:
  22. """manipulate a pool of Python objects"""
  23. notify = directNotify.newCategory('ObjectPool')
  24. def __init__(self, objects):
  25. self._objs = list(objects)
  26. self._type2objs = {}
  27. self._count2types = {}
  28. self._len2obj = {}
  29. type2count = {}
  30. for obj in self._objs:
  31. typ = itype(obj)
  32. type2count.setdefault(typ, 0)
  33. type2count[typ] += 1
  34. self._type2objs.setdefault(typ, [])
  35. self._type2objs[typ].append(obj)
  36. try:
  37. self._len2obj[len(obj)] = obj
  38. except Exception:
  39. pass
  40. self._count2types = invertDictLossless(type2count)
  41. def _getInternalObjs(self):
  42. return (self._objs, self._type2objs, self._count2types)
  43. def destroy(self):
  44. del self._objs
  45. del self._type2objs
  46. del self._count2types
  47. def getTypes(self):
  48. return list(self._type2objs.keys())
  49. def getObjsOfType(self, type):
  50. return self._type2objs.get(type, [])
  51. def printObjsOfType(self, type):
  52. for obj in self._type2objs.get(type, []):
  53. print(repr(obj))
  54. def diff(self, other):
  55. """print difference between this pool and 'other' pool"""
  56. thisId2obj = {}
  57. otherId2obj = {}
  58. for obj in self._objs:
  59. thisId2obj[id(obj)] = obj
  60. for obj in other._objs:
  61. otherId2obj[id(obj)] = obj
  62. thisIds = set(thisId2obj.keys())
  63. otherIds = set(otherId2obj.keys())
  64. lostIds = thisIds.difference(otherIds)
  65. gainedIds = otherIds.difference(thisIds)
  66. del thisIds
  67. del otherIds
  68. lostObjs = []
  69. for i in lostIds:
  70. lostObjs.append(thisId2obj[i])
  71. gainedObjs = []
  72. for i in gainedIds:
  73. gainedObjs.append(otherId2obj[i])
  74. return Diff(self.__class__(lostObjs), self.__class__(gainedObjs))
  75. def typeFreqStr(self):
  76. s = 'Object Pool: Type Frequencies'
  77. s += '\n============================='
  78. for count in sorted(self._count2types, reverse=True):
  79. types = makeList(self._count2types[count])
  80. for typ in types:
  81. s += '\n%s\t%s' % (count, typ)
  82. return s
  83. def printObjsByType(self):
  84. print('Object Pool: Objects By Type')
  85. print('\n============================')
  86. # print types with the smallest number of instances first, in case
  87. # there's a large group that waits a long time before printing
  88. #counts.reverse()
  89. for count in sorted(self._count2types):
  90. types = makeList(self._count2types[count])
  91. for typ in types:
  92. print('TYPE: %s, %s objects' % (repr(typ), len(self._type2objs[typ])))
  93. print(getNumberedTypedSortedString(self._type2objs[typ]))
  94. def printReferrers(self, numEach=3):
  95. """referrers of the first few of each type of object"""
  96. for count in sorted(self._count2types, reverse=True):
  97. types = makeList(self._count2types[count])
  98. for typ in types:
  99. print('\n\nTYPE: %s' % repr(typ))
  100. for i in range(min(numEach, len(self._type2objs[typ]))):
  101. obj = self._type2objs[typ][i]
  102. print('\nOBJ: %s\n' % safeRepr(obj))
  103. referrers = gc.get_referrers(obj)
  104. print('%s REFERRERS:\n' % len(referrers))
  105. if len(referrers) > 0:
  106. print(getNumberedTypedString(referrers, maxLen=80,
  107. numPrefix='REF'))
  108. else:
  109. print('<No Referrers>')
  110. def __len__(self):
  111. return len(self._objs)