boostworthyisryantaylor

AS3 Performance Tests

A lot of debate exists over AS3 performance in regards to things such as numerical data types, loops, timers, and enter frame events. While I’m in the process of porting my animation system over to AS3, what better time to do some testing to ensure that it is as optimized as possible.

Loops and Numerical Data Types

I sampled my three favorite loops for this experiment; they are as follows:

Test #1: for(var i:(Number, int, uint) = 0; i < 1000000; i++)

Test #2: for(var i:(Number, int, uint) = 1000000 - 1; i > -1; i--)

Test #3: var i:(Number, int, uint) = 1000000; while(i--)

Inside the loops was some simple math:

var nRandom:Number = Math.random() * 100;

Also note that I tried both pre and post operations (i++, ++i, i--, --i) for each loop and found no change in results. Each loop was ran 50 times to gather an average, and then I ran the test many times to ensure that I was getting the best results possible. Here is what I gathered.

Results in millseconds:

50-average, 100000 loop, Number

Test #1: 230.54 (228.82 on additional test)
Test #2: 235.54
Test #3: 233.36 (228.63 on additional test)

50-average, 100000 loop, int

Test #1: 239.82
Test #2: 268.38
Test #3: 266.7

50-average, 100000 loop, uint

Test #1: 15 second timeout occured
Test #2: 15 second timeout occured
Test #3: 15 second timeout occured

As you can see, when 'i' was typed as an uint performance was so bad that the Flash 15 second timeout was thrown before the test completed. Equally note-worthy is the fact that Numbers out-performed ints.

Next, I decided to do some tests with arrays in loops. I created an indexed array containing 100 elements, each of which was a string with 4 to 20 characters. I ran the same tests as last time, however this time I did not test uint. The test results were all pretty close, Test #’s 1 and 3 were basically dead even. Here is the interesting part; In AS2, despite all the best practices and stuff preaching this:


var nLength:Number = aList.length;
for(var i:Number = 0; i < nLength; i++)

I still found that it was faster to plug the array length property directly into the loop:


for(var i:Number = 0; i < aList.length; i++)

I was very insecure with these results, but I tested things again and again and found the same thing. Now, in AS3, setting a variable with the array length and then using that in the loop is finally faster, and quite a bit at that (0.024ms compared to 0.034ms).

One final thing before we move on. If you are looping through an array and 'i' is only being used to access an index in your array, I recommend typing 'i' as an int. If 'i' is of type Number, it actually slows the loop down a bit from what I have seen. If you are using 'i' in the loop for some math as well, typing it as a Number is fine, but to pick up some performance, make sure you type cast 'i' as int when passing it into the array.

var nLength:Number = aList.length;

for(var i:int = 0; i < nLength; i++)
{
trace(aList[i]);
}

or

var nLength:Number = aList.length;

for(var i:Number = 0; i < nLength; i++)
{
trace(aList[int(i)]);
}

Enter Frame Event and Timers

Before we begin, I just want to clarify a few important points. There is a time and a place for both the enter frame event and for timers, the key is knowing when and why to use them in your architecture. Let’s examine the enter frame event first.

We begin by adding a new listener for the enter frame event:

import flash.events.Event;

addEventListener(Event.ENTER_FRAME, OnLogTime);

In the above example, a listener is added to the object in which the code is placed in, and the method 'OnLogTime' will be called at the corresponding framerate of the SWF file. For example, if the typical 31 frames per second is set, the enter frame event will be dispatched every 32 milliseconds approximately (1000 / 31 = 32.258). I created a simple test which logs the time in milliseconds between each time the event handler is called.

Average: 34.31 milliseconds from 100 samples.

Not bad. Only around 2 milliseconds were lost in between the time the event occured, it was dispatched, and the handler recorded the time. Now let’s take a look at Timers.

import flash.utils.Timer;
import flash.events.TimerEvent;

var objTimer:Timer = new Timer(15, 0);
objTimer.addEventListener(TimerEvent.TIMER, OnLogTime);
objTimer.start();

That’s enough to have our test up and running with a Timer this time, as opposed to listening for the enter frame event. It’s important to note that the event handler will be getting called every 15 milliseconds this time, as opposed to every 32 miliseconds. I did this to try and get it triggered twice per frame. Let’s take a look at some results:

Average: 17.17 milliseconds from 100 samples.

Like with the enter frame event, around 2 milliseconds is lost in the event process. Ideally, that number should be about 16 milliseconds, so let’s lower the delay rate down to 14 milliseconds and run the test again.

Average: 16.29 milliseconds from 100 samples.

That’s more like it. Now we have a setup that will be triggered around twice per frame. We can then force the display to be updated after the event is completed by calling 'objTimerEvent.updateAfterEvent()', where 'objTimerEvent' is the name you give the event argument passed to the timer event handler. This will give something like an animation a smoother look while only occuring during the short duration of the animation, as opposed to using the enter frame event with the SWF running at a higher frame rate at all times. It is very important that you do not abuse the use of 'updateAfterEvent'; if it is getting called often and in multiple places, performance will likely take a hit. Having a setup like this centralized in something like an animation manager and then using it throughout your application wisely will result in smoother animations without noticably sacraficing performance.

So, the results of our tests? Both methods perform roughly the same under normal workloads. When you are after smoother animations or need to call something at a given rate other than the framerate, use Timer. However, under heavy loads, both methods become fairly inaccurate, but enter frame seems to be a little less accurate than Timer. Enter frame is nice, convenient, and reliable; I recommend using it for most general tasks.

That’s all for now. I will certainly be doing more and more tests in the weeks to come; I’m anxious to see what I find as I dive deeper into AS3. Feel free to post up comments about this stuff or share your results if you have done similar tests.

6 Comments so far

  1. seven December 2nd, 2006 10:38 pm

    Good points Ryan! I just stared to play with as3, so I am not an expert. Just wanted to add that strong data typing is a must if you are looking for performance. I did some experimenting and there is also change in performance if you don’t strong type both class method params and return (on a low level - different bytecode is generated). Conversion between numerical datatypes also eats up some time. All those small inconsistencies in the code sum up eventually and slow down performance.

    I hope strict OOP will finally bring some order in ActionScript. :)

  2. Ryan Taylor December 3rd, 2006 9:34 am

    Yes, agreed. In AS2, there is certainly a difference in performance when typing something as 'Object' (or any other dynamic type I might add), as opposed to a sealed (non-dynamic) data type in which all properties are declared. The same applies for AS3, and from what I understand, performance is effected even more so than in it was in AS2, though I have yet to do any testing of this myself.

    You also bring up a good point with numerical data types. When in doubt use Number, it seems to be the data type used majority of the time internally. If a conversion needs to take place, casting it in your code will result in better performance, though this is only a concern when dealing with loops or code that is getting called repeatidly by something like the enter frame event or a Timer.

    Thanks for contributing those good thoughts!

  3. Trevor Burton May 6th, 2007 2:11 pm

    Thanks Ryan, just stumbled across this page as i was about to do very similar tests on Timer vs. onEnterFrame so your results are invaluable. Thanks. I have an AS2 framework that makes big use of a Timer management package and was wondering whether i’d get better results using onEnterFrame instead in the AS3 version.

    T

  4. […] While trawling to see if anyone had done any tests on the best way to keep time in AS3 i stumbled across Ryan Taylor’s experiments at http://www.boostworthy.com/blog/?p=82 PLAIN TEXT Actionscript: […]

  5. johnny September 3rd, 2009 7:13 pm

    Did you happen to test if typecasting would provide the same performance increase as strict typing a new variable? ex:

    var nLength:Number = aList.length;
    for(var i:Number = 0; i

  6. johnny September 3rd, 2009 7:18 pm

    sorry, cut off for some reason. ex:

    var nLength:Number = aList.length;
    for(var i:Number = 0; i

Leave a reply

*
To prove you are human (not an imperial spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word