260 lines
7.4 KiB
Python
Executable File
260 lines
7.4 KiB
Python
Executable File
'''
|
|
Description:
|
|
Simple code profiling module, which generates a hierarchy of events and saves them to disk in xml form.
|
|
|
|
Author:
|
|
Jason Hayes <jason.hayes@rockstarsandiego.com>
|
|
'''
|
|
|
|
import os
|
|
import datetime
|
|
import xml.etree.cElementTree
|
|
import inspect
|
|
|
|
import RS.Config
|
|
|
|
from pyfbsdk import *
|
|
|
|
|
|
# Profile event stack.
|
|
__PROFILING_STACK = []
|
|
|
|
# Index of where we are in the stack.
|
|
__CURRENT_STACK_IDX = 0
|
|
|
|
# Whether or not the profiler is enabled.
|
|
ENABLED = True
|
|
|
|
# Profile event history directory.
|
|
PROFILE_DIR = '{0}\\profiler'.format( RS.Config.Script.Path.Root )
|
|
|
|
if not os.path.isdir( PROFILE_DIR ):
|
|
os.makedirs( PROFILE_DIR )
|
|
|
|
|
|
class ProfileEvent( object ):
|
|
'''
|
|
Description:
|
|
Container for a profile event. Records the start and stop time.
|
|
|
|
Author:
|
|
Jason Hayes <jason.hayes@rockstarsandiego.com>
|
|
|
|
Arguments:
|
|
context: A named string representing the profile event.
|
|
|
|
Keyword Arguments:
|
|
parentEvent: A parent profile event.
|
|
'''
|
|
|
|
def __init__( self, context, parentEvent = None, totalTime = 0.0 ):
|
|
self.__parentEvent = parentEvent
|
|
|
|
self.__context = context
|
|
self.__start = datetime.datetime.now()
|
|
self.__end = None
|
|
self.__subEvents = []
|
|
self.__totalTime = totalTime
|
|
|
|
|
|
## Properties ##
|
|
|
|
@property
|
|
def context( self ):
|
|
return self.__context
|
|
|
|
@property
|
|
def subEvents( self ):
|
|
return self.__subEvents
|
|
|
|
@property
|
|
def totalTime( self ):
|
|
return self.__totalTime
|
|
|
|
|
|
## Methods ##
|
|
|
|
def addSubEvent( self, event ):
|
|
self.__subEvents.append( event )
|
|
|
|
def stop( self ):
|
|
self.__end = datetime.datetime.now()
|
|
totalTime = self.__end - self.__start
|
|
|
|
self.__totalTime = '{0}.{1}'.format( totalTime.seconds, totalTime.microseconds )
|
|
|
|
def printResult( self ):
|
|
print '{0}: {1} seconds'.format( self.__context, self.totalTime )
|
|
|
|
|
|
def start( context, parentEvent = None ):
|
|
'''
|
|
Description:
|
|
Starts a new profile event.
|
|
|
|
Author:
|
|
Jason Hayes <jason.hayes@rockstarsandiego.com>
|
|
|
|
Arguments:
|
|
context: A named string representing the profiled event.
|
|
|
|
Returns:
|
|
The started ProfileEvent object.
|
|
'''
|
|
|
|
global __PROFILING_STACK
|
|
global __CURRENT_STACK_IDX
|
|
global ENABLED
|
|
|
|
if ENABLED:
|
|
event = None
|
|
|
|
currentFrame = inspect.currentframe()
|
|
callerLineNo = currentFrame.f_back.f_lineno
|
|
callerCodeFilename = currentFrame.f_back.f_code.co_filename
|
|
|
|
if parentEvent:
|
|
event = ProfileEvent( context, parentEvent = parentEvent )
|
|
parentEvent.addSubEvent( event )
|
|
|
|
else:
|
|
event = ProfileEvent( context )
|
|
|
|
__PROFILING_STACK.append( event )
|
|
__CURRENT_STACK_IDX += 1
|
|
|
|
return event
|
|
|
|
return None
|
|
|
|
def stop( printResult = False ):
|
|
'''
|
|
Description:
|
|
Stops the current profile event on the stack.
|
|
|
|
Author:
|
|
Jason Hayes <jason.hayes@rockstarsandiego.com>
|
|
|
|
Keyword Arguments:
|
|
printResult: Boolean of whether or not to print out the result of the profiled event.
|
|
'''
|
|
|
|
global __PROFILING_STACK
|
|
global __CURRENT_STACK_IDX
|
|
global ENABLED
|
|
|
|
if ENABLED:
|
|
if __CURRENT_STACK_IDX > 0:
|
|
__CURRENT_STACK_IDX -= 1
|
|
|
|
event = __PROFILING_STACK[ __CURRENT_STACK_IDX ]
|
|
event.stop()
|
|
|
|
if printResult:
|
|
event.printResult()
|
|
|
|
# Write the current profile event history to disk.
|
|
if __CURRENT_STACK_IDX == 0:
|
|
saveProfileEvents()
|
|
|
|
__PROFILING_STACK.pop( __CURRENT_STACK_IDX )
|
|
|
|
def getTabs( tabLevel ):
|
|
tabStr = ''
|
|
|
|
for i in range( 0, tabLevel ):
|
|
tabStr += '\t'
|
|
|
|
return tabStr
|
|
|
|
def recurseWriteEvents( event, xmlDoc, tabLevel ):
|
|
tabLevel += 1
|
|
|
|
for event in event.subEvents:
|
|
xmlDoc.write( '{0}<event context="{1}" totalTime="{2}">\n'.format( getTabs( tabLevel ), event.context, event.totalTime ) )
|
|
|
|
if event.subEvents:
|
|
recurseWriteEvents( event, xmlDoc, tabLevel )
|
|
|
|
xmlDoc.write( '{0}</event>\n'.format( getTabs( tabLevel ) ) )
|
|
|
|
tabLevel -= 1
|
|
|
|
def saveProfileEvents():
|
|
global __PROFILING_STACK
|
|
global PROFILE_DIR
|
|
global LOG_AS_MICROSECONDS
|
|
|
|
tabLevel = 0
|
|
topEvent = __PROFILING_STACK[ 0 ]
|
|
|
|
writeTime = datetime.datetime.now()
|
|
doc = open( '{0}\\{1}_{2}{3}{4}{5}{6}{7}{8}.xml'.format( PROFILE_DIR, topEvent.context, writeTime.day, writeTime.month, writeTime.year, writeTime.hour, writeTime.minute, writeTime.second, writeTime.microsecond ), 'w' )
|
|
|
|
doc.write( '<?xml version="1.0" encoding="utf-8"?>\n' )
|
|
doc.write( '<root>\n' )
|
|
|
|
tabLevel += 1
|
|
|
|
doc.write( '{0}<info>\n'.format( getTabs( tabLevel ) ) )
|
|
|
|
tabLevel += 1
|
|
|
|
doc.write( '{0}<fbxFilename>{1}</fbxFilename>\n'.format( getTabs( tabLevel ), FBApplication().FBXFileName ) )
|
|
doc.write( '{0}<username>{1}</username>\n'.format( getTabs( tabLevel ), RS.Config.User.Name ) )
|
|
|
|
tabLevel -= 1
|
|
|
|
doc.write( '{0}</info>\n'.format( getTabs( tabLevel ) ) )
|
|
doc.write( '{0}<event context="{1}" totalTime="{2}">\n'.format( getTabs( tabLevel ), topEvent.context, topEvent.totalTime ) )
|
|
|
|
recurseWriteEvents( topEvent, doc, tabLevel )
|
|
|
|
doc.write( '{0}</event>\n'.format( getTabs( tabLevel ) ) )
|
|
doc.write( '</root>\n' )
|
|
|
|
doc.close()
|
|
|
|
def loadProfileEvents( filename ):
|
|
events = []
|
|
|
|
def recurseReadXmlEvents( xmlRoot, parentEvent ):
|
|
eventNodes = xmlRoot.findall( 'event' )
|
|
|
|
for eventNode in eventNodes:
|
|
context = eventNode.get( 'context' )
|
|
totalTime = eventNode.get( 'totalTime' )
|
|
|
|
event = ProfileEvent( context, parentEvent, totalTime = totalTime )
|
|
parentEvent.addSubEvent( event )
|
|
|
|
recurseReadXmlEvents( eventNode, event )
|
|
|
|
if os.path.isfile( filename ):
|
|
doc = xml.etree.cElementTree.parse( filename )
|
|
root = doc.getroot()
|
|
|
|
if root:
|
|
infoRoot = root.find( 'info' )
|
|
|
|
if infoRoot:
|
|
fbxFilename = infoRoot.find( 'fbxFilename' )
|
|
username = infoRoot.find( 'username' )
|
|
|
|
rootEventNodes = root.findall( 'event' )
|
|
|
|
for rootEventNode in rootEventNodes:
|
|
context = rootEventNode.get( 'context' )
|
|
totalTime = rootEventNode.get( 'totalTime' )
|
|
|
|
event = ProfileEvent( context, totalTime = totalTime )
|
|
events.append( event )
|
|
|
|
recurseReadXmlEvents( rootEventNode, event )
|
|
|
|
return events
|
|
|
|
|
|
|
|
#events = loadProfileEvents( r'X:\wildwest\script\MotionBuilderPython\profiler\Strip Scene_432013175244593000.xml' )
|
|
#print events |