Practical Performance Tweaks
I’ve had a little bit of time on my hands in my day job *cough choke laugh* and thought I would spend some time doing some low level improvements on the performance of my applications. Though there were some changes I made that might have improved the performance of a function by a few milliseconds on average there were a few things that I changed that made large improvements. These are the sorts of fixes that you commit to memory and just always keep them as time moves forward.
I’m not talking about making sure that you removeEventListeners and nullify unused objects for garbage collection, that is a given. These are common tweaks that people could use in every application but often we don’t because we suspect that the performance hit isn’t as big as it is. Here we will look at how big that hit actually is.
For all these tests I used Grant Skinner’s Performance Testing Harness. The numbers for the tests are provided along with the source code and the test available to run. I slightly modified the Testing Harness so that I could also get the times and numbers out of each test for graphing purposes.
Array vs ArrayCollection vs ICollectionView
These tests all started when I wondered how much slower iterating through an ArrayCollection was than iterating through an Array. The numbers were staggering. In some cases, iterating through the Array was 1/50th of the time or 5000% faster.
For my test I also was curious if using an interface instead of using the actual object made a difference. As you can see from the numbers that the difference wasn’t hugely significant, but actual.
1 2 3 4 5 6 7 8 9 10 11 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.ArraysTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different array tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms findLastArray 81 16.20 findLastArrayCollection 4484 896.80 findLastICollectionView 4405 881.00 findLastVector 106 21.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
One rumor that I heard was that ArrayCollections are faster at finding a specific index value than Array’s due to some sort of magical optimization. So I tested that rumor also, below are the results. As you will see, this rumor is false. Arrays are faster at accessing a specific index value than ArrayCollections.
1 2 3 4 5 6 7 8 9 10 11 12 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.ArraysTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different array tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms findObjectAtArray 64 12.80 findObjectAtArrayCollectionOperand 4200 840.00 findObjectAtArrayCollectionGetItemAt 1700 340.00 findObjectAtICollectionView 4151 830.20 findObjectAtVector 84 16.80 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Already there are additional tests I am thinking about running, but on the whole you can see that using the base Array over ArrayCollection will yield large performance improvements.
However, I again want to point out that whenever you set an Array as the dataProvider of a Flex component, Flex components convert Arrays to ArrayCollections. So don’t try to get a performance increase from a component specifically by setting the dataProvider as an Array, the Array will be transformed either way.
Loops
The next section that I was going to test was the age old debate about the perfect loop: For Loops vs While Loops, iterating before the loop vs after the loop, etc etc. Luckily for me, as soon as I started looking at Grant’s testing harness, he had already created most of the test cases for me (Thanks). So the only extension to the test that I had to make was to also test against iterating before or after the loop (++i vs i++). The results can be seen below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.LoopsTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different loop structures. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms forIncrementAfter 439 87.80 forDecrementAfter 439 87.80 forIncrementBefore 445 89.00 forDecrementBefore 435 87.00 * whileIncrementAfter 647 129.40 whileDecrementAfter 456 91.20 whileIncrementBefore 649 129.80 whileDecrementBefore 456 91.20 * doWhileIncrementAfter 465 93.00 doWhileDecrementAfter 480 96.00 doWhileIncrementBefore 483 96.60 doWhileDecrementBefore 479 95.80 * forIn 623 124.60 forEachIn 669 133.80 forEachInUntyped 647 129.40 forEachInPosttyped 1255 251.00 * arrForEach 1722 344.40 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
What you will probably notice is that no specific loop includes massive performance improvements, though the simple for loop seemed to be the fastest on average. So take your pick and run with it.
Unrolled Loops
The next tests that I came up with was to see how efficient rolled vs unrolled loops were. The reason I felt this was important is there are times that we needlessly iterate through a loop when we know there will always be X number of elements. When this is a the case I’ve found (and the tests prove) that it is faster to just do what you need with the X elements rather than write a loop to iterate through the elements.
Remember to check the source to see the implementations of these different tests.
1 2 3 4 5 6 7 8 9 10 11 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.LoopsTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different loop structures. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms rolledUpLoop 1585 317.00 unRolledLoop 864 172.80 rolledUpLongLoop 1134 226.80 unRolledUpLongLoop 803 160.60 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Length Reference Variable
This is definitely a nit picky test, but I had to know the truth! When iterating through a loop is it significantly better to get a reference to the length of the loop, or is it okay just to use array.length in each iteration. As proven, using a variable to store the length is significantly better.
1 2 3 4 5 6 7 8 9 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.LoopsTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different loop structures. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms lengthReferenceTest 512 102.40 noLengthReferenceTest 926 185.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Reference Variables
When iterating through a loop I often like to pull a reference to the current value that is being evaluated in a loop. I do this mainly to make reading the code easier, but I was curious if this creation of a new reference would be harmful to performance. On top of that I was curious if giving these temporary variables a type was helpful for performance or not. Below are the results.
1 2 3 4 5 6 7 8 9 10 11 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.LoopsTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different loop structures. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms noTemporaryLoopVariableUntyped 1988 397.60 noTemporaryLoopVariableTyped 1937 387.40 temporaryLoopVariableUntyped 1849 369.80 temporaryLoopVariableTyped 1897 379.40 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
As you can see I’ve figured that there isn’t a significant performance increase or loss with using temporary variables. I think I’ll keep using my temporary variables to make reading easier.
Type, Cast and toX
The next series of tests are extremely geeky tests with some startling results. Is it faster to say (object as String) or String(object) or object.toString? This test case and many others are included below for each of the base types. May this help you decide how to type and cast your variables.
The big one to notice is the amount of time it takes to String(number) instead of saying (number as String).
Included with each test is the control case of casting and typing each type to the same base type.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.TypesTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different type, casting, and manipulation tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms stringToString 96 19.20 stringCastString 68 13.60 stringAsString 76 15.20 objectStringToString 153 30.60 objectStringCastString 70 14.00 objectStringAsString 78 15.60 numberCastString 888 177.60 numberAsString 104 20.80 intCastString 229 45.80 intAsString 86 17.20 uIntCastString 229 45.80 uIntAsString 86 17.20 * numberCastNumber 46 9.20 numberAsNumber 103 20.60 objectNumberCastNumber 50 10.00 objectNumberAsNumber 81 16.20 intCastNumber 46 9.20 intAsNumber 84 16.80 uIntCastNumber 46 9.20 uIntAsNumber 86 17.20 stringCastNumber 76 15.20 stringAsNumber 84 16.80 * uintCastUint 45 9.00 uintAsUint 86 17.20 objectUintCastUint 48 9.60 objectUintAsUint 82 16.40 numberCastUint 47 9.40 numberAsUint 113 22.60 intCastUint 45 9.00 intAsUint 84 16.80 stringCastUint 82 16.40 stringAsUint 90 18.00 * intCastInt 46 9.20 intAsInt 82 16.40 objectIntCastInt 48 9.60 objectIntAsInt 80 16.00 numberCastInt 47 9.40 numberAsInt 106 21.20 uintCastInt 46 9.20 uintAsInt 86 17.20 stringCastInt 77 15.40 stringAsInt 88 17.60 * arrayAsArray 77 15.40 objectArrayAsArray 81 16.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Remember when using “as”, if the conversion fails, you will receive a null rather than the value. Unless you explicitly know what the type will be, it is always good to make this check.
The “new” operator
I’ve always been told that when creating a new base type that you should use the value rather than new because it saves the need for the VM to allocate the memory in the heap. But what was the ACTUAL performance improvements. Again, the numbers are staggering. For the next tests I created each of the simple types 3 different ways.
The first way I used the new operator as such: var s:String = new String();
The second way I used the new value as such: var s:String = “”;
And the final test was to create the variable with the new operator without the final parenthesis, such as: var s:String = new String;
For every test setting the value rather than using the new operator was almost twice as fast. The biggest difference being with creating a new Array, using the [] operand instead of the new operator was almost 3 times as fast.
I should also point out that for almost each test, using the parenthesis was slower than leaving them off when creating a new variable, though this is considered bad practice. Though the difference was marginal.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.TypesTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different type, casting, and manipulation tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms newUintTest 75 15.00 newUintValueTest 44 8.80 newUintTestNoParams 76 15.20 * newIntTest 75 15.00 newIntValueTest 45 9.00 newIntTestNoParams 74 14.80 * newNumberTest 72 14.40 newNumberValueTest 45 9.00 newNumberTestNoParams 75 15.00 * newStringTest 71 14.20 newStringValueTest 45 9.00 newStringTestNoParams 74 14.80 * newArrayTest 711 142.20 newArrayValueTest 249 49.80 newArrayTestNoParams 709 141.80 * newObjectTest 267 53.40 newObjectValueTest 230 46.00 newObjectTestNoParams 263 52.60 * newXMLTest 1032 206.40 newXMLValueTest 1023 204.60 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Static Methods vs Class Methods
As a side curiosity I was wanted to know if there was any performance loss or gain based on the types of functions used within a class. I was able to see that there weren’t any significant performance improvements over one type of function or another. So stick with best practices within your classes and only make methods and properties public when they absolutely have to be.
This test does not include testing whether creating the class and then accessing the function is better than a static function which does not need to instantiate a class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.ClassTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different class method tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms publicMethod 141 28.20 privateMethod 143 28.60 protectedMethod 144 28.80 publicStaticMethod 141 28.20 privateStaticMethod 142 28.40 protectedStaticMethod 141 28.20 publicInternalMethod 142 28.40 publicFinalMethod 144 28.80 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Using “this” and Other Class Curiosities
This next section includes many different tests to improve my class creation.
Setting the default values
In this test I was curious if it is better to initially set a variable in the constructor or at the variable, and also if setting the variable defaults inside the class vs outside the class was better. What I found is that it is faster to initially just set the variables to their default value rather than making this change in the constructor.
1 2 3 4 5 6 7 8 9 10 11 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.VariablesTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different variables and vo based tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms defaultVarsSetVO 400 80.00 varsSetInConstructorVO 490 98.00 varsSetOutsideConstructorThisVO 499 99.80 varsSetOutsideConstructorNoThisVO 496 99.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Is using “this” wrong?
Checking whether it was faster to use the “this” identifier was harmful to performance I concluded that there was no significant performance loss or gain in using the “this” identifier.
1 2 3 4 5 6 7 8 9 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.VariablesTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different variables and vo based tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms thisToString 2395 479.00 noThisToString 2441 488.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Getters and Setters vs Direct Accessors
Lots of good ole’ boy Java developers will tell you that every property has to have a getter and setter. Other programmers will say that this is only necessary if there is some logic that needs to run in the get/set process. Now you can see that by using a getter/setter when a direct accessor can be used is wasteful for performance and typing. Therefore, only create getters/setters when it is important to run some logic in the getting/setting process.
1 2 3 4 5 6 7 8 9 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.VariablesTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different variables and vo based tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms noGetSetAccessors 2382 476.40 getSetAccessors 2786 557.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Size really doesn’t matter… in variables.
Finally, the stigma from writing Javascript applications always left me feeling guilty about using full words when a letter can do. In Javascript this was a performance issue and caused many programmers to use single incomprehensible letters instead of easy to read words. To elevate my guilt I decided to test if using long variable names made any difference at runtime. The answer is no. No savings, no loss. Now, guilt free, I will always use well written variable names instead of short single letter descriptors.
1 2 3 4 5 6 7 8 9 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.VariablesTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different variables and vo based tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms shortVarNames 45 9.00 longVarNames 45 9.00 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
If..Then vs Switch..Case
Like loops, developers argue which logical test is better: if..then vs switch..case. Pitting the two against each other, apples vs apples, I’ve found that if..then statements are slightly faster than switch..case statements. I will still use each statement where appropriate though, but it is good to know in the situations that I have the choice that I should use if..then statements.
1 2 3 4 5 6 7 8 9 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.LogicalTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different logical structure tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms switchCaseStatement 411 82.20 ifThenElseStatement 378 75.60 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Math.max() vs Math.max.apply()
One little known secret to AS3 is the apply method. Most classes have more than one way to skin a cat, and the apply method is that function. In the case of Math.max (or Math.min) I was curious how much faster the apply method was vs logically finding the largest (or smallest) value. The numbers were staggering. From now on I will be using the apply method whenever possible as it is a very low level and fast function.
1 2 3 4 5 6 7 8 9 | ––––––––––––––––––––––––––––––––––––––––––––––––––––––– com.unitedmindset.tests.ApplyTest (5 iterations) Player version: MAC 10,0,32,18 (debug) Test different apply method tests. ––––––––––––––––––––––––––––––––––––––––––––––––––––––– method..................................ttl ms...avg ms findMaxLogically 2093 418.60 findMaxApply 131 26.20 ––––––––––––––––––––––––––––––––––––––––––––––––––––––– |
Final Thoughts
Obviously the things in this list I see as some of the greatest offenders and also the easiest to fix. It all comes down to you and which changes you feel comfortable making in your daily coding practices. Some of the more “nit picky” performance changes I feel can effect code readability and reusability, and which you implement into your code is up to you and your coding practices. Hopefully this ends the debate between some techniques as being the end all be all technique.
If there are other coding techniques that have left you wondering which is better, let me know and I’ll add it in. I’m sure over time I’ll revisit these test cases.
The Test, Run It For Yourself Or View Source
View Source (or right click swf)





[...] Check it out [...]
[...] This post was mentioned on Twitter by Grant Skinner, Joseph Burchett. Joseph Burchett said: Practical Performance Tweaks in Flex http://bit.ly/5KEANi [...]
Social comments and analytics for this post…
This post was mentioned on Twitter by retrogamer4ever: Practical Performance Tweaks in Flex http://bit.ly/5KEANi...
Interesting results, especially for apply().
I have a question about if..else and switch comparison. I think that speed of if..else structure largely depends on the place of correct condition (condition that gives a “true”). Can you confirm and test that? When I’m in question whether to use if or switch, I examine a conditions. If probability for some conditions to be true is greater than for rest, I’ll go with if and that conditions would be on the top of if structure. If probability for large numbers of conditions is same (or similar), I would go for switch.
So can you check on this
The Math.max.apply() results are shocking, I will definitely have to remember that one.
@krdr That would be interesting tests. Finding in first position and finding in last position. You will notice from my tests that I put the if..then and switch..case statements in the same order and randomized the order that the true result would be found so that it would equalize the found first, second, or last. But that would be an interesting set of tests to add, just to see the results.
[...] This post was Twitted by nothingagency [...]
Function.apply … I’m not the first who is surprised…
How did you find this tips ?
Thanks for this benchmark !
Some very interesting results here, thanks for the tests! According to this site http://wiki.joa-ebert.com/index.php/Casting wrapped cast is faster than cast with ‘as’.
One case that would still interest me is if a Math function stored in a class property is faster than using it direclty. E.g.
private var _mathRandom:Function = Math.random;
…
somewhere down the line:
var n:Numer = _mathRandom();
instead of:
var n:Numer = Math.random();
Nevermind. After some quick tests it turns out that calling Math functions directly is much faster than storing them in a var or even const.
@Germain It wasn’t that I found these stats. I created these tests to run because I wanted to see not what people said / assumed was faster, but instead what actually was faster. You can view source and see the tests and run them for yourself. I will be releasing another set of tests at some point as performance testing has been interesting and fun.
@sascha That was my guess too. Making the additional reference to a static function seemed more like another hoop to jump through rather than a point of improvement.
[...] 2010 (25/03/2010) 4 Likes Adobe: Flex 4 beta in a Week 4 Likes Practical Performance Tweaks | The World In A State of Flex I've had a little bit of time on my hands in my day job *cough choke laugh* and thought I would [...]
The NumberAsString is wrong — it should be excluded from the tests.
That’s because:
41.5 as String is clearly null and not “41.5″.
‘as’ does not convert. It just checks the RTTI and returns non-null only if the object is an instance of the class argument.
I agree that you receive Null. I did make sure to include that warning when using “as”. But I left it in there so I didn’t get people saying I forgot NumberAsString as one of the permutations. One of those situations where you’re damned if you do, damned if you don’t.