UnrealScript Optimization
This page is about optimization of UnrealScript code. The UnrealScript compiler doesn't do any optimization by itself. In fact, doing stupid things that have no effect in other languages will have effect in UnrealScript.
However, you shouldn't take most of the content on this page serious. Why not? Because other code in your functions is mostlikely much slower than the optimizations listed here. But it doesn't hurt to know about these optimizations.
This page also covers comparissions between various methods to do certain things that might not be an optimization at all.
Useless code
The compiler doesn't drop useless statements. These statements are still compiled in byte-code and executed. Thefore these useless statements can hurt performance.
The following examples are all bad:
00001 switch (i) 00002 { 00003 case 1: 00004 ... 00005 break; 00006 ... 00007 default: 00008 ... 00009 break; 00010 }
The break on line #9 is useless, at the last case the switch will always go back to the main code. Adding this break will insert a jump to the next instruction, therefor useless. It doesn't have a major impact.
while (...) { ... continue; }
This example isn't as terrible as the former. In this case the continue is in fact useless and doesn't have a performance side effect. It only wastes a tiny bit of diskspace.
Basic arithmetic
00001 i = i+1; // BAD 00002 i += 1; // better 00003 i++; // good 00004 ++i; // best 00005 00006 i / 2; // BAD 00007 i >> 1; // good
El Muerte: I have a bit of a doubt here. What would be faster i /= 2 or i = i >> 1?
Switch`: i/=2 is faster, i*=0.5 is fastest.
Boolean evaluations
UnrealScript uses the so called short bool evaluation, meaning it will escape the boolean evaluation as soon as possible.
if (A || B) { ... }
If A is true it won't evaluate B because it already has a valid reason to execute the body of the if statement. You can use this to your advantage to optimize your boolean evaluations.
With and the right hand side isn't evaluated when the left hand side is already false. With or the right hand side isn't evaluated when the left hand side is already true.
Not all boolean expressions are fast as the others. For example string comparison is slower than a simple integer comparison. Thefore you should first compare types line integers, booleans, object references, floats, enumerations and names (yes names are actually integers with a friendly name) before comparing more complex types like strings and classes.
And ofcourse you should optimize the boolean expressions in the first place:
((A && B) || (B && C)) → (B && (A || C)) (A && B || !A && C || B && C) → (A && B || !A && C)
Variable accessing
00001 t = class.default.vc; // 428ms 00002 t = class'Sandbox'.default.vc; // 415ms 00003 t = default.vc; // 385ms 00004 t = vc; // 380ms 00005 t = self.vc; // randomly 406ms - 424ms...
TODO make more meaning out of this. source.
Jimboh: hmm...how about local variables vs class/object variables?
Out parameters
Defining function arguments as out will simulate passing by reference. But be careful with this. It doesn't actually pass the arguments by reference. It will copy the results back when the function exists. Because of this arguments defined as out are about twice as slow as arguments not defined as out.
Only native functions can use the out flag for true pass-by-reference instead of pass-by-value, but script functions can not.
Discussion
El Muerte: well, it's a start. We might need to think about a notation scheme for optimizations or something. Other items that could be address are:
local int x; x = Rand(MaxInt); doX(x); doY(y); doZ(z);
vs
doX(Rand(MaxInt)); doY(Rand(MaxInt)); doZ(Rand(MaxInt));
So far not a lot has been written on this subject. But quite some of these optimization tricks have been explored. So I think it's a good thing to dedicate a page on this subject.
SuperApe: Looks great. Useful stuff. Some of this might've even been helpful to Epic in earlier versions of Unreal.
El Muerte: earlier?
Jimboh: Mabye merge with Code Optimization?
Jimboh: Hmm...does the final modifier (by itself) improve the speed of calling a function like it does in Java?
El Muerte: hmm... missed that page. Yes, final produces a significant speed improvement. For the simple reason that it will cut the function lookup short.