mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
added task profiler
This commit is contained in:
parent
7ec03c1c3e
commit
6895e25221
@ -30,7 +30,8 @@ __all__ = ['enumerate', 'unique', 'indent', 'nonRepeatingRandomList',
|
|||||||
'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel', 'choice',
|
'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel', 'choice',
|
||||||
'printStack', 'printReverseStack', 'listToIndex2item', 'listToItem2index',
|
'printStack', 'printReverseStack', 'listToIndex2item', 'listToItem2index',
|
||||||
'pandaBreak','pandaTrace','formatTimeCompact','DestructiveScratchPad',
|
'pandaBreak','pandaTrace','formatTimeCompact','DestructiveScratchPad',
|
||||||
'deeptype',]
|
'deeptype','getProfileResultString','StdoutCapture','StdoutPassthrough',
|
||||||
|
'Averager',]
|
||||||
|
|
||||||
import types
|
import types
|
||||||
import string
|
import string
|
||||||
@ -794,12 +795,47 @@ def binaryRepr(number, max_length = 32):
|
|||||||
digits = digits [digits.index (1):]
|
digits = digits [digits.index (1):]
|
||||||
return string.join (map (repr, digits), '')
|
return string.join (map (repr, digits), '')
|
||||||
|
|
||||||
|
class StdoutCapture:
|
||||||
|
# redirects stdout to a string
|
||||||
|
def __init__(self):
|
||||||
|
self._oldStdout = sys.stdout
|
||||||
|
sys.stdout = self
|
||||||
|
self._string = ''
|
||||||
|
def destroy(self):
|
||||||
|
sys.stdout = self._oldStdout
|
||||||
|
del self._oldStdout
|
||||||
|
|
||||||
|
def getString(self):
|
||||||
|
return self._string
|
||||||
|
|
||||||
|
# internal
|
||||||
|
def write(self, string):
|
||||||
|
self._string = ''.join([self._string, string])
|
||||||
|
|
||||||
|
class StdoutPassthrough(StdoutCapture):
|
||||||
|
# like StdoutCapture but also allows output to go through to the OS as normal
|
||||||
|
|
||||||
|
# internal
|
||||||
|
def write(self, string):
|
||||||
|
self._string = ''.join([self._string, string])
|
||||||
|
self._oldStdout.write(string)
|
||||||
|
|
||||||
# constant profile defaults
|
# constant profile defaults
|
||||||
PyUtilProfileDefaultFilename = 'profiledata'
|
PyUtilProfileDefaultFilename = 'profiledata'
|
||||||
PyUtilProfileDefaultLines = 80
|
PyUtilProfileDefaultLines = 80
|
||||||
PyUtilProfileDefaultSorts = ['cumulative', 'time', 'calls']
|
PyUtilProfileDefaultSorts = ['cumulative', 'time', 'calls']
|
||||||
|
|
||||||
def profile(callback, name, terse):
|
_ProfileResultStr = ''
|
||||||
|
|
||||||
|
def getProfileResultString():
|
||||||
|
# if you called profile with 'log' not set to True,
|
||||||
|
# you can call this function to get the results as
|
||||||
|
# a string
|
||||||
|
global _ProfileResultStr
|
||||||
|
return _ProfileResultStr
|
||||||
|
|
||||||
|
def profile(callback, name, terse, log=True):
|
||||||
|
global _ProfileResultStr
|
||||||
import __builtin__
|
import __builtin__
|
||||||
if 'globalProfileFunc' in __builtin__.__dict__:
|
if 'globalProfileFunc' in __builtin__.__dict__:
|
||||||
# rats. Python profiler is not re-entrant...
|
# rats. Python profiler is not re-entrant...
|
||||||
@ -811,10 +847,20 @@ def profile(callback, name, terse):
|
|||||||
))
|
))
|
||||||
return
|
return
|
||||||
__builtin__.globalProfileFunc = callback
|
__builtin__.globalProfileFunc = callback
|
||||||
print '***** START PROFILE: %s *****' % name
|
__builtin__.globalProfileResult = [None]
|
||||||
startProfile(cmd='globalProfileFunc()', callInfo=(not terse))
|
prefix = '***** START PROFILE: %s *****' % name
|
||||||
print '***** END PROFILE: %s *****' % name
|
if log:
|
||||||
|
print prefix
|
||||||
|
startProfile(cmd='globalProfileResult[0]=globalProfileFunc()', callInfo=(not terse), silent=not log)
|
||||||
|
suffix = '***** END PROFILE: %s *****' % name
|
||||||
|
if log:
|
||||||
|
print suffix
|
||||||
|
else:
|
||||||
|
_ProfileResultStr = '%s\n%s\n%s' % (prefix, _ProfileResultStr, suffix)
|
||||||
|
result = globalProfileResult[0]
|
||||||
del __builtin__.__dict__['globalProfileFunc']
|
del __builtin__.__dict__['globalProfileFunc']
|
||||||
|
del __builtin__.__dict__['globalProfileResult']
|
||||||
|
return result
|
||||||
|
|
||||||
def profiled(category=None, terse=False):
|
def profiled(category=None, terse=False):
|
||||||
""" decorator for profiling functions
|
""" decorator for profiling functions
|
||||||
@ -883,12 +929,14 @@ def startProfile(filename=PyUtilProfileDefaultFilename,
|
|||||||
filename = '%s.%s' % (filename, randUint31())
|
filename = '%s.%s' % (filename, randUint31())
|
||||||
import profile
|
import profile
|
||||||
profile.run(cmd, filename)
|
profile.run(cmd, filename)
|
||||||
if not silent:
|
if silent:
|
||||||
|
extractProfile(filename, lines, sorts, callInfo)
|
||||||
|
else:
|
||||||
printProfile(filename, lines, sorts, callInfo)
|
printProfile(filename, lines, sorts, callInfo)
|
||||||
import os
|
import os
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
|
||||||
# call this to see the results again
|
# call these to see the results again, as a string or in the log
|
||||||
def printProfile(filename=PyUtilProfileDefaultFilename,
|
def printProfile(filename=PyUtilProfileDefaultFilename,
|
||||||
lines=PyUtilProfileDefaultLines,
|
lines=PyUtilProfileDefaultLines,
|
||||||
sorts=PyUtilProfileDefaultSorts,
|
sorts=PyUtilProfileDefaultSorts,
|
||||||
@ -903,6 +951,18 @@ def printProfile(filename=PyUtilProfileDefaultFilename,
|
|||||||
s.print_callees(lines)
|
s.print_callees(lines)
|
||||||
s.print_callers(lines)
|
s.print_callers(lines)
|
||||||
|
|
||||||
|
# same args as printProfile
|
||||||
|
def extractProfile(*args, **kArgs):
|
||||||
|
global _ProfileResultStr
|
||||||
|
# capture print output
|
||||||
|
sc = StdoutCapture()
|
||||||
|
# print the profile output, redirected to the result string
|
||||||
|
printProfile(*args, **kArgs)
|
||||||
|
# make a copy of the print output
|
||||||
|
_ProfileResultStr = sc.getString()
|
||||||
|
# restore stdout to what it was before
|
||||||
|
sc.destroy()
|
||||||
|
|
||||||
def getSetterName(valueName, prefix='set'):
|
def getSetterName(valueName, prefix='set'):
|
||||||
# getSetterName('color') -> 'setColor'
|
# getSetterName('color') -> 'setColor'
|
||||||
# getSetterName('color', 'get') -> 'getColor'
|
# getSetterName('color', 'get') -> 'getColor'
|
||||||
@ -927,8 +987,14 @@ class Functor:
|
|||||||
self._function = function
|
self._function = function
|
||||||
self._args = args
|
self._args = args
|
||||||
self._kargs = kargs
|
self._kargs = kargs
|
||||||
self.__name__ = self._function.__name__
|
if hasattr(self._function, '__name__'):
|
||||||
self.__doc__ = self._function.__doc__
|
self.__name__ = self._function.__name__
|
||||||
|
else:
|
||||||
|
self.__name__ = str(itype(self._function))
|
||||||
|
if hasattr(self._function, '__doc__'):
|
||||||
|
self.__doc__ = self._function.__doc__
|
||||||
|
else:
|
||||||
|
self.__doc__ = self.__name__
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
del self._function
|
del self._function
|
||||||
@ -1714,6 +1780,19 @@ def average(*args):
|
|||||||
val += arg
|
val += arg
|
||||||
return val / len(args)
|
return val / len(args)
|
||||||
|
|
||||||
|
class Averager:
|
||||||
|
def __init__(self, name):
|
||||||
|
self._name = name
|
||||||
|
self._total = 0.
|
||||||
|
self._count = 0
|
||||||
|
def addValue(self, value):
|
||||||
|
self._total += value
|
||||||
|
self._count += 1
|
||||||
|
def getAverage(self):
|
||||||
|
return self._total / self._count
|
||||||
|
def getCount(self):
|
||||||
|
return self._count
|
||||||
|
|
||||||
def addListsByValue(a, b):
|
def addListsByValue(a, b):
|
||||||
"""
|
"""
|
||||||
returns a new array containing the sums of the two array arguments
|
returns a new array containing the sums of the two array arguments
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user