Tips on how to write efficient AS3 – part 2

robot-calculatorAs a continuation from my last post regarding AS3 and performance here are some more tips I found interesting.

Array push vs. Array index

Don't use the push function on an Array instead use the Array length property and set on the Array like so list[list.length] = data; Or if that's not enough for the best performance (about 600% faster) than using push don't use the Array length property at all. To do this keep the Array length as an external variable and increment/decrement it as you add and remove items from the Array.

Array emptying - length 0 vs. A new Array

If you need to empty an Array there is a handy option to do this via setting the Arrays property length to 0. You would think this would be the better option as you are avoiding creating a new Array and ultimately saving memory. Though it's interesting to know as a trade off using length to clear an Array is not faster in performance (in most cases). Using length is more efficient when you might need to clear more than 510 Arrays in a single execution, otherwise creating a new Array via [] is the faster option again.

Var declarations on multiple lines vs. Var declarations on a single line

If you need to declare a few variables it's slightly more efficient to do so on a single line i.e.
var a:int=0, b:int=0, c:int=0;
vs.
var a:int=0;
var b:int=0;
var c:int=0;

Using Xor to swap variables

Using Xor is very handy if you want to swap variables but don't want to create a third variable i.e.

a = a^b;
b = a^b;
a = a^b;

Like most people I thought this would be more efficient but it's not compared to creating a third variable and then doing the swap. In fact it's about 300% more efficient to do the swap this way. Though honestly I still have a soft spot for the Xor method.

var oldB:int = b;
b = a;
a = oldB;

Multiplication vs. Division

When working with Math in Actionscript multiplications seem to always run faster than divisions so instead of 5000/1000 use 5000*0.001 it's about 130% faster.

Type casting comparison

When type casting the keyword as is 250% more efficient than casting by Type(item); Though surprisingly not using either is about 1400% more efficient.

Long vs Short variable names

Though this one is debatable because it results in illegible code. Shortened variable names do give a millisecond or so improvement if iterating many 1,000's of times in a single loop. Though I think this is a last resort in code optimization as the differences are really marginal.

Object Pooling in AS3

If you're looking to save memory overhead and increase performance in your Flash creations then implementing the design pattern of Object Pooling is a great place to start. Object Pooling is most beneficial when the cost of construction is high or the frequency of construction is high.

Though it has to be known Object Pooling is not a silver bullet. There are definitely pitfalls to Object Pooling this most of all includes cleaning the Object for reuse. I'll get back to this in just a moment but first I have to talk about Object Pools generally.

In short an Object Pool allows you to retrieve an instance of a particular type of Object by checking it in and out of a resource pool. The concept of checking in and out resources is very consistent when using an Object Pool. Though handling the situation when a pool is empty is not.

There are three approaches I will talk about when handling an empty pool :

1) The Unbounded Pool

The pool has a boundless size and Objects are added as required to the resource pool on check out. This ensures that an Object will always be returned on check out.

2) The Capped Pool

The pool has a constant size and the resource pool is populated during the construction of the pool. This allows you to have all the memory overhead in the pool construction and not during check out. Though when check outs occur to an empty pool it won't return an Object.

3) The Queue Pool

The pool has a minimum size and the resource pool is populated during construction like option 1 it has the benefit of a maximum size - allowing the pool to grow. Unlike option 2 when the pool's maximum size or flood limit is reached and a check out occurs on an empty pool then this request is queued. Requests in the queue will be eventually dropped if not fulfilled within a defined timeout or alternatively resolved once an Object is checked in. This doesn't guarantee that the check out will be fulfilled by the Object Pool but does ensure that pools don't grow uncontrollably and when they reach flood limits that the next fulfilled check out should be the last.

Each of these approaches to controlling the resource pool size have unique benefits and the option you choose depends on how size matters :). Lets say in one scenario that Object memory allocation is inexpensive and having 1,000's to even 10,000's of Objects is no big deal then option 1 is a good choice. Especially considering it's simple and reliable. Though in another scenario where the same number of Objects are checked in as out and as a safe guard when a checkout occurs on an empty pool it can be suppressed then option 2 is a good choice. And doubly so considering a lot of the memory overhead of Object construction is on the Object Pool constructor and the pool will never grow out of your control. Though lastly if you can't suppress check outs on empty pools and the next Object checkout should be the last one and you need to limit your pool size due to the Objects being expensive then option 3 is more than likely the best approach for you.

Now I'll get back to Object cleaning, this sets an Object to the state it was in after construction which is important because check out is a replacement for constructing anew. The scenario when dirty Objects are added into the resource pool is often known as a cesspool and is considered an anti-pattern but honestly it's up to you to wether this worries you or not. Though in regard to Object cleaning it's also important to note this is where a clear pitfall emerges. If the process of cleaning is more expensive than construction then you should really consider not using an Object Pool.

If Object cleaning is important to you it gets interesting when consider the time and place to do this in your Object Pool class. It would seem logical to clean the Object within the check in method to ensure a cesspool never occurs. Though this could limit the Object Pool to containing a specific type of Object. This is because cleaning an Object is almost always subjective to type i.e. cleaning a DisplayObject is different to cleaning a BitmapData. Then thinking about this problem further the solution is "be kind rewind" - so the checkinee must clean before checkin. Problem solved.

And with every problem tackled there is another to solve. Creating an Object is also subjective to type due to parameters it may require in construction :( Unfortunately there isn't as ideal way to construct a Class with a dynamic number of parameters in Actionscript like function.apply offers for Functions. The simplest and most effective solution to this is once again the create process is external also. Another problem solved - hopefully that's all :)

So now that's enough talk on Object Pool's and hopefully it's given you some points to consider when creating your own Object Pool class. There's an example below demonstrating the Object Pool concepts I've used and discussed above and has a small performance victory. What this example demonstrates is the performance cost in reinitializing the particle effect constantly. As you will see there is quite a noticeable difference between pooling or not but when you compare one pool concept over another there's not much difference other than size handling features they offer which could save you performance.

If you would like to download the source code used in this example you can do so here

Simple rotation problem

It's been odd though this week I've been asked about this rotation problem a few times, so it's likely this may help others. This problem occurs when tweening rotation and the visual bug is that it's not using the smallest rotation direction.

To reproduce this rotation problem or visual glitch it seems to only occur when the target angle is after PI and the current angle is before (and vice versa). To fix this is quite simple and it's also interesting to see other peoples different mathematical approaches to solving this common problem, I've seen a few and a fix is a fix but here's mine.

Below is an broken down version of the equation I've used to solve this problem where cA is your current radians and tA is your desired radians.

 
var diff:Number = tA-cA;
var pi:Number = Math.PI;
var pi2:Number = pi*2;
tA += (Math.abs(diff) < pi) ? 0 : (diff>0) ? -pi2 : pi2;
 

Though this equation can easily be done in a single line which is my preference.

 
tA += (Math.abs(tA-cA) < Math.PI) ? 0 : (tA-cA>0) ? -Math.PI*2 : Math.PI*2;
 

Also further to this it's important that the cA and the tA be normalized so they are not greater than Math.PI*2 or less than -Math.PI*2, if you're not sure then this equation will sort this out for you.

 
cA = (Math.abs(cA)>pi2) ? (cA<0) ? cA%pi2+ pi2 : cA%pi2 : cA;
tA = (Math.abs(tA)>pi2) ? (tA<0) ? tA%pi2+ pi2 : tA%pi2 : tA;
 

I also understand some people may not prefer to be using the unit radians to express an angle. If this is you then it's really no problem at all, just make sure cA and tA are in degrees and exchange Math.PI to the equivalent degrees value of 180.

 
tA += (Math.abs(tA-cA) < 180) ? 0 : (tA-cA>0) ? -180*2 : 180*2;
 

I have also included an example SWF below to better demonstrate this situation with and without the fix. To undo the fix change the radio button selection to 'normal' to see the error. In this example the green line is the target angle, the blue line is the current angle and the grey line is the location of PI or 180 degrees.

Flash In The Can 2009 Amsterdam

A couple of weeks ago I was asked by Shawn Pucknell director of the FITC events to talk at the upcoming 2009 conference. I graciously accepted his offer with some degree of terror as I've not presented to a group of people quite as large as the FITC event attracts.

There's a great line-up and more importantly a diversity of presenters from David Carson to Joshua Davis, so I think there will be something for everyone.

My talk will be on 'Efficient programming practices in AS3' and this does sound like the title of a quite dusty and dull book. When I proposed this talk among others (as he wanted a few ideas) to Shawn I had these awful visions of someone ranting for what might seem a lifetime by analysing Actionscript syntax examples to get across what might be an interesting point but instead emptyied the room. So in order to make this topic fun and information packed I will present these concepts visually by the well used practice of analogies. The format of the visuals I can't say yet but don't get your hopes up on some song and dance routine.

The talk is going to be really exciting and challenging for me, so that any one who knows a little Actionscript can get at least one takeaway. Enough said, for a line-up of the speakers or presentations follow the links and hope to see you in Feb 2009.

AS3 SWF Profiler

This handy script applies a profiler option to the right click Flash Context Menu which allows you to debug or track the current FPS or memory used by your SWF. Further to this it also stores a configurable history length of the frame rate and memory performance for the SWF.

Adding this feature into your SWF couldn't be easier than this line of code SWFProfiler.init(stage, this); and adding an import to the class you can download it here.

(The desired frame rate for the above example is 40fps)




Me

I am Shane McCartney an Aussie Flash Developer who's currently working in London on a contractual basis. If you would like to check out some of the work I have done recently, go to my folio at shanemccartney.com.

Donate

If you find the source code or information provided on this site of such use that you would like to donate please do it is appreciated.

Your donation will help us to provide even more source code to the community and cover the cost of time to develop and maintain the source code we provide, thank you.


Meet me at

FITC Toronto