Currently I can't back my findings with benchmarks and they are mostly based on common sense (in other words: you shouldn't read that kind of guide). As some general words: don't waste your time optimizing code which rarely executes and focus on higher level code optimizations rather than small scale changes and benchmark!
Don't use unnecessary casts/class checks (I).
DO:
Code: Select all
function Stuff( Actor Other )
{
var Inventory OtherInventory;
OtherInventory = Inventory(Other);
if ( bool(OtherInventory) )
{
// [...]
}
}
Code: Select all
function Stuff( Actor Other )
{
var Inventory OtherInventory;
if ( Other.IsA('Inventory') )
{
OtherInventory = Inventory(Other);
// [...]
}
}
Don't use unnecessary casts/class checks (II).
DO:
Code: Select all
function Stuff( Actor Other )
{
if ( Other.bIsPawn )
{
// [...]
}
}
Code: Select all
function Stuff( Actor Other )
{
if ( Other.IsA('Pawn') )
{
// [...]
}
}
You can also start to add more of these sort of variables to your classes, to use it in more places. If you need to access variables of that particular class, you could also consider storing them in the baseclass. This will also make it easier to write 3rd party code which is not of that particular class. In case of function calls, you could also add some stub function in the baseclass which gets overriden, though this would introduce another function resolve, so this is more useful to keep code flexible by not relying on a specific class.
Make functions final which are certainly never going to be overriden.
DO:
Code: Select all
final function SetBorderStyle( EDrawStyle NewBorderStyle )
{
BorderStyle = NewBorderStyle;
}
Code: Select all
function SetBorderStyle( EDrawStyle NewBorderStyle )
{
BorderStyle = NewBorderStyle;
}
Don't use functions which just call Super.
DO:
Code: Select all
Code: Select all
simulated event RenderOverlays( Canvas Canvas )
{
Super.RenderOverlays( Canvas );
}
Finish your math.
DO:
Code: Select all
function float CalculateSomething( float f )
{
// 1.00392156863 = 256.0/255.0.
return f*1.00392156863;
//
// 0x0000: EX_Return
// 0x0001: EX_Native (iNative=171,Function=Core.Object.Multiply_FloatFloat,OperatorType=1)
// 0x0002: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.CalculateSomething.F)
// 0x0007: EX_FloatConst (FloatConst=1.003922)
//
}
Code: Select all
function float CalculateSomething( float f )
{
return f*256.0/255.0;
//
// 0x0000: EX_Return
// 0x0001: EX_Native (iNative=172,Function=Core.Object.Divide_FloatFloat,OperatorType=1)
// 0x0002: EX_Native (iNative=171,Function=Core.Object.Multiply_FloatFloat,OperatorType=1)
// 0x0003: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.CalculateSomething2.F)
// 0x0008: EX_FloatConst (FloatConst=256.000000)
// 0x000E: EX_FloatConst (FloatConst=255.000000)
//
}
Use cast to bool instead of checking againts 0/0.0/""/None/vect(0,0,0)/rot(0,0,0).
DO:
Code: Select all
function UseBoolCast2( int i, float f, string Str, Object Obj )
{
if ( bool(i) );
if ( bool(f) );
//if ( bool(Str) ); // See dots post below.
if ( bool(Obj) );
//
// 0x0000: EX_JumpIfNot (JumpOffset=0x0009)
// 0x0003: EX_IntToBool
// 0x0004: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast2.i)
// 0x0009: EX_JumpIfNot (JumpOffset=0x0012)
// 0x000C: EX_FloatToBool
// 0x000D: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast2.F)
// 0x0012: EX_JumpIfNot (JumpOffset=0x001B)
// 0x0015: EX_StringToBool
// 0x0016: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast2.Str)
// 0x001B: EX_JumpIfNot (JumpOffset=0x0024)
// 0x001E: EX_ObjectToBool
// 0x001F: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast2.Obj)
//
}
Code: Select all
function UseBoolCast( int i, float f, string Str, Object Obj )
{
if ( i!=0 );
if ( f!=0.0 );
//if ( Str!="" ); // See dots post below.
if ( Obj!=None );
//
// 0x0000: EX_JumpIfNot (JumpOffset=0x000B)
// 0x0003: EX_Native (iNative=155,Function=Core.Object.NotEqual_IntInt,OperatorType=1)
// 0x0004: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast.i)
// 0x0009: EX_IntZero
// 0x000B: EX_JumpIfNot (JumpOffset=0x001A)
// 0x000E: EX_Native (iNative=181,Function=Core.Object.NotEqual_FloatFloat,OperatorType=1)
// 0x000F: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast.F)
// 0x0014: EX_FloatConst (FloatConst=0.000000)
// 0x001A: EX_JumpIfNot (JumpOffset=0x0026)
// 0x001D: EX_Native (iNative=123,Function=Core.Object.NotEqual_StrStr,OperatorType=1)
// 0x001E: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast.Str)
// 0x0023: EX_StringConst (StringConst="")
// 0x0026: EX_JumpIfNot (JumpOffset=0x0031)
// 0x0029: EX_Native (iNative=119,Function=Core.Object.NotEqual_ObjectObject,OperatorType=1)
// 0x002A: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseBoolCast.Obj)
// 0x002F: EX_NoObject
//
}
Use correct constant types.
DO:
Code: Select all
function float UseCorrectConstantTypes2( float f )
{
return f*2.0;
//
// 0x0000: EX_Return
// 0x0001: EX_Native (iNative=171,Function=Core.Object.Multiply_FloatFloat,OperatorType=1)
// 0x0002: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseCorrectConstantTypes2.F)
// 0x0007: EX_FloatConst (FloatConst=2.000000)
//
}
Code: Select all
function float UseCorrectConstantTypes( float f )
{
return f*2;
//
// 0x0000: EX_Return
// 0x0001: EX_Native (iNative=171,Function=Core.Object.Multiply_FloatFloat,OperatorType=1)
// 0x0002: EX_LocalVariable (Property=ScriptRaysTestPackage.ScriptRaysTestFunctions.UseCorrectConstantTypes.F)
// 0x0007: EX_IntToFloat
// 0x0008: EX_IntConstByte (IntConst=2)
//
}
Don't use 'conveniance' functions to wrap your Natives..
DO:
Code: Select all
native final function SetViewportLocation( Vector NewLocation, optional bool bEnable );
native final function SetViewportLocationXYZ( float X, float Y, float Z, optional bool bEnable );
Code: Select all
native final function SetViewportLocation( Vector NewLocation, optional bool bEnable );
final function SetViewportLocationXYZ( float X, float Y, float Z, bool bEnable )
{
local Vector Temp;
Temp.X = X;
Temp.Y = Y;
Temp.Z = Z;
SetViewportLocation( Temp, bEnable );
}
Don't define empty functions (if they just return 0).
DO:
Code: Select all
event bool ComputerInputFinished( String inputKey, String inputValue );
Code: Select all
event bool ComputerInputFinished( String inputKey, String inputValue )
{
return False;
}
In any case this is certainly a neglectable optimization and I only put it here because it looks cleaner to me and it could be used with a future (small) optimizations of bytecode execution especially in respect to RPCs. (I briefly talked with Smirftsch about it).
tl;dr
Don't use unnecessary cast/class checks and function resolves to get the biggest savings.
To be continued...