NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

pythonobjects.py (16999B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\devtools\script\pythonobjects.py
      2 from __future__ import print_function
      3 import gc
      4 import weakref
      5 import sys
      6 import pprint
      7 import blue
      8 import log
      9 import stackless
     10 from carbon.common.script.sys.serviceConst import ROLE_QA
     11 from carbon.common.script.util.format import FmtDate
     12 from carbon.common.script.util.htmlwriter import Swing
     13 from carbonui import uiconst
     14 from carbonui.control.checkbox import Checkbox
     15 from carbonui.control.scrollentries import ScrollEntryNode, SE_GenericCore
     16 from carbonui.control.singlelineedits.singleLineEditText import SingleLineEditText
     17 from carbonui.primitives.base import Base
     18 from carbonui.primitives.container import Container
     19 from carbonui.primitives.containerAutoSize import ContainerAutoSize
     20 from carbonui.control.button import Button
     21 from eve.client.script.ui.control.eveLabel import EveLabelMedium
     22 from eve.client.script.ui.control.eveScroll import Scroll
     23 from carbonui.control.window import Window
     24 from pympler import asizeof
     25 
     26 def srepr(obj):
     27     try:
     28         return pprint.saferepr(obj)
     29     except:
     30         try:
     31             t = 'for type ' + type(obj).__name__
     32         except:
     33             t = "couldn't even get the typename!"
     34 
     35         return '[srepr failed %s]' % t
     36 
     37 
     38 def FindObjectByID(obID):
     39     obID = int(obID)
     40     objs = gc.get_objects()
     41     blue_objs = blue.classes.GetWrapperList()
     42     ob = None
     43     try:
     44         for ob in objs:
     45             if id(ob) == obID:
     46                 return (ob,)
     47 
     48         for ob in blue_objs:
     49             if id(ob) == obID:
     50                 return (ob,)
     51 
     52         return ()
     53     finally:
     54         del objs
     55         del ob
     56         del blue_objs
     57 
     58 
     59 def GetClassName(object):
     60     typeOrClass = type(object)
     61     if not isinstance(object, weakref.ProxyType):
     62         try:
     63             typeOrClass = object.__class__
     64         except (AttributeError, ReferenceError):
     65             sys.exc_clear()
     66 
     67     objectName = '%s.%s' % (typeOrClass.__module__, typeOrClass.__name__)
     68     return objectName
     69 
     70 
     71 class PythonObjectsMonitor(Window):
     72     default_caption = 'Python objects'
     73     default_windowID = 'pythonobjectsmonitor'
     74     default_minSize = (500, 400)
     75 
     76     def ApplyAttributes(self, attributes):
     77         self._ready = False
     78         Window.ApplyAttributes(self, attributes)
     79         self.settingsContainer = Container(parent=self.sr.main, align=uiconst.TOTOP, top=8, height=16, padding=8)
     80         self.filterEdit = SingleLineEditText(parent=self.settingsContainer, align=uiconst.TOLEFT, width=150, label='Filter:', OnReturn=self.PopulateScroll)
     81         Button(parent=self.settingsContainer, label='Reset', align=uiconst.TORIGHT, func=self.Reset, padRight=8)
     82         Button(parent=self.settingsContainer, label='Refresh', align=uiconst.TORIGHT, func=self.PopulateScroll, padRight=8)
     83         self.onlyUiCheckbox = Checkbox(parent=self.settingsContainer, text='Only UI  ', align=uiconst.TORIGHT, callback=self.PopulateScroll, padRight=20)
     84         self.scroll = Scroll(parent=self.sr.main, id='pythonobjectscroll', align=uiconst.TOALL)
     85         self.Reset()
     86         self._ready = True
     87 
     88     def Reset(self, *args):
     89         wnd = PythonObjectClassDetails.GetIfOpen()
     90         if wnd:
     91             wnd.Close()
     92         self.peakCount = {}
     93         self.baseCount = {}
     94         self.filterEdit.SetText('')
     95         self.PopulateScroll()
     96 
     97     def GetLabelForEntry(self, key, value):
     98         peak = self.peakCount.get(key, 0)
     99         delta = value - self.baseCount.get(key, 0)
    100         if delta < 0:
    101             color = '0xffff0000'
    102         else:
    103             color = '0xff00ff00'
    104         label = '%s<t><color=%s>%d</color><t>%d<t>%d' % (key,
    105          color,
    106          delta,
    107          value,
    108          peak)
    109         return (label, delta)
    110 
    111     def RebuildScrollContents(self, objects, filter, onlyShowUI):
    112         contentList = []
    113         newObjects = {}
    114         for k, v in objects.iteritems():
    115             if filter and filter not in k.lower():
    116                 continue
    117             newObjects[k] = v
    118 
    119         if onlyShowUI:
    120             isUiByClassName = self.GetIsUiDict(newObjects)
    121         else:
    122             isUiByClassName = {}
    123         for key, value in newObjects.iteritems():
    124             if onlyShowUI:
    125                 if not isUiByClassName[key]:
    126                     continue
    127             label, delta = self.GetLabelForEntry(key, value)
    128             listEntry = ScrollEntryNode(decoClass=SE_GenericCore, id=id, name=key, label=label, OnDblClick=self.ClassEntryDetails, OnGetMenu=self.EntryMenu)
    129             listEntry.Set('sort_Delta', delta)
    130             contentList.append(listEntry)
    131 
    132         self.scroll.Load(contentList=contentList, headers=['Name',
    133          'Delta',
    134          'Count',
    135          'Peak'])
    136 
    137     def GetIsUiDict(self, objects):
    138         activeObjects = gc.get_objects()
    139         myDict = {}
    140         for activeObject in activeObjects:
    141             objectName = GetClassName(activeObject)
    142             if objectName not in objects or objectName in myDict:
    143                 continue
    144             myDict[objectName] = isinstance(activeObject, Base)
    145 
    146         return myDict
    147 
    148     def EntryMenu(self, entry):
    149         if not session.role and ROLE_QA:
    150             return []
    151         m = [('Open Details', self.ClassEntryDetails, (entry,))]
    152         return m
    153 
    154     def ClassEntryDetails(self, entry, *args):
    155         if not session.role and ROLE_QA:
    156             return
    157         wnd = PythonObjectClassDetails.GetIfOpen()
    158         if wnd:
    159             wnd.SwitchItemClass(entry.name)
    160             wnd.Maximize()
    161         else:
    162             PythonObjectClassDetails.Open(itemClass=entry.name)
    163 
    164     def PopulateScroll(self, *args):
    165         objectsByType = {}
    166         for object in gc.get_objects():
    167             tp = type(object)
    168             if not isinstance(object, weakref.ProxyType):
    169                 try:
    170                     tp = object.__class__
    171                 except (AttributeError, ReferenceError):
    172                     sys.exc_clear()
    173 
    174             objectsByType[tp] = objectsByType.get(tp, 0) + 1
    175 
    176         objectsByModuleAndType = {}
    177         for k, v in objectsByType.iteritems():
    178             name = k.__module__ + '.' + k.__name__
    179             objectsByModuleAndType[name] = objectsByModuleAndType.get(name, 0) + v
    180 
    181         for key, value in objectsByModuleAndType.iteritems():
    182             peak = self.peakCount.get(key, 0)
    183             if value > peak:
    184                 self.peakCount[key] = value
    185             if key not in self.baseCount:
    186                 self.baseCount[key] = value
    187 
    188         filter = self.filterEdit.text.lower()
    189         onlyShowUi = self.onlyUiCheckbox.GetValue()
    190         self.RebuildScrollContents(objectsByModuleAndType, filter, onlyShowUi)
    191 
    192 
    193 class PythonObjectClassDetails(Window):
    194     default_caption = 'Python Object Class Details'
    195     default_windowID = 'pythonobjectclassdetails'
    196     default_minSize = (500, 400)
    197 
    198     def ApplyAttributes(self, attributes):
    199         self._ready = False
    200         Window.ApplyAttributes(self, attributes)
    201         self.maxLen = 250
    202         self.collectTimestamp = None
    203         self.itemClass = attributes.itemClass
    204         self.classDetailsContainer = ContainerAutoSize(parent=self.GetMainArea(), align=uiconst.TOTOP, padding=8)
    205         Button(parent=self.sr.main, label='GC and Refresh', align=uiconst.TOPRIGHT, func=self.GarbageCollectAndRefresh, padRight=8)
    206         self.scroll = Scroll(parent=self.sr.main, id='pythonobjectclassdetailscroll', align=uiconst.TOALL)
    207         self.ShowObjectDetail()
    208         self._ready = True
    209 
    210     def Close(self, setClosed = False, *args, **kwds):
    211         wnd = PythonObjectDetails.GetIfOpen()
    212         if wnd:
    213             wnd.Close()
    214         self.scroll = None
    215         self.classDetailsContainer = None
    216         Window.Close(self, setClosed, *args, **kwds)
    217 
    218     def GarbageCollectAndRefresh(self, *args):
    219         import gc
    220         self.scroll.Clear()
    221         self.classDetailsContainer.Flush()
    222         print('cleaned up: ', gc.collect())
    223         self.Refresh()
    224 
    225     def Refresh(self):
    226         self.scroll.Clear()
    227         self.classDetailsContainer.Flush()
    228         self.ShowObjectDetail()
    229 
    230     def SwitchItemClass(self, itemClass):
    231         if not self._ready:
    232             return
    233         wnd = PythonObjectDetails.GetIfOpen()
    234         if wnd:
    235             wnd.Close()
    236         self.itemClass = itemClass
    237         self._ready = False
    238         self.Refresh()
    239         self._ready = True
    240 
    241     def PopulateScroll(self, objectData, destroyedCountLabel):
    242         contentList = []
    243         destroyedCount = 0
    244         for i, obj in enumerate(objectData):
    245             objectName = self.GetObjectName(obj)
    246             parentName = getattr(getattr(obj, 'parent', None), 'name', '-')
    247             debugDisplayName = getattr(obj, 'debugDisplayName', None)
    248             if not debugDisplayName:
    249                 debugDisplayName = getattr(obj, 'name', ' - ')
    250             isDestroyed = getattr(obj, 'destroyed', 'N/A')
    251             if isDestroyed is True:
    252                 destroyedCount += 1
    253             label = '%s<t>%s<t>%s<t>%s' % (objectName,
    254              debugDisplayName,
    255              isDestroyed,
    256              parentName)
    257             listEntry = ScrollEntryNode(decoClass=SE_GenericCore, id=objectName, label=label, OnDblClick=self.EntryDetails, OnGetMenu=self.EntryMenu, refid=id(obj))
    258             contentList.append(listEntry)
    259             if i >= self.maxLen:
    260                 break
    261 
    262         self.scroll.Load(contentList=contentList, headers=['ObjectName',
    263          'debugDisplayName',
    264          'isDestroyed',
    265          'parentName(?)'])
    266         destroyedCountLabel.text = 'Destroyed count: %s' % destroyedCount
    267 
    268     def ShowObjectDetail(self):
    269         objectDetails = self.GetObjectDetails()
    270         classLabel = EveLabelMedium(name='classLabel', parent=self.classDetailsContainer, text='module.class: %s' % self.itemClass, align=uiconst.TOTOP)
    271         timeStamp = EveLabelMedium(name='timestamp', parent=self.classDetailsContainer, text='Collected at %s' % FmtDate(self.collectTimestamp), align=uiconst.TOTOP)
    272         oCount = len(objectDetails)
    273         countText = '%s Objects' % oCount
    274         if oCount > self.maxLen:
    275             countText += ', only first %s displayed' % self.maxLen
    276         objectCount = EveLabelMedium(name='oCount', parent=self.classDetailsContainer, text=countText, align=uiconst.TOTOP)
    277         destroyedCount = EveLabelMedium(name='destroyedCount', parent=self.classDetailsContainer, text='-', align=uiconst.TOTOP)
    278         self.PopulateScroll(objectDetails, destroyedCount)
    279 
    280     def EntryMenu(self, entry):
    281         m = [('Open Details', self.EntryDetails, (entry,))]
    282         return m
    283 
    284     def EntryDetails(self, entry):
    285         wnd = PythonObjectDetails.GetIfOpen()
    286         if wnd:
    287             wnd.Switch(entry.sr.node.refid)
    288             wnd.Maximize()
    289         else:
    290             PythonObjectDetails.Open(refid=entry.sr.node.refid)
    291 
    292     def GetObjectDetails(self):
    293         self.collectTimestamp = startTime = blue.os.GetWallclockTimeNow()
    294         activeObjects = gc.get_objects()
    295         blueObjects = blue.classes.GetWrapperList()
    296         objectDetails = []
    297         for activeObject in activeObjects:
    298             objectName = GetClassName(activeObject)
    299             if objectName == self.itemClass:
    300                 objectDetails.append(activeObject)
    301 
    302         for activeBlueObject in blueObjects:
    303             if activeBlueObject.__bluetype__ == self.itemClass:
    304                 objectDetails.append(activeBlueObject)
    305 
    306         endTime = blue.os.GetWallclockTimeNow()
    307         log.LogInfo('Finished fetching object details in %s Ms' % blue.os.TimeDiffInMs(startTime, endTime))
    308         return objectDetails
    309 
    310     def GetObjectName(self, object):
    311         try:
    312             className = object.__class__
    313         except AttributeError:
    314             className = object.__bluetype__
    315 
    316         objectName = '%s at 0x%.8x' % (className, id(object))
    317         objectName = '%s - Ref Count = %s - Size: %s' % (objectName, sys.getrefcount(object) - 4, asizeof.asizeof(object, limit=3))
    318         objectName = Swing(objectName)
    319         return objectName
    320 
    321 
    322 class PythonObjectDetails(Window):
    323     default_caption = 'Python Object Details'
    324     default_windowID = 'pythonobjectdetails'
    325     default_minSize = (400, 400)
    326 
    327     def ApplyAttributes(self, attributes):
    328         self._ready = False
    329         Window.ApplyAttributes(self, attributes)
    330         self.subWindow = None
    331         self.errorMessage = None
    332         self.objectRefID = attributes.refid
    333         self.object = self.GetObject()
    334         self.classDetailsContainer = ContainerAutoSize(parent=self.GetMainArea(), align=uiconst.TOTOP, padding=8)
    335         self.main = Container(name='main', parent=self.sr.main, align=uiconst.TOALL)
    336         self.ShowObjectDetail()
    337         self._ready = True
    338 
    339     def Close(self, setClosed = False, *args, **kwds):
    340         self.object = None
    341         wnd = PythonObjectDetails.GetIfOpen(windowID='pythonobjectdetails_sub_%s' % id(self.object))
    342         if wnd:
    343             wnd.Close()
    344         Window.Close(self, setClosed, *args, **kwds)
    345 
    346     def Refresh(self):
    347         self.scroll.Clear()
    348         self.classDetailsContainer.Flush()
    349         self.main.Flush()
    350         self.ShowObjectDetail()
    351 
    352     def Switch(self, refid):
    353         if not self._ready:
    354             return
    355         windowID = 'pythonobjectdetails_sub_%s' % id(self.object)
    356         wnd = PythonObjectDetails.GetIfOpen(windowID=windowID)
    357         if wnd:
    358             wnd.Close()
    359         self.errorMessage = None
    360         self.objectRefID = refid
    361         self.object = self.GetObject()
    362         self.Refresh()
    363         self._ready = True
    364 
    365     def ShowObjectDetail(self):
    366         self.listCont = Container(name='listCont', parent=self.main, align=uiconst.TOBOTTOM, height=140, padding=8)
    367         self.objRepr = Container(name='objRepr', parent=self.main, align=uiconst.TOALL, height=20, padding=8)
    368         className = GetClassName(self.object)
    369         objectName = self.GetObjectName(self.object)
    370         objectRepr = self.GetObjectRepr(self.object)
    371         objectSizes = self.GetObjectSizes(self.object)
    372         EveLabelMedium(parent=self.classDetailsContainer, text='Class name: %s' % className, align=uiconst.TOTOP, height=15)
    373         EveLabelMedium(parent=self.classDetailsContainer, text='Object name: %s' % objectName, align=uiconst.TOTOP, height=15)
    374         EveLabelMedium(parent=self.classDetailsContainer, text='Sizes: %s' % objectSizes, align=uiconst.TOTOP, height=20)
    375         EveLabelMedium(parent=self.objRepr, text='Repr: %s' % objectRepr, align=uiconst.TOALL)
    376         EveLabelMedium(parent=self.listCont, text='Incoming Refs:', align=uiconst.TOTOP, height=16)
    377         self.scroll = Scroll(parent=self.listCont, id='pythonobjectrefereesscroll', align=uiconst.TOALL)
    378         self.PopulateScroll()
    379 
    380     def GetObject(self):
    381         ob = FindObjectByID(self.objectRefID)
    382         if not ob:
    383             log.LogWarn('This Object could not be found %s' % self.objectRefID)
    384             return
    385         return ob[0]
    386 
    387     def GetObjectName(self, object):
    388         try:
    389             className = object.__class__
    390         except AttributeError:
    391             className = object.__bluetype__
    392 
    393         objectName = '%s at 0x%.8x' % (className, id(object))
    394         objectName = '%s - Ref Count = %s  - %s' % (objectName, sys.getrefcount(object) - 4, getattr(object, 'destroyed', 'N/A'))
    395         objectName = Swing(objectName)
    396         return objectName
    397 
    398     def GetObjectRepr(self, object):
    399         objectRepr = Swing(srepr(object))
    400         if len(objectRepr) < 1001:
    401             return objectRepr
    402         return objectRepr[:1000]
    403 
    404     def GetObjectSizes(self, object):
    405         sizes = [ asizeof.asizeof(object, limit=l) for l in range(8) ]
    406         return sizes
    407 
    408     def PopulateScroll(self):
    409         contentList = self.GetReferees()
    410         self.scroll.Load(contentList=contentList)
    411 
    412     def GetReferees(self):
    413         refList = []
    414         referrers = gc.get_referrers(self.object)
    415         known = [gc.garbage,
    416          stackless.getcurrent().frame,
    417          self.object,
    418          self.scroll,
    419          self.__dict__]
    420         for ref in referrers:
    421             if ref not in known:
    422                 try:
    423                     objectName = self.GetObjectName(ref)
    424                     refid = id(ref)
    425                     listEntry = ScrollEntryNode(decoClass=SE_GenericCore, id=id, name=objectName, label=objectName, OnDblClick=self.EntryDetails, OnGetMenu=self.EntryMenu, refid=refid)
    426                     refList.append(listEntry)
    427                 except Exception:
    428                     log.LogException('Invalid reference')
    429 
    430         return refList
    431 
    432     def EntryMenu(self, entry):
    433         m = [('Open Details', self.EntryDetails, (entry,))]
    434         return m
    435 
    436     def EntryDetails(self, entry):
    437         windowID = 'pythonobjectdetails_sub_%s' % id(self.object)
    438         wnd = PythonObjectDetails.GetIfOpen(windowID=windowID)
    439         if wnd:
    440             wnd.Switch(entry.sr.node.refid)
    441             wnd.Maximize()
    442         else:
    443             PythonObjectDetails.Open(refid=entry.sr.node.refid, windowID=windowID)