Files
gtav-src/tools_ng/techart/dcc/motionbuilder2014/python/RS/Utils/Profiler.py
T
2025-09-29 00:52:08 +02:00

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