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

115 lines
5.2 KiB
Python
Executable File

'''
Description:
This module allows us to easily instrument Modules, Classes, Functions and Methods.
The primary use for this is to allow us to use the pyfbsdk with cProfile.
Doesn't work with static/class methods only with instance methods
Author:
Ross George
'''
import compiler
_instrumentedMethodClosures = dict()
_instrumentedMethodIdPairings = dict()
def InstrumentMethod( targetClass, targetMethodName ):
#Get the target function and it's Id
targetInnerMethod = getattr( targetClass, targetMethodName )
targetInnerMethodId = id( targetInnerMethod )
#Check if we have processed this method
if ( _instrumentedMethodIdPairings.has_key( targetInnerMethodId ) ): return()
#Add the function to our closures list so that we can call it later
#We use the objects ID to do this.
_instrumentedMethodClosures[ targetInnerMethodId ] = targetInnerMethod
#Get the name we will give the outer function (this is how it will
#appear on the profiler so it's important that it is descriptive)
targetOuterFunctionName = '{0}_{1}_{2}'.format( targetClass.__module__, targetClass.__name__, targetMethodName )
#Compile into a function. We do this because we want the correct function and filename to appear on the profile stats.
outerFunctionSource = 'def {0}( *args, **kwargs ): return( _instrumentedMethodClosures[{1}]( *args, **kwargs ) )'.format( targetOuterFunctionName, targetInnerMethodId )
outerFunctionCompiled = compiler.compile( outerFunctionSource, 'pyfbsdk.pyc', 'exec' )
exec( outerFunctionCompiled )
#Get the outer function ready to override the inner method on our targetClass
exec( 'targetOuterFunction = {0}'.format( targetOuterFunctionName ) )
#Add this function to our list of functions that have been instrumented
outerFunctionId = id( targetOuterFunction )
_instrumentedMethodIdPairings[ outerFunctionId ] = targetInnerMethodId
#Finally we set the attribute on the class
setattr( targetClass, targetMethodName, targetOuterFunction )
_instrumentedFunctionClosures = dict()
_instrumentedFunctionIdPairings = dict()
def InstrumentFunction( targetModule, targetFunctionName ):
#Get the target function
targetInnerFunction = getattr( targetModule, targetFunctionName )
targetInnerFunctionId = id( targetInnerFunction )
#Check if we have processed this function
if ( _instrumentedFunctionIdPairings.has_key( targetInnerFunctionId ) ): return()
#Add the function to our closures list so that we can call it later
#We use the objects ID to do this.
_instrumentedFunctionClosures[ targetInnerFunctionId ] = targetInnerFunction
#Get the name we will give the outer function (this is how it will
#appear on the profiler so it's important that it is descriptive)
targetOuterFunctionName = '{0}_{1}'.format( targetModule.__name__, targetFunctionName )
#Compile into a function. We do this because we want the correct function and filename to appear on the profile stats.
outerFunctionSource = 'def {0}( *args, **kwargs ): return( _instrumentedFunctionClosures[{1}]( *args, **kwargs ) )'.format( targetOuterFunctionName, targetInnerFunctionId )
outerFunctionCompiled = compiler.compile( outerFunctionSource, 'pyfbsdk.pyc', 'exec' )
exec( outerFunctionCompiled )
#Get the outer function ready to override our inner function
exec( 'targetOuterFunction = {0}'.format( targetOuterFunctionName ) )
#Add this function to our list of functions that have been instrumented
outerFunctionId = id( targetOuterFunction )
_instrumentedFunctionIdPairings[ outerFunctionId ] = targetInnerFunctionId
#Finally we set the attribute on the module
setattr( targetModule, targetFunctionName, targetOuterFunction )
_instrumentedClassIdList = list()
def InstrumentClass( targetClass ):
#Check we haven't already processed this class
targetClassId = id( targetClass )
if targetClassId in _instrumentedClassIdList: return()
for attributeKey in dir( targetClass ):
attributeValue = getattr( targetClass, attributeKey )
if ( 'instancemethod' in type( attributeValue ).__name__ ):
InstrumentMethod( targetClass, attributeKey )
#Add the class so that we don't process it again
_instrumentedClassIdList.append( targetClassId )
_instrumentedModuleIdList = list()
def InstrumentModule( targetModule ):
#Check we haven't already processed this module
targetModuleId = id( targetModule )
if targetModuleId in _instrumentedModuleIdList: return()
for attributeKey in dir( targetModule ):
attributeValue = getattr( targetModule, attributeKey )
if ( 'function' in type( attributeValue ).__name__ ):
InstrumentFunction( targetModule, attributeKey )
if ( 'class' in type( attributeValue ).__name__ ):
InstrumentClass( attributeValue )
#Add the module so that we don't process it again
_instrumentedModuleIdList.append( targetModuleId )