H3XED

Actionscript 3 Code Performance Tips & Testing

Nov 16, 2010   Programming   Nick Vogt   Comments (1)
Please note that this post is over a year old and may contain outdated information.
In Actionscript 3 there are usually different coding methods to achieve the same output (this can be said of any programming language). Variables can be declared in different ways, math equations can be performed in different ways, you can move code into functions, perform things on single lines or multiple lines, and so on and so forth. While different methods may achieve the same output, certain methods are often faster than others. This post is dedicated to finding as many performance tweaks and enhancements as I can, and I will update it as I find more.

Methodology: For each test, I use the following loop to determine the relative duration of processing time. I use 500,000 iterations (or more in some cases) so that small differences in performance between code are exacerbated. Usually, any variables that I use in the test are initialized before the timed loop, to eliminate their initialization time from the test. That is unless I'm testing the performance including initialization. I also run the test multiple times to get the average time.

var i:int;
var time1 = getTimer();
for(i = 0; i < 500000; i ++)
{
   // Code to test
}
var time2 = getTimer();
trace(time2 - time1);


Array Initialization and Values


You can initialize a new array using either new Array() or [] (brackets). I had assumed that it didn't matter which method was used, but after some performance testing I found that they do operate differently, and in my tests [] is significantly faster than new Array().

214 milliseconds:
var array1:Array = [];
670 milliseconds:
var array1:Array = new Array();
If you specify the size of the array, like you're supposed to in other programming languages, it slows things down further:

818 milliseconds:
var array1:Array = new Array(10);
The above test comes out the same even if you specify 0 as the size.

Here are tests when initializing an array with values:

357 milliseconds:
var array1:Array = [4,82,3,99,1];
1066 milliseconds:
var array1:Array = new Array(4,82,3,99,1);
Initializing an array and then adding values to it later results in some odd behavior:

454 milliseconds:
var array1:Array = [];
array1[0] = 4;
array1[1] = 82;
array1[2] = 3;
array1[3] = 99;
array1[4] = 1;

918 milliseconds:
var array1:Array = new Array();
array1[0] = 4;
array1[1] = 82;
array1[2] = 3;
array1[3] = 99;
array1[4] = 1;

Comparing those to the ones above, when using new Array() it is faster to declare the array and then add values individually, as opposed to declaring it with values, at least when adding only a handful of values like above. But using brackets is still quicker than either.

I am fairly sure the reason for the performance hit using new Array() comes from the fact that Actionscript 3 has to first determine what constructor to use, depending on if you enter just one integer or multiple values (see Livedocs). If you use brackets, there is only one constructor that would be used.

It's also important to note that it can be easy to cause an error using new Array() if you try to initialize it with an integer as its first and only value. Writing something like "var arr = new Array(18);", with the intent of creating an array whose first value is 18, will actually create an Array of size 18 (with empty values). I generally stick to brackets in Actionscript.


Inline Multiplication versus Math.pow (Exponentiation)


Math.pow is a very useful function when you need to get the value of some number raised to the power of some other number, with both of these numbers being dynamic and not known beforehand. However, if you know the exponent that you want to raise a number to, it is much faster to use simple inline multiplication. Here are some performance tests using the 2D distance equation (without the square root). I used 10,000,000 iterations for this test to get meaningful results, as inline multiplication was extremely quick compared to the power function. I also initialized myVar before the timed test to eliminate initialization time from the results.

Using Math.pow takes 4250 milliseconds:
myVar = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2);
While using inline multiplication takes only around 55 milliseconds:
myVar = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);

Single-line vs Multi-line Conditional Checks


In Actionscript 3, checking several conditions at once can often be slower than checking each condition by itself. Using a 2D box collision test for the example, here is a typical collision check (note that I used 10 millions iterations to get meaningful results):

if(x1 + w1 > x2 && x1 < x2 + w2 && y1 + h1 > y2 && y1 < y2 + h2)
{
   // Execute
}

The above took 284 milliseconds to process. Now breaking it down:

if(x1 + w1 > x2)
{
   if(x1 < x2 + w2)
   {
      if(y1 + h1 > y2)
      {
         if(y1 < y2 + h2)
         {
            // Execute
         }
      }
   }
}

The above took 188 milliseconds.

Both tests used the following variable values:

var x1:int = 44, y1:int = -12, w1:int = 100, h1:int = 100;
var x2:int = -20, y2:int = 27, w2:int = 100, h2:int = 100;

You'll notice that each condition check returns TRUE, so the program does have to go through all 4 conditional checks for each example. What if we make it so that the very first condition check returns FALSE? By just changing the location of the second box's x, we can do just that:

var x1:int = 44, y1:int = -12, w1:int = 100, h1:int = 100;
var x2:int = 400, y2:int = 27, w2:int = 100, h2:int = 100;

Using the above values, the first example (conditions all on one line) took 142 milliseconds, while the second example (separate lines) took 90 milliseconds.

Update: You can combine both the improved performance and single-line conditional checking by formatting the code like this:

if(x1 + w1 > x2) if(x1 < x2 + w2) if(y1 + h1 > y2) if(y1 < y2 + h2)
{
   // Execute
}

Another thing to note is the order in which you perform your conditional checks. Always perform the checks that are most likely to return FALSE first, to avoid needless conditional checks. For example, if you have a 2D platformer game with long horizontal levels, it's probably a good idea to check the horizontal collision first, as the vertical checks can return TRUE for objects at the other end of the level if they are at the same height.


Object Attribute Access


You can access the attributes of an object in two ways. One by using a dot followed by the name of the attribute, and the other by putting the name in quotes in brackets. See below:

var myObj:Object = {one:15, two:33};
trace(myObj.one);
trace(myObj['two']);

In my testing, just using a dot was slightly quicker than using brackets and quotes.

var i:int;
var myObj:Object = {one:15};
var myInt:int;
var time1 = getTimer();
for(i = 0; i < 5000000; i ++)
{
   myInt = myObj.one;
}
var time2 = getTimer();
trace(time2 - time1);

Using just a dot, the above took 591 milliseconds on my machine.

var i:int;
var myObj:Object = {one:15};
var myInt:int;
var time1 = getTimer();
for(i = 0; i < 5000000; i ++)
{
   myInt = myObj['one'];
}
var time2 = getTimer();
trace(time2 - time1);

While using quotes and brackets took 653 milliseconds.
Share This Post
Twitter

Comments (1)

Poul   Nov 14, 2018
Interesting investigation. Writing a virtual machine engine in AS, and this information was helpful.
Share This Post
Twitter
H3XED © Nick Vogt   RSS   Policies   Twitter