Yesterday a “tweet” pointed me to a nice article about ActionScript 3.0 optimization. Most of these techniques are quite common within the ActionScript developer scene but one thing caught my attention: A link to Jackson Dunstans blog post about runtime performance and the const
and final
keywords. Since I always tried to use at least final classes I was a little disappointed that my extra work time doesn’t have any performance benefit at runtime.
Due to that circumstance I was curious about some other common techniques like “Use Object and Array Literals Whenever Possible” or “Add Elements to the End of an Array Without Pushing”. I wanted to check performance benefits for myself just to make sure it’s worth the effort. So I wrote a little test script:
var result : String = "Test playerType: " + Capabilities.playerType + " version: " + Capabilities.version + "\n",
i : int = 0,
c : int = 1000000,
array : Array,
object : Object,
vectorInt : Vector.<int>,
startTime : int;
startTime = getTimer();
for ( i = 0; i < c; i++ ) { object = new Object(); }
result += c + " times: object = new Object() -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { object = {}; }
result += c + " times: object = {} -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { array = new Array(); }
result += c + " times: array = new Array() -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { array = []; }
result += c + " times: array = [] -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { vectorInt = new Vector.<int>(); }
result += c + " times: vectorInt = new Vector.<int>() -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { vectorInt = new <int>[]; }
result += c + " times: vectorInt = new <int>[] -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { array.push( i ); }
result += c + " times: array.push( i ) -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { array[ array.length ] = i; }
result += c + " times: array[ array.length ] = i -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { vectorInt.push( i ); }
result += c + " times: vectorInt.push( i ) -> duration: " + String( getTimer() - startTime ) + "\n";
startTime = getTimer();
for ( i = 0; i < c; i++ ) { vectorInt[ vectorInt.length ] = i; }
result += c + " times: vectorInt[ vectorInt.length ] = i -> duration: " + String( getTimer() - startTime ) + "\n";
var textFormat : TextFormat = new TextFormat();
textFormat.font = "Courier";
textFormat.size = 14;
var textField : TextField = new TextField();
textField.autoSize = TextFieldAutoSize.LEFT;
textField.background = true;
textField.backgroundColor = 0xFFFFFF;
textField.defaultTextFormat = textFormat;
textField.multiline = true;
textField.text = result;
addChild( textField );
It turns out that the benefits differ greatly on platform and player type but basically it’s always a good idea to avoid using the .push
methods and new
keyword. While there’s almost no speed difference in Flash Players and Plug-ins, the debug versions are really slow. And check out the blazing fast object creation with AIR on iOS! Or is this a compiler optimization? Here my results:
Flash CS 5 publish
Test playerType: External version: MAC 10,1,52,14
1000000 times: object = new Object() |
-> duration: 246 |
1000000 times: object = {} |
-> duration: 427 |
1000000 times: array = new Array() |
-> duration: 1288 |
1000000 times: array = [] |
-> duration: 339 |
1000000 times: vectorInt = new Vector.() |
-> duration: 586 |
1000000 times: vectorInt = new [] |
-> duration: 596 |
1000000 times: array.push( i ) |
-> duration: 134 |
1000000 times: array[ array.length ] = i |
-> duration: 137 |
1000000 times: vectorInt.push( i ) |
-> duration: 113 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 114 |
Flash Player Debugger.app
Test playerType: StandAlone version: MAC 11,1,102,62
1000000 times: object = new Object() |
-> duration: 179 |
1000000 times: object = {} |
-> duration: 311 |
1000000 times: array = new Array() |
-> duration: 1072 |
1000000 times: array = [] |
-> duration: 313 |
1000000 times: vectorInt = new Vector.() |
-> duration: 397 |
1000000 times: vectorInt = new [] |
-> duration: 402 |
1000000 times: array.push( i ) |
-> duration: 118 |
1000000 times: array[ array.length ] = i |
-> duration: 108 |
1000000 times: vectorInt.push( i ) |
-> duration: 111 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 89 |
Flash Player.app
Test playerType: StandAlone version: MAC 11,1,102,62
1000000 times: object = new Object() |
-> duration: 127 |
1000000 times: object = {} |
-> duration: 183 |
1000000 times: array = new Array() |
-> duration: 227 |
1000000 times: array = [] |
-> duration: 189 |
1000000 times: vectorInt = new Vector.() |
-> duration: 215 |
1000000 times: vectorInt = new [] |
-> duration: 218 |
1000000 times: array.push( i ) |
-> duration: 72 |
1000000 times: array[ array.length ] = i |
-> duration: 62 |
1000000 times: vectorInt.push( i ) |
-> duration: 61 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 42 |
Browser Debug Plug-in (Safari)
Test playerType: PlugIn version: MAC 11,1,102,62
1000000 times: object = new Object() |
-> duration: 157 |
1000000 times: object = {} |
-> duration: 249 |
1000000 times: array = new Array() |
-> duration: 1015 |
1000000 times: array = [] |
-> duration: 293 |
1000000 times: vectorInt = new Vector.() |
-> duration: 281 |
1000000 times: vectorInt = new [] |
-> duration: 282 |
1000000 times: array.push( i ) |
-> duration: 124 |
1000000 times: array[ array.length ] = i |
-> duration: 117 |
1000000 times: vectorInt.push( i ) |
-> duration: 124 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 94 |
Browser Plug-in (Google Chrome)
Test playerType: PlugIn version: MAC 11,2,202,235
1000000 times: object = new Object() |
-> duration: 147 |
1000000 times: object = {} |
-> duration: 146 |
1000000 times: array = new Array() |
-> duration: 237 |
1000000 times: array = [] |
-> duration: 224 |
1000000 times: vectorInt = new Vector.() |
-> duration: 257 |
1000000 times: vectorInt = new [] |
-> duration: 266 |
1000000 times: array.push( i ) |
-> duration: 54 |
1000000 times: array[ array.length ] = i |
-> duration: 61 |
1000000 times: vectorInt.push( i ) |
-> duration: 70 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 51 |
AIR SDK 3.2
Test playerType: Desktop version: MAC 11,2,202,223
1000000 times: object = new Object() |
-> duration: 274 |
1000000 times: object = {} |
-> duration: 243 |
1000000 times: array = new Array() |
-> duration: 1344 |
1000000 times: array = [] |
-> duration: 379 |
1000000 times: vectorInt = new Vector.() |
-> duration: 431 |
1000000 times: vectorInt = new [] |
-> duration: 426 |
1000000 times: array.push( i ) |
-> duration: 135 |
1000000 times: array[ array.length ] = i |
-> duration: 136 |
1000000 times: vectorInt.push( i ) |
-> duration: 153 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 74 |
iOS (iPad 3) debug interpreter
Test playerType: StandAlone version: MAC 11,1,102,62
1000000 times: object = new Object() |
-> duration: 4707 |
1000000 times: object = {} |
-> duration: 2033 |
1000000 times: array = new Array() |
-> duration: 22191 |
1000000 times: array = [] |
-> duration: 2993 |
1000000 times: vectorInt = new Vector.() |
-> duration: 10235 |
1000000 times: vectorInt = new [] |
-> duration: 10156 |
1000000 times: array.push( i ) |
-> duration: 1728 |
1000000 times: array[ array.length ] = i |
-> duration: 1670 |
1000000 times: vectorInt.push( i ) |
-> duration: 2056 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 1951 |
iOS (iPad 3) ad-hoc
Test playerType: Desktop version: IOS 11,2,202,223
1000000 times: object = new Object() |
-> duration: 1224 |
1000000 times: object = {} |
-> duration: 0 !!! |
1000000 times: array = new Array() |
-> duration: 5886 |
1000000 times: array = [] |
-> duration: 1048 |
1000000 times: vectorInt = new Vector.() |
-> duration: 2737 |
1000000 times: vectorInt = new [] |
-> duration: 2784 |
1000000 times: array.push( i ) |
-> duration: 2043 |
1000000 times: array[ array.length ] = i |
-> duration: 234 |
1000000 times: vectorInt.push( i ) |
-> duration: 1524 |
1000000 times: vectorInt[ vectorInt.length ] = i |
-> duration: 643 |
Always worth reading: http://gskinner.com/talks/quick/