traceref.py (11467B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\util\traceref.py 2 from __future__ import print_function 3 from __future__ import absolute_import 4 import gc 5 from . import inspect 6 import sys 7 import types 8 import stackless 9 import blue 10 11 def ObjectHistogram(deltaFrom = {}): 12 hist = {} 13 for obj in gc.get_objects(): 14 try: 15 objType = ClassOrType(obj) 16 except ReferenceError: 17 continue 18 19 hist[objType] = hist.get(objType, 0) + 1 20 21 for objType in set(hist).union(deltaFrom): 22 hist[objType] = hist.get(objType, 0) - deltaFrom.get(objType, 0) 23 24 report = _SortList([ (count, (objType, count)) for objType, count in hist.iteritems() ]) 25 report.reverse() 26 print('Histogram BEGIN -----------------------------------') 27 if deltaFrom: 28 print('(Delta from previous.)') 29 print('%s%20s' % ('Type', 'Count')) 30 for objType, count in report: 31 if count != 0: 32 print('%s%20s' % (objType, count)) 33 34 print('Histogram END -------------------------------------') 35 return hist 36 37 38 def GetLiveObjectsByTypeName(typeName): 39 ret = [] 40 for obj in gc.get_objects(): 41 try: 42 if typeName in ClassOrType(obj).__name__: 43 ret.append(obj) 44 except ReferenceError: 45 pass 46 47 return ret 48 49 50 def GetLiveObjectsByType(type_): 51 return [ obj for obj in gc.get_objects() if isinstance(obj, type_) ] 52 53 54 def _RawRefGraph(ob, ignore = (), depthLimit = None, breadthLimit = None): 55 56 def Ignore(*obs): 57 for ob in obs: 58 ignored.add(id(ob)) 59 60 def IgnoreFrame(f): 61 Ignore(f, f.f_locals) 62 63 def IgnoreCallStack(): 64 f = inspect.currentframe() 65 while f is not None: 66 IgnoreFrame(f) 67 f = f.f_back 68 69 def Graph(ob, depth = 0): 70 blue.pyos.BeNice() 71 if depthLimit is not None and depth > depthLimit: 72 return 73 IgnoreCallStack() 74 ret[id(ob)] = rfrs = [] 75 l = gc.get_referrers(ob) 76 Ignore(rfrs, l) 77 breadth = 0 78 for rfr in l: 79 if id(rfr) not in ignored: 80 breadth += 1 81 if breadthLimit is not None and breadth > breadthLimit: 82 return 83 rfrs.append(rfr) 84 if id(rfr) not in ret: 85 for type_ in [stackless.module, 86 stackless.modict, 87 stackless.frame, 88 stackless.function, 89 stackless.listiterator]: 90 if isinstance(rfr, type_): 91 break 92 else: 93 Graph(rfr, depth + 1) 94 95 ret = {} 96 ignored = set() 97 Ignore(ret, ignored, sys.modules['__main__'].__dict__, *ignore) 98 IgnoreFrame(inspect.currentframe()) 99 Graph(ob) 100 return ret 101 102 103 def TestRawRefGraph(): 104 105 class A: 106 pass 107 108 o = A() 109 d = {'a si': a} 110 a.dd = d 111 import pprint 112 pprint.pprint(_RawRefGraph(a)) 113 114 115 def TestAnnotatedRefGraph(verbose = False): 116 117 def ImportHack(name): 118 return sys.modules.setdefault(name, types.ModuleType(name)) 119 120 foo = ImportHack('foo') 121 bar = ImportHack('bar') 122 123 class Blah: 124 pass 125 126 o = Blah() 127 foo.o = o 128 foo.alias = o 129 o.self = o 130 p = bar.p = Blah() 131 p.oo = p.oOo = o 132 l = foo.l = [o, 'blah', o] 133 t = foo.t = (o, 'bleh', o) 134 d = bar.d = {'o si': o, 135 'o si also': o} 136 q = Blah() 137 q.o = o 138 m = [o] 139 u = (o,) 140 e = {'o': o} 141 die = False 142 143 def f(): 144 b = o 145 while not die: 146 blue.pyos.synchro.SleepWallclock(0) 147 148 import uthread 149 uthread.new(f) 150 blue.pyos.synchro.SleepWallclock(0) 151 try: 152 PrintRefPaths(o, verbose=verbose) 153 finally: 154 die = True 155 156 157 def PrintRefPaths(obj, ignore = (), verbose = False, depthLimit = None, breadthLimit = None): 158 159 class loop: 160 pass 161 162 def PathsFromRef(ref, prevPath = []): 163 newPath = prevPath + [ref] 164 if ref.refs: 165 ret = [] 166 for ref in ref.refs: 167 blue.pyos.BeNice() 168 if ref in newPath: 169 ret.append([ref, loop]) 170 else: 171 for path in PathsFromRef(ref, newPath): 172 ret.append([ref] + path) 173 174 return ret 175 else: 176 return [[]] 177 178 def PathStr(path): 179 rev = path 180 rev.reverse() 181 if rev[0] is loop: 182 prefix = ['(CYCLE)'] 183 rev = rev[1:] 184 else: 185 root = rev[0].obj 186 if isinstance(root, stackless.frame) or isinstance(root, stackless.function): 187 prefix = [] 188 elif isinstance(root, stackless.module): 189 prefix = [root.__name__] 190 elif isinstance(root, stackless.modict): 191 prefix = [root.__module__] 192 else: 193 prefix = ['<%s at %x>' % (ClassOrType(root).__name__, id(root))] 194 if verbose: 195 196 def fn(ref): 197 if ClassOrType(ref.obj) in (list, 198 tuple, 199 dict, 200 stackless.frame): 201 return ref.expr() 202 else: 203 typeName = getattr(ref.obj, '__guid__', ClassOrType(ref.obj).__name__) 204 return '(%s)%s' % (typeName, ref.expr()) 205 206 else: 207 fn = lambda ref: ref.expr() 208 return ''.join(prefix + [ fn(each) for each in rev ]) 209 210 refs = _AnnotatedRefGraph(obj, ignore, depthLimit, breadthLimit) 211 allPaths = [] 212 for ref in refs: 213 allPaths.extend([ [ref] + path for path in PathsFromRef(ref) ]) 214 215 pathStrs = map(PathStr, allPaths) 216 pathStrs.sort() 217 print('Paths are (in alphabetical order):') 218 for each in pathStrs: 219 print(' ', each) 220 221 del allPaths[:] 222 allPurged = set() 223 224 def PurgeRef(ref): 225 if id(ref) in allPurged: 226 return 227 allPurged.add(id(ref)) 228 map(PurgeRef, ref.refs) 229 del ref.refs[:] 230 231 map(PurgeRef, refs) 232 233 234 def _AnnotatedRefGraph(obj, ignore = (), depthLimit = None, breadthLimit = None): 235 handledAnnotations = {} 236 handledIndices = set() 237 238 def IndexHandled(obID, refID, categ, index): 239 ret = (obID, 240 refID, 241 categ, 242 index) in handledIndices 243 handledIndices.add((obID, 244 refID, 245 categ, 246 index)) 247 handledIndices.add((obID, 248 refID, 249 'unknown', 250 None)) 251 return ret 252 253 class Ref: 254 255 def __init__(self, obj, categ, index): 256 self.obj = obj 257 self.categ = categ 258 self.index = index 259 self.refs = handledAnnotations[id(obj)] 260 261 def __str__(self): 262 return 'Ref(%s, %s, <%s at %x>)' % (self.categ, 263 self.index, 264 ClassOrType(self.obj).__name__, 265 id(self.obj)) 266 267 def expr(self): 268 if self.categ == 'frame_local': 269 return "<local '%s' at %s:%s(%s)>" % (self.index, 270 self.obj.f_code.co_filename, 271 self.obj.f_code.co_firstlineno, 272 self.obj.f_code.co_name) 273 elif self.categ == 'func_closure': 274 return '<closed over at %s:%s(%s)>' % (self.obj.__code__.co_filename, self.obj.__code__.co_firstlineno, self.obj.__name__) 275 elif self.categ == 'attr': 276 return '.%s' % self.index 277 elif self.categ in ('seq', 'dict'): 278 return '[%r]' % self.index 279 else: 280 return '<%s>' % self 281 282 handledAnnotations[id(None)] = [] 283 omitted = Ref(None, 'omitted', None) 284 285 def FrameDetails(obj, rfr): 286 if not isinstance(rfr, stackless.frame): 287 return None 288 for name, val in rfr.f_locals.iteritems(): 289 if val is obj and not IndexHandled(id(obj), id(rfr), 'frame_local', name): 290 return (rfr, 'frame_local', name) 291 292 def FuncDetails(obj, rfr): 293 for rfrfr in GetRefs(rfr): 294 if isinstance(rfrfr, stackless.function): 295 for name, val in rfrfr.__dict__.iteritems(): 296 if val is obj and not IndexHandled(id(obj), id(rfrfr), 'func_dict', name): 297 return (rfrfr, 'func_dict', i) 298 299 elif isinstance(rfr, stackless.cell): 300 for rfrfrfr in GetRefs(rfrfr): 301 if isinstance(rfrfrfr, stackless.function): 302 for i, cell in enumerate(rfrfrfr.__closure__ or ()): 303 if cell is rfr and not IndexHandled(id(obj), id(rfrfrfr), 'func_closure', i): 304 IndexHandled(id(obj), id(rfr), 'seq', i) 305 return (rfrfrfr, 'func_closure', i) 306 307 def AttrDetails(obj, rfr): 308 if isinstance(rfr, stackless.modict): 309 ret = DictDetails(obj, rfr) 310 if ret is not None: 311 rfr, categ, index = ret 312 return (rfr, 'attr', index) 313 for rfrfr in GetRefs(rfr): 314 for name in dir(rfrfr): 315 try: 316 if getattr(rfrfr, name, None) is obj and not IndexHandled(id(obj), id(rfr), 'dict', name): 317 return (rfrfr, 'attr', name) 318 except TypeError: 319 sys.exc_clear() 320 321 def DictDetails(obj, rfr): 322 if not hasattr(rfr, 'iteritems'): 323 return None 324 for key, val in rfr.iteritems(): 325 if val is obj and not IndexHandled(id(obj), id(rfr), 'dict', key): 326 return (rfr, 'dict', key) 327 328 def SequenceDetails(obj, rfr): 329 try: 330 for i, val in enumerate(rfr): 331 if val is obj and not IndexHandled(id(obj), id(rfr), 'seq', i): 332 return (rfr, 'seq', i) 333 334 except TypeError: 335 try: 336 enumerate(rfr) 337 except TypeError: 338 sys.exc_clear() 339 return None 340 341 raise 342 343 def UnknownDetails(obj, rfr): 344 if not IndexHandled(id(obj), id(rfr), 'unknown', None): 345 return (rfr, 'unknown', None) 346 347 def NextAnnotation(obj, rfr): 348 for func in [FrameDetails, 349 FuncDetails, 350 AttrDetails, 351 DictDetails, 352 SequenceDetails, 353 UnknownDetails]: 354 ref = func(obj, rfr) 355 if ref is not None: 356 return ref 357 358 def AnnotateRefs(obj): 359 ret = [] 360 handledAnnotations[id(obj)] = [] 361 for rfr in GetRefs(obj): 362 while True: 363 next = NextAnnotation(obj, rfr) 364 if next is None: 365 break 366 ostensibleRfr, categ, index = next 367 if id(ostensibleRfr) not in handledAnnotations: 368 AnnotateRefs(ostensibleRfr) 369 ret.append(Ref(ostensibleRfr, categ, index)) 370 371 handledAnnotations[id(obj)].extend(ret) 372 return ret 373 374 raw = _RawRefGraph(obj, ignore, depthLimit, breadthLimit) 375 376 def GetRefs(obj): 377 return raw.get(id(obj), []) 378 379 try: 380 return AnnotateRefs(obj) 381 finally: 382 raw.clear() 383 384 385 def ClassOrType(obj): 386 return getattr(obj, '__class__', type(obj)) 387 388 389 def _SortList(lst): 390 lst.sort() 391 return [ item[1] for item in lst ] 392 393 394 import carbon.common.script.util.autoexport as autoexport 395 exports = autoexport.AutoExports('util', locals())