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

monitor.py (34700B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\client\script\util\monitor.py
      2 from __future__ import print_function
      3 import gc
      4 import operator
      5 import sys
      6 import blue
      7 from carbonui.control.window import Window
      8 import log
      9 import trinity
     10 import uthread
     11 from carbon.common.script.util.format import HoursMinsSecsFromSecs, SecsFromBlueTimeDelta
     12 from carbon.common.script.sys import basesession, service, serviceConst
     13 from carbon.common.script.util import timerstuff
     14 from carbon.common.script.util.format import FmtAmt, FmtDate, FmtTime
     15 from carbonui import uiconst
     16 from carbonui.control.scrollentries import ScrollEntryNode, SE_GenericCore
     17 from carbonui.control.singlelineedits.singleLineEditInteger import SingleLineEditInteger
     18 from carbonui.primitives.container import Container
     19 from carbonui.primitives.line import Line
     20 from carbonui.uicore import uicore
     21 from carbonui.util.bunch import Bunch
     22 from eve.client.script.ui.control import eveLabel, eveScroll
     23 from carbonui.control import tabGroup
     24 from carbonui.button.group import ButtonGroup
     25 from carbonui.control.button import Button
     26 from carbonui.control.radioButton import RadioButton
     27 from eveprefs import prefs
     28 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     29 from pytelemetry import StartTelemetry
     30 from functools import reduce
     31 GRAPH_MEMORY = 1
     32 GRAPH_PERFORMANCE = 2
     33 GRAPH_HEAP = 3
     34 MAX_LOG_CAPACITY = 10000
     35 LOGTYPE_MAPPING = {0: ('info', '0xffeeeeee'),
     36  1: ('notice', '0xff22dd22'),
     37  2: ('warning', '0xffcccc00'),
     38  3: ('error', '0xffcc0000')}
     39 LOGUPDATETIME = 2000
     40 
     41 class Monitor(service.Service):
     42     __exportedcalls__ = {'Show': [],
     43      'ShowLogTab': []}
     44     __dependencies__ = ['settings']
     45     __update_on_reload__ = 0
     46     __guid__ = 'svc.monitor'
     47     __servicename__ = 'monitor'
     48     __displayname__ = 'Monitor Service'
     49 
     50     def Run(self, memStream = None):
     51         self.LogInfo('Starting MonitorSvc')
     52         self.started = False
     53         self.logRunning = False
     54         self.logSaveHandle = None
     55         self.lastLogEntry = None
     56 
     57     def UpdateHeapHistory(self):
     58         heaps = blue.MemoryTrackerGetAllProcessHeapsSizes()
     59         for i, h in enumerate(heaps):
     60             if i not in self.heaphistory:
     61                 self.heaphistory[i] = []
     62             self.heaphistory[i].append((blue.os.GetWallclockTime(), h))
     63 
     64     def Stop(self, memStream = None):
     65         if self.started:
     66             self.CleanUp()
     67 
     68     def Show(self):
     69         if not self.started:
     70             self.started = True
     71             self.CleanUp()
     72             self.ResetCounters()
     73             self.tabs = None
     74             self.heaphistory = {}
     75             if prefs.GetValue('heapinfo', 0):
     76                 self.heaphistorytimer = timerstuff.AutoTimer(1000, self.UpdateHeapHistory)
     77         wnd = self.GetWnd(1)
     78         if wnd is not None and not wnd.destroyed:
     79             wnd.Maximize()
     80             self.uitimer = timerstuff.AutoTimer(100, self.UpdateUI)
     81             self.graphtimer = timerstuff.AutoTimer(20000, self.UpdateGraph)
     82             self.heapgraphtimer = timerstuff.AutoTimer(20000, self.UpdateHeapGraph)
     83         wnd.sr.updateTimer = None
     84 
     85     def ShowOutstandingTab(self):
     86         self.Show()
     87         blue.pyos.synchro.SleepWallclock(500)
     88         tabName = 'Outstanding_tab'
     89         tab = self.tabs.sr.Get(tabName)
     90         tab.Select(1)
     91 
     92     def ShowLogTab(self):
     93         self.Show()
     94         blue.pyos.synchro.SleepWallclock(500)
     95         tabName = 'Logs_tab'
     96         tab = self.tabs.sr.Get(tabName)
     97         tab.Select(1)
     98 
     99     def _OnResize(self, *args):
    100         if self.tabs and self.tabs.GetSelectedArgs() in ('memory', 'performance', 'heap'):
    101             self.GetWnd().sr.updateTimer = timerstuff.AutoTimer(500, self.UpdateSize)
    102 
    103     def GetGraphMenu(self, *args):
    104         MEMORY_FILTERS = {'total_memory': 'Total Memory',
    105          'python_memory': 'Python Memory',
    106          'blue_memory': 'Blue Memory',
    107          'other_memory': 'Other Memory',
    108          'working_set': 'Working Set'}
    109         PERFORMANCE_FILTERS = {'fps': 'FPS',
    110          'thread_cpu': 'Thread CPU'}
    111         if self.GetGraphType() == GRAPH_PERFORMANCE:
    112             filters = PERFORMANCE_FILTERS
    113         elif self.GetGraphType() == GRAPH_MEMORY:
    114             filters = MEMORY_FILTERS
    115         else:
    116             return []
    117         m = []
    118         for name, label in filters.iteritems():
    119             m.append(('%s %s' % (['Show', 'Hide'][settings.user.ui.Get('monitor_setting_' + name, 1)], label), self.ToggleMemory, (name,)))
    120 
    121         m.append(None)
    122         m.append(('Time', self.MemoryTimeMenu()))
    123         return m
    124 
    125     def GetHeapGraphMenu(self, *args):
    126         m = []
    127         for k, v in self.heaphistory.iteritems():
    128             m.append(('%s %s' % (['Show', 'Hide'][settings.user.ui.Get('monitor_setting_heap_%s' % k, 1)], 'Heap #%s' % k), self.ToggleHeap, (k,)))
    129 
    130         m.append(None)
    131         return m
    132 
    133     def ToggleHeap(self, name):
    134         name = 'monitor_setting_heap_%s' % name
    135         curr = settings.user.ui.Get(name, 1)
    136         settings.user.ui.Set(name, not curr)
    137         uthread.new(self.GetHeapGraph)
    138 
    139     def ToggleMemory(self, name):
    140         name = 'monitor_setting_' + name
    141         curr = settings.user.ui.Get(name, 1)
    142         settings.user.ui.Set(name, not curr)
    143         uthread.new(self.GetGraph)
    144 
    145     def MemoryTimeMenu(self):
    146         m = []
    147         for i in [5,
    148          10,
    149          30,
    150          60,
    151          120,
    152          9999]:
    153             m.append(('last %s minutes' % i if i < 9999 else 'Since counter started', self.SetMemoryTime, (i,)))
    154 
    155         return m
    156 
    157     def SetMemoryTime(self, n):
    158         settings.user.ui.Set('monitor_setting_memory_time', n)
    159         uthread.new(self.GetGraph)
    160 
    161     def UpdateGraph(self):
    162         wnd = self.GetWnd()
    163         if wnd is not None and not wnd.destroyed and self.tabs and hasattr(self.tabs, 'GetSelectedArgs') and self.tabs.GetSelectedArgs() in ('memory', 'performance'):
    164             self.LogInfo('Updating memory graph')
    165             self.GetGraph()
    166 
    167     def UpdateHeapGraph(self):
    168         wnd = self.GetWnd()
    169         try:
    170             if wnd is not None and not wnd.destroyed and self.tabs and hasattr(self.tabs, 'GetSelectedArgs') and self.tabs.GetSelectedArgs() in ('heap',):
    171                 self.LogInfo('Updating heap graph')
    172                 self.GetHeapGraph()
    173         except:
    174             pass
    175 
    176     def UpdateSize(self):
    177         uthread.new(self.GetGraph)
    178         uthread.new(self.GetHeapGraph)
    179         self.GetWnd(1).sr.updateTimer = None
    180 
    181     def CleanUp(self):
    182         wnd = self.GetWnd()
    183         if wnd and not wnd.destroyed:
    184             wnd.CloseByUser()
    185         self.timer = None
    186         self.uitimer = None
    187         self.modeltimer = None
    188         self.graphtimer = None
    189         self.laststats = {}
    190         self.maxPeaks = {}
    191         self.lastresetstats = {}
    192         self.lastVM = None
    193         self.lastVMDelta = 0
    194         self.totalVMDelta = 0
    195         self.statsdiffs = {}
    196         self.showing = None
    197         self.settingsinited = 0
    198         self.pythonProfile = None
    199 
    200     def GetWnd(self, new = 0):
    201         wnd = MonitorWnd.GetIfOpen()
    202         if wnd is None and new:
    203             wnd = MonitorWnd.Open()
    204             wnd.OnClose = self.CloseWnd
    205             wnd._OnResize = self._OnResize
    206             main = wnd.sr.maincontainer
    207             topcontainer = Container(name='push', parent=main, align=uiconst.TOTOP, height=46, clipChildren=1)
    208             w = wnd.sr.telemetryButton = Button(parent=topcontainer, label='Telemetry', align=uiconst.TOPRIGHT, func=self.RunTelemetry)
    209             w = wnd.sr.fpsText = eveLabel.Label(text='', parent=topcontainer, align=uiconst.TOPLEFT, top=0, left=8)
    210             w = wnd.sr.vmText = eveLabel.Label(text='', parent=topcontainer, align=uiconst.TOPLEFT, top=14, left=8)
    211             w = wnd.sr.cacheText = eveLabel.Label(text='', parent=topcontainer, align=uiconst.TOPLEFT, top=28, left=8)
    212             self.tabs = tabGroup.TabGroup(parent=main)
    213             wnd.sr.scroll = eveScroll.Scroll(parent=main, padding=(const.defaultPadding,
    214              const.defaultPadding,
    215              const.defaultPadding,
    216              const.defaultPadding))
    217             wnd.sr.scroll.sr.id = 'monitorscroll'
    218             textonly = Container(name='textonly', parent=main, clipChildren=1, padding=8)
    219             graph = wnd.sr.graph = Container(name='graph', parent=main, clipChildren=1, padding=8)
    220             statusHeader = ' '
    221             for tme in self.intvals:
    222                 statusHeader += '<t><right>%s' % FmtDate(long(tme * 10000), 'ss')
    223 
    224             statusHeader += '<t><right>total'
    225             wnd.statusLabels = []
    226             txt = eveLabel.Label(text=statusHeader, parent=textonly, align=uiconst.TOPLEFT, tabs=[80,
    227              130,
    228              180,
    229              230,
    230              280,
    231              330,
    232              380], state=uiconst.UI_DISABLED)
    233             for i in xrange(7):
    234                 statusLabel = eveLabel.Label(text='', parent=textonly, top=(i + 1) * txt.height + 1, align=uiconst.TOPLEFT, tabs=[80,
    235                  130,
    236                  180,
    237                  230,
    238                  280,
    239                  330,
    240                  380], state=uiconst.UI_DISABLED)
    241                 wnd.statusLabels.append(statusLabel)
    242 
    243             wnd.sr.settings = Container(name='settings', parent=main, clipChildren=1, padding=8)
    244             w = wnd.sr.queueText = eveLabel.Label(text='', parent=wnd.sr.settings, align=uiconst.TOTOP)
    245             wnd.sr.settingsInner = Container(name='settingsInner', parent=wnd.sr.settings, align=uiconst.TOALL)
    246             tabs = [('Main',
    247               wnd.sr.settings,
    248               self,
    249               'settings'),
    250              ('Network',
    251               textonly,
    252               self,
    253               'network'),
    254              ('Rot',
    255               wnd.sr.scroll,
    256               self,
    257               'rot'),
    258              ('Timers',
    259               wnd.sr.scroll,
    260               self,
    261               'timers'),
    262              ('Objects',
    263               wnd.sr.scroll,
    264               self,
    265               'objects'),
    266              ('Memory',
    267               graph,
    268               self,
    269               'memory'),
    270              ('Performance',
    271               graph,
    272               self,
    273               'performance'),
    274              ('Outstanding',
    275               wnd.sr.scroll,
    276               self,
    277               'outstanding'),
    278              ('Logs',
    279               wnd.sr.scroll,
    280               self,
    281               'logs')]
    282             if prefs.GetValue('heapinfo', 0):
    283                 tabs.append(['Heap',
    284                  graph,
    285                  self,
    286                  'heap'])
    287             if session.role & serviceConst.ROLE_GML:
    288                 tabs.append(['Method Calls',
    289                  wnd.sr.scroll,
    290                  self,
    291                  'methodcalls'])
    292             tabData = []
    293             for label, panel, code, args in tabs:
    294                 tabData.append(Bunch(label=label, panel=panel, code=code, args=args, LoadTabCallback=self.Load))
    295 
    296             self.tabs.LoadTabs(tabData, 1, settingsID='monitortabs')
    297             wnd.sr.bottomCont = bottomCont = Container(parent=main, align=uiconst.TOBOTTOM, height=48, idx=0)
    298             wnd.sr.resetWnd = Container(name='resetwnd', parent=bottomCont, align=uiconst.TOTOP, height=24, idx=0)
    299             wnd.sr.logWnd = Container(name='logwnd', parent=bottomCont, align=uiconst.TOTOP, height=24, idx=0)
    300             wnd.sr.logWnd2 = Container(name='logwnd2', parent=bottomCont, align=uiconst.TOTOP, height=24, idx=0)
    301             btns = ButtonGroup(parent=wnd.sr.logWnd, line=False, btns=[['Start',
    302               self.StartLogInMemory,
    303               (),
    304               51],
    305              ['Stop',
    306               self.StopLogInMemory,
    307               (),
    308               51],
    309              ['Clear',
    310               self.ClearLogInMemory,
    311               (),
    312               51],
    313              ['Copy',
    314               self.ExportLogInMemory,
    315               (),
    316               51],
    317              ['Attach',
    318               self.AttachToLogServer,
    319               (),
    320               51],
    321              ['Save',
    322               self.SaveLogsToFile,
    323               (),
    324               51]])
    325             eveLabel.Label(parent=wnd.sr.logWnd2, text='<b>Threshold:</b>', align=uiconst.TOLEFT, padLeft=10, padTop=1)
    326             options = (('Info', 0),
    327              ('Notice', 1),
    328              ('Warning', 2),
    329              ('Error', 3))
    330             for text, value in options:
    331                 isChecked = blue.logInMemory.threshold == value
    332                 RadioButton(parent=wnd.sr.logWnd2, text=text, groupname='threshold', align=uiconst.TOLEFT, width=100, top=5, checked=isChecked, callback=self.OnLogThresholdRadioButtons, retval=value)
    333 
    334             edit = SingleLineEditInteger(parent=wnd.sr.logWnd2, name='capacityEdit', align=uiconst.TORIGHT, minvalue=1, maxValue=MAX_LOG_CAPACITY, padRight=5, padBottom=5, setvalue=blue.logInMemory.capacity, OnChange=self.OnLogCapacityEdit)
    335             eveLabel.Label(parent=wnd.sr.logWnd2, text='<b>Capacity:</b>', align=uiconst.TORIGHT, padLeft=10, padTop=1)
    336             wnd.sr.methodcallWnd = Container(name='methodcallwnd', parent=bottomCont, align=uiconst.TOTOP, height=24, idx=0)
    337             btns = ButtonGroup(btns=[['Copy',
    338               self.ExportMethodCalls,
    339               (),
    340               51]])
    341             wnd.sr.methodcallWnd.children.insert(0, btns)
    342             Line(parent=wnd.sr.resetWnd, align=uiconst.TOTOP)
    343             Button(parent=wnd.sr.resetWnd, label='Reset', align=uiconst.CENTER, func=self.Reset)
    344             wnd.SetMinSize([400, 300])
    345             wnd.Maximize(1)
    346             if not wnd.InStack():
    347                 wnd.SetParent(uicore.layer.abovemain)
    348         return wnd
    349 
    350     def Load(self, args, *arg):
    351         wnd = self.GetWnd()
    352         if wnd:
    353             wnd.sr.logWnd.state = uiconst.UI_HIDDEN
    354             wnd.sr.logWnd2.state = uiconst.UI_HIDDEN
    355             wnd.sr.resetWnd.state = uiconst.UI_HIDDEN
    356             wnd.sr.methodcallWnd.state = uiconst.UI_HIDDEN
    357             wnd.sr.bottomCont.height = 24
    358             self.timer = None
    359             if args == 'objects':
    360                 wnd.sr.resetWnd.state = uiconst.UI_NORMAL
    361                 self.GetObjects()
    362             elif args in ('memory', 'performance'):
    363                 blue.pyos.synchro.SleepWallclock(100)
    364                 self.GetGraph()
    365             elif args in ('heap',):
    366                 self.GetHeapGraph()
    367             elif args == 'network':
    368                 wnd.sr.resetWnd.state = uiconst.UI_NORMAL
    369                 self.UpdateData()
    370                 self.timer = timerstuff.AutoTimer(1000, self.UpdateData)
    371             elif args == 'rot':
    372                 wnd.sr.resetWnd.state = uiconst.UI_NORMAL
    373                 self.UpdateROT(force=True)
    374                 self.timer = timerstuff.AutoTimer(1000, self.UpdateROT)
    375             elif args == 'settings':
    376                 if not self.settingsinited:
    377                     self.LoadSettings()
    378                     self.settingsinited = 1
    379             elif args == 'timers':
    380                 wnd.sr.resetWnd.state = uiconst.UI_NORMAL
    381                 self.UpdateTimers()
    382                 self.timer = timerstuff.AutoTimer(2500, self.UpdateTimers)
    383             elif args == 'outstanding':
    384                 self.UpdateOutstanding()
    385                 self.timer = timerstuff.AutoTimer(100, self.UpdateOutstanding)
    386             elif args == 'methodcalls':
    387                 wnd.sr.methodcallWnd.state = uiconst.UI_NORMAL
    388                 self.UpdateMethodCalls()
    389                 self.timer = timerstuff.AutoTimer(2500, self.UpdateMethodCalls)
    390             elif args == 'logs':
    391                 self.ShowLogs()
    392             self.showing = args
    393 
    394     def ShowLogs(self):
    395         wnd = self.GetWnd()
    396         if wnd:
    397             wnd.sr.logWnd.state = uiconst.UI_NORMAL
    398             wnd.sr.logWnd2.state = uiconst.UI_NORMAL
    399             wnd.sr.bottomCont.height = 48
    400             wnd.sr.scroll.Load(contentList=[], headers=['#',
    401              'time',
    402              'channel',
    403              'type',
    404              'message'], fixedEntryHeight=18)
    405             self.lastLogEntry = None
    406             self.DoUpdateLogs()
    407 
    408     def LoadSettings(self):
    409         wnd = self.GetWnd()
    410         eveLabel.Label(text='<br><b>Debug Settings</b> (changing these settings is <b>not</b> recommended):', parent=wnd.sr.settingsInner, align=uiconst.TOTOP)
    411         if wnd:
    412             for cfgname, value, label, checked, group in [['userotcache',
    413               None,
    414               'Enable rot cache',
    415               settings.public.generic.Get('userotcache', 1),
    416               None],
    417              ['lazyLoading',
    418               None,
    419               'Enable Lazy model loading',
    420               settings.public.generic.Get('lazyLoading', 1),
    421               None],
    422              ['preload',
    423               None,
    424               'Enable Preloading',
    425               settings.public.generic.Get('preload', 1),
    426               None],
    427              ['asyncLoad',
    428               None,
    429               'Enable Asyncronous Loading (change requires reboot)',
    430               settings.public.generic.Get('asyncLoad', 1),
    431               None],
    432              ['resourceUnloading',
    433               None,
    434               'Enable Resource Unloading',
    435               settings.public.generic.Get('resourceUnloading', 1),
    436               None]]:
    437                 RadioButton(text=label, parent=wnd.sr.settingsInner, settingsKey=cfgname, retval=value, checked=checked, groupname=group, callback=self.CheckBoxChange, settingsPath=('generic',))
    438 
    439     def CheckBoxChange(self, checkbox, *args):
    440         config = checkbox.GetSettingsKey()
    441         if config == 'resourceUnloading':
    442             trinity.SetEveSpaceObjectResourceUnloadingEnabled(settings.public.generic.Get('resourceUnloading', 1))
    443 
    444     def RunTelemetry(self, *args):
    445         blue.synchro.SleepWallclock(5000)
    446         StartTelemetry()
    447         blue.synchro.SleepWallclock(20000)
    448         blue.statistics.StopTelemetry()
    449 
    450     def Reset(self, *args):
    451         self.ResetCounters()
    452         self.lastresetstats = sm.GetService('machoNet').GetConnectionProperties()
    453         self.laststats = {}
    454         self.rotinited = 0
    455         self.lastVM = None
    456         self.lastVMDelta = 0
    457         self.totalVMDelta = 0
    458         self.maxPeaks = {}
    459         self.typeBag = {}
    460 
    461     def ResetCounters(self, *args):
    462         self.intvals = [5000,
    463          10000,
    464          15000,
    465          30000,
    466          60000]
    467         self.counter = [[],
    468          [],
    469          [],
    470          [],
    471          [],
    472          []]
    473         self.ticker = 0
    474         self.packets_outTotal = 0
    475         self.packets_inTotal = 0
    476         self.bytes_outTotal = 0
    477         self.bytes_inTotal = 0
    478 
    479     def UpdateROT(self, force = False):
    480         wnd = self.GetWnd()
    481         if wnd:
    482             try:
    483                 rot = blue.classes.LiveCount()
    484                 if not getattr(self, 'rotinited', 0) or force:
    485                     scrolllist = []
    486                     for k, v in rot.iteritems():
    487                         scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, totalDelta=0, typeName=k, peakValue=v, lastValue=v, label='%s<t>%s<t>%s<t>%s' % (k,
    488                          0,
    489                          v,
    490                          v)))
    491 
    492                     wnd.sr.scroll.Load(contentList=scrolllist, headers=['type',
    493                      'delta',
    494                      'instances',
    495                      'peak'], fixedEntryHeight=18)
    496                     self.showing = 'rot'
    497                     self.rotinited = 1
    498                     return
    499                 for entry in wnd.sr.scroll.GetNodes():
    500                     v = rot[entry.typeName]
    501                     d = v - entry.lastValue
    502                     td = d + entry.totalDelta
    503                     entry.totalDelta = td
    504                     peak = self.maxPeaks.get(entry.typeName, -1)
    505                     p = max(peak, v)
    506                     self.maxPeaks[entry.typeName] = p
    507                     c = ['<color=0xff00ff00>', '<color=0xffff0000>'][td > 0]
    508                     entry.label = '%s<t>%s%s<color=0xffffffff><t>%s<t>%s' % (entry.typeName,
    509                      c,
    510                      td,
    511                      v,
    512                      p)
    513                     if entry.panel:
    514                         entry.panel.sr.label.text = entry.label
    515                     entry.lastValue = v
    516 
    517                 wnd.sr.scroll.RefreshSort()
    518             except:
    519                 self.timer = None
    520                 sys.exc_clear()
    521 
    522     def UpdateUI(self):
    523         wnd = self.GetWnd()
    524         if not wnd or wnd.destroyed:
    525             return
    526         virtualMem = blue.sysinfo.GetMemory().pageFile / 1024
    527         if self.lastVM is None:
    528             self.lastVM = virtualMem
    529         delta = virtualMem - self.lastVM
    530         self.totalVMDelta += delta
    531         self.lastVM = virtualMem
    532         delta = delta or self.lastVMDelta
    533         self.lastVMDelta = delta
    534         dc = ['<color=0xff00ff00>', '<color=0xffff0000>'][delta > 0]
    535         tdc = ['<color=0xff00ff00>', '<color=0xffff0000>'][self.totalVMDelta > 0]
    536         try:
    537             dev = trinity.device
    538             iml = ''
    539             if blue.logInMemory.isActive:
    540                 iml = 'In-memory logging <color=0xff00ff00>active</color> (%s / %s)' % (LOGTYPE_MAPPING.get(blue.logInMemory.threshold, ('Unknown', ''))[0], blue.logInMemory.capacity)
    541             fps = 'Fps: %.1f - %s' % (blue.os.fps, iml)
    542             if wnd.sr.fpsText.text != fps:
    543                 wnd.sr.fpsText.text = fps
    544             vm = 'VM Size/D/TD: %sK / %s%sK<color=0xffffffff> / %s%sK<color=0xffb0b0b0>' % (FmtAmt(virtualMem),
    545              dc,
    546              FmtAmt(delta),
    547              tdc,
    548              FmtAmt(self.totalVMDelta))
    549             if wnd.sr.vmText.text != vm:
    550                 wnd.sr.vmText.text = vm
    551             inUse = FmtAmt(blue.motherLode.memUsage / 1024)
    552             total = FmtAmt(blue.motherLode.maxMemUsage / 1024)
    553             num = blue.motherLode.size()
    554             vm = 'Resource Cache Usage: %sK / %sK - %s objects' % (inUse, total, num)
    555             if wnd.sr.cacheText.text != vm:
    556                 wnd.sr.cacheText.text = vm
    557             spaceMgr = sm.StartService('space')
    558             mo = 'Lazy Queue: %s' % getattr(spaceMgr, 'lazyLoadQueueCount', 0)
    559             if wnd.sr.queueText.text != mo:
    560                 wnd.sr.queueText.text = mo
    561         except Exception as e:
    562             print('e', e)
    563             self.uitimer = None
    564             sys.exc_clear()
    565 
    566     def GetTrace(self, item):
    567         trace = ''
    568         while item.parent:
    569             trace = '/' + item.name + trace
    570             item = item.parent
    571 
    572         return trace
    573 
    574     def UpdateTimers(self):
    575         wnd = self.GetWnd()
    576         if not wnd or wnd.destroyed:
    577             return
    578         scrolllist = []
    579         for timer in timerstuff.AutoTimer.autoTimers.iterkeys():
    580             label = str(timer.method)
    581             label = label[1:]
    582             label = label.split(' ')
    583             label = ' '.join(label[:3])
    584             scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, label='%s<t>%s<t>%s' % (label, timer.interval, timer.run)))
    585 
    586         wnd.sr.scroll.Load(contentList=scrolllist, headers=['method', 'interval', 'run'], fixedEntryHeight=18)
    587 
    588     def UpdateLogs(self):
    589         self.logRunning = True
    590         wnd = self.GetWnd()
    591         if wnd is None:
    592             return
    593         try:
    594             while 1:
    595                 loggingToWindow = not (not wnd or wnd.destroyed or self.tabs.GetSelectedArgs() != 'logs')
    596                 if not loggingToWindow and self.logSaveHandle is None or not self.logRunning:
    597                     return
    598                 self.DoUpdateLogs(loggingToWindow)
    599                 blue.pyos.synchro.SleepWallclock(LOGUPDATETIME)
    600 
    601         finally:
    602             self.logRunning = False
    603 
    604     def DoUpdateLogs(self, loggingToWindow = True):
    605         wnd = self.GetWnd()
    606         entries = blue.logInMemory.GetEntries()
    607         if entries:
    608             logsToFile = []
    609             scrolllist = []
    610             for i, e in enumerate(entries):
    611                 if e == self.lastLogEntry:
    612                     break
    613                 s = LOGTYPE_MAPPING.get(e[2], ('Unknown', '0xffeeeeee'))
    614                 lineno = 0
    615                 for line in e[4].split('\n'):
    616                     label = '%s<t>%s<t>%s::%s<t><color=%s>%s</color><t>%s' % (str(e[3] + lineno)[-15:],
    617                      FmtDate(e[3], 'nl'),
    618                      e[0],
    619                      e[1],
    620                      s[1],
    621                      s[0],
    622                      line.replace('<', '&lt;'))
    623                     scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, label=label))
    624                     lineno += 1
    625 
    626                 if self.logSaveHandle:
    627                     txt = '%s\t%s::%s\t%s\t%s\n' % (FmtDate(e[3], 'nl'),
    628                      e[0],
    629                      e[1],
    630                      s[0],
    631                      e[4])
    632                     logsToFile.append(txt)
    633 
    634             if self.logSaveHandle:
    635                 logsToFile.reverse()
    636                 for l in logsToFile:
    637                     self.logSaveHandle.Write(l)
    638 
    639             self.lastLogEntry = entries[0]
    640             if scrolllist and loggingToWindow:
    641                 wnd.sr.scroll.AddEntries(-1, scrolllist)
    642         if loggingToWindow:
    643             maxEntries = blue.logInMemory.capacity
    644             if len(wnd.sr.scroll.GetNodes()) > maxEntries:
    645                 wnd.sr.scroll.RemoveEntries(wnd.sr.scroll.GetNodes()[:-maxEntries])
    646 
    647     def StartLogInMemory(self):
    648         blue.logInMemory.Start()
    649         if not self.logRunning:
    650             uthread.new(self.UpdateLogs)
    651 
    652     def StopLogInMemory(self):
    653         blue.logInMemory.Stop()
    654         if self.logSaveHandle:
    655             self.logSaveHandle.Close()
    656             self.logSaveHandle = None
    657         self.logRunning = False
    658 
    659     def ClearLogInMemory(self):
    660         blue.logInMemory.Clear()
    661         self.StopLogInMemory()
    662         blue.pyos.synchro.SleepWallclock(LOGUPDATETIME * 2)
    663         self.StartLogInMemory()
    664 
    665     def OnLogThresholdRadioButtons(self, button):
    666         threshold = button.GetGroupValue()
    667         blue.logInMemory.threshold = int(threshold)
    668 
    669     def OnLogCapacityEdit(self, value):
    670         if value:
    671             blue.logInMemory.capacity = min(int(value), MAX_LOG_CAPACITY)
    672 
    673     def GetInMemoryLogs(self):
    674         txt = 'Time\tFacility\tType\tMessage\r\n'
    675         entries = blue.logInMemory.GetEntries()
    676         entries.reverse()
    677         for e in entries:
    678             s = LOGTYPE_MAPPING.get(e[2], ('Unknown', ''))
    679             for line in e[4].split('\n'):
    680                 try:
    681                     txt += '%s\t%s::%s\t%s\t%s\r\n' % (FmtDate(e[3], 'nl'),
    682                      e[0],
    683                      e[1],
    684                      s[0],
    685                      line)
    686                 except:
    687                     txt += '***Error writing out logline***\r\n'
    688 
    689         return txt
    690 
    691     def ExportLogInMemory(self, *args):
    692         blue.pyos.SetClipboardData(self.GetInMemoryLogs())
    693         prompt_player_fsd_dialog('CustomInfo', {'info': 'Logs copied to clipboard.'})
    694 
    695     def GetMethodCalls(self):
    696         txt = 'Time\tMethod\tDuration [ms]\n'
    697         entries = basesession.methodCallHistory
    698         for e in entries:
    699             txt += '%s\t%s\t%s\n' % (FmtDate(e[1], 'sl'), e[0], e[2] / const.MSEC)
    700 
    701         return txt
    702 
    703     def ExportMethodCalls(self, *args):
    704         blue.pyos.SetClipboardData(self.GetMethodCalls())
    705         prompt_player_fsd_dialog('CustomInfo', {'info': 'Method calls copied to clipboard.'})
    706 
    707     def AttachToLogServer(self):
    708         blue.AttachToLogServer()
    709         prompt_player_fsd_dialog('CustomInfo', {'info': 'Done attaching to Log Server.'})
    710 
    711     def SaveLogsToFile(self):
    712         filename = 'evelogs.log'
    713         self.logSaveHandle = blue.classes.CreateInstance('blue.ResFile')
    714         directory = blue.sysinfo.GetUserDocumentsDirectory() + '/EVE/logs/'
    715         path = directory + filename
    716         self.logSaveHandle.Create(path)
    717         if not self.logRunning:
    718             blue.logInMemory.Start()
    719             uthread.new(self.UpdateLogs)
    720         prompt_player_fsd_dialog('CustomInfo', {'info': 'Saving logs directly to file at %s' % path})
    721 
    722     def UpdateOutstanding(self):
    723         wnd = self.GetWnd()
    724         if not wnd or wnd.destroyed:
    725             return
    726         scrolllist = []
    727         for ct in basesession.outstandingCallTimers:
    728             method = ct[0]
    729             t = ct[1]
    730             label = '%s<t>%s<t>%s' % (method, FmtDate(t, 'nl'), FmtTime(blue.os.GetWallclockTimeNow() - t))
    731             scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, label=label))
    732 
    733         wnd.sr.scroll.Load(contentList=scrolllist, headers=['method', 'time', 'dt'])
    734 
    735     def UpdateMethodCalls(self):
    736         wnd = self.GetWnd()
    737         if not wnd or wnd.destroyed:
    738             return
    739         scrolllist = []
    740         history = list(basesession.methodCallHistory)
    741         history.reverse()
    742         for ct in history[:100]:
    743             method = ct[0]
    744             t = ct[1]
    745             label = '%s<t>%s<t>%s' % (method, FmtDate(t, 'nl'), ct[2] / const.MSEC)
    746             scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, label=label))
    747 
    748         wnd.sr.scroll.Load(contentList=scrolllist, headers=['method', 'time', 'ms'])
    749 
    750     def UpdateData(self):
    751         wnd = self.GetWnd()
    752         if not wnd or wnd.destroyed:
    753             return
    754         try:
    755             self.ticker += self.intvals[0]
    756             if self.ticker > self.intvals[-1]:
    757                 self.ticker = self.intvals[0]
    758             stats = sm.GetService('machoNet').GetConnectionProperties()
    759             if self.laststats == {}:
    760                 self.laststats = stats
    761             if self.lastresetstats != {}:
    762                 for key in stats.iterkeys():
    763                     stats[key] = stats[key] - self.lastresetstats[key]
    764 
    765             props = [('Packets out', 'packets_out', 0),
    766              ('Packets in', 'packets_in', 0),
    767              ('Kilobytes out', 'bytes_out', 1),
    768              ('Kilobytes in', 'bytes_in', 1)]
    769             for i in xrange(len(self.counter) - 1):
    770                 self.counter[i].append([ stats[key] - self.laststats[key] for header, key, K in props ])
    771                 self.counter[i] = self.counter[i][-(self.intvals[i] / 1000):]
    772 
    773             self.counter[-1].append([ stats[key] - self.laststats[key] for header, key, K in props ])
    774             if wnd.state != uiconst.UI_NORMAL:
    775                 self.laststats = stats
    776                 return
    777             valueIdx = 0
    778             for header, key, K in props:
    779                 statusstr = '%s' % header
    780                 for intvals in self.counter:
    781                     value = reduce(operator.add, [ intval[valueIdx] for intval in intvals ], 0)
    782                     if not value:
    783                         statusstr += '<t><right>-'
    784                     else:
    785                         statusstr += '<t><right>%s' % [value, '%.1f' % (value / 1024.0)][K]
    786 
    787                 wnd.statusLabels[valueIdx].text = statusstr
    788                 valueIdx += 1
    789 
    790             wnd.statusLabels[valueIdx].text = 'Outstanding<t><right>%s' % stats['calls_outstanding']
    791             valueIdx += 1
    792             wnd.statusLabels[valueIdx].text = 'Blocking Calls<t><right>%s' % stats['blocking_calls']
    793             valueIdx += 1
    794             block_time = stats['blocking_call_times']
    795             if block_time >= 0:
    796                 secs = SecsFromBlueTimeDelta(block_time)
    797                 wnd.statusLabels[valueIdx].text = 'Blocking time<t><right>%sH<t><right>%sM<t><right>%sS' % HoursMinsSecsFromSecs(secs)
    798             elif not hasattr(self, 'warnedBlockingTimeNegative'):
    799                 self.warnedBlockingTimeNegative = True
    800                 log.LogTraceback('Blocking time is negative?')
    801             self.laststats = stats
    802         except:
    803             self.timer = None
    804             raise
    805 
    806     def GetGraphType(self):
    807         if self.tabs and hasattr(self.tabs, 'GetSelectedArgs'):
    808             return {'memory': GRAPH_MEMORY,
    809              'performance': GRAPH_PERFORMANCE,
    810              'heap': GRAPH_HEAP}.get(self.tabs.GetSelectedArgs(), None)
    811 
    812     def GetObjects(self, num = 1000000, drill = None, textDrill = None, b = 0, e = 100):
    813         wnd = self.GetWnd()
    814         if not wnd or wnd.destroyed:
    815             return
    816         dict = {}
    817         import weakref
    818         for object in gc.get_objects():
    819             tp = type(object)
    820             if not isinstance(object, weakref.ProxyType):
    821                 try:
    822                     tp = object.__class__
    823                 except AttributeError:
    824                     sys.exc_clear()
    825 
    826             dict[tp] = dict.get(tp, 0) + 1
    827 
    828         dict2 = {}
    829         for k, v in dict.iteritems():
    830             n = k.__module__ + '.' + k.__name__
    831             dict2[n] = dict2.get(n, 0) + v
    832 
    833         scrolllist = []
    834         items = dict2.items()
    835         items.sort()
    836         for tp, inst in items:
    837             scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, OnDblClick=self.ClickEntry, instType=tp, label='%s<t>%s' % (tp, FmtAmt(inst))))
    838 
    839         wnd.sr.scroll.Load(contentList=scrolllist, headers=['type', 'instances'], fixedEntryHeight=18)
    840 
    841     def ClickEntry(self, entry, *args):
    842         typeName = entry.sr.node.instType.__name__
    843         inst = gc.get_objects()
    844         alldict = {}
    845         for object in inst:
    846             s = type(object)
    847             alldict.setdefault(s, []).append(object)
    848 
    849         attrs = {'BlueWrapper': ['__typename__', '__guid__'],
    850          'instance': ['__class__', '__guid__'],
    851          'class': ['__guid__', '__class__', '__repr__']}
    852         attr = attrs.get(typeName, None)
    853         if attr is None:
    854             return
    855         dict = {}
    856         for i in alldict[entry.sr.node.instType]:
    857             stringval = ''
    858             for a in attr:
    859                 stringval += str(getattr(i, a, None))[:24] + '<t>'
    860 
    861             dict.setdefault(stringval, []).append(i)
    862 
    863         scrolllist = []
    864         for tp, inst in dict.iteritems():
    865             if tp == 'None<t>' * len(attr):
    866                 continue
    867             scrolllist.append(ScrollEntryNode(decoClass=SE_GenericCore, label='%s%s' % (tp, FmtAmt(len(inst)))))
    868 
    869         wnd = self.GetWnd()
    870         if not wnd or wnd.destroyed:
    871             return
    872         wnd.wnd.sr.scroll.Load(contentList=scrolllist, headers=attr + ['instances'], fixedEntryHeight=18)
    873 
    874     def CloseWnd(self, *args):
    875         self.settingsinited = 0
    876         self.showing = None
    877         self.rotinited = 0
    878         self.uitimer = None
    879         self.modeltimer = None
    880         self.graphtimer = None
    881         self.timer = None
    882         self.lastVM = None
    883         self.lastVMDelta = 0
    884         self.totalVMDelta = 0
    885 
    886 
    887 class MonitorWnd(Window):
    888     default_windowID = 'MonitorWnd'
    889 
    890     def ApplyAttributes(self, attributes):
    891         super(MonitorWnd, self).ApplyAttributes(attributes)
    892         self.scope = uiconst.SCOPE_ALL
    893         self.SetCaption('Monitor')