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('<', '<')) 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')