ActionScript performance test for Array, Object, Vector literals and Array.push, Vector.push methods

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/

Avoid iFrame content clipping with CSS transform on iOS

The HTML(5) version of our SCORM based e-learning runtime heavily uses i-frames as template containers. This architecture gives a lot of flexibility but since customers mainly request iPad support we where very unhappy with Safari’s rendering capabilities on iOS. Of course we use CSS transform to get the best animation performance on mobile devices, but in Apple’s mobile browser you’ll likely see huge clipping rectangles during hardware accelerated transitions.

There was not much information about that issue online but at least this entry on stackoverflow suggested there is not much you can do. Well, it took a lot of trail an error testing time but finally we nailed it. The solution is quite simple:

Whenever you use CSS transform with i-frames or it’s parents you also need to apply a basic CSS transform to the body tag of your i-frame content. That’s it. You can also use other contents within the loaded frame HTML page but the body tag seems to be the perfect target.

So this is a little JavaScript code snipped:

// Reference to your iFrame HTML element
var iFrameElement = document.getElementById( "yourIFrameID" );
 
// Avoid clipping by applying simple css transfrom3D to the iframe content itself
$( iFrameElement.contentWindow.document.body ).css( "-webkit-transform", "translate3d(0,0,0)" );
 
// Start your iFrame transition (from a visible position)
$( iFrameElement ).css( "-webkit-transform", "translate3d(-1000px,0,0)" );

UPDATE: Make sure you start from a visible position!

Don’t forget to remove CSS transform after your animation is done:

// Don't forget to reset after your transition has finished!
$( iFrameElement.contentWindow.document.body ).css( "-webkit-transform", "none" );

I suggest to use “none” as the default value. We sometimes experienced weird behavior using an empty string…

Have fun coding!

Adobe AIR 2.7: Faster App Performance on iOS

Get a big performance boost on iOS using Adobe AIR 2.7 SDK!

Adobe’s current release version includes a number of feature enhancements:

  • Install AIR Runtime to SD (Android)
  • Improved performance on iOS
  • Media Measurement
  • Acoustic Echo Cancellation (Desktop only)
  • Enhanced HTMLLoader API
  • Interpreter Mode for iOS

Read full details here: http://blogs.adobe.com/flashruntimereleases/2011/06/14/air-2-7-runtimes-and-sdk-are-now-available/

See the performance:

Don’t know where to start? This guide is still valid: iOS development with AIR 2.6 using FDT and my new friend ANT

FFK11 – beyond tellerrand notes

I’m still not sure if “beyond tellerrand” is a subtitle or will become the new brand for the one and only Flashforum conference here in germany. Sascha Wolter and Marc Thiele did a great job as always and even I never went to another conference, FFK seems still to be a special one. Again I was lucky listening to some really cool stuff.

Interestingly most of my last year notes are still up to date, which doesn’t help if you don’t keep them in mind. So I think it’s a good idea to read my own notes from time to time. 😉

That’s what I became aware of this time:

AIR 2.6

  • Lee Brimelow mentioned AIR 2.6 on iOS is faster than on Android! Yeah.
  • Adobe is working hard on increasing performance near to native code.
  • Installing a runtime seems to be annoying for Android users, so Adobe is thinking about compiling for Android like for iOS. Which might bring some extra performance as well.
  • I asked Lee Brimelow about AIR on Windows Phone 7 and he said something like “Adobe is currently not working on that and it would be a lot of work”. Well, of course Microsoft is not interested having AIR on their system, but it would be a really important platform for all of us. So in my opinion Adobe at least has a small team checking out what’s possible. What do you think about Windows Phone 7 and AIR support?

Flex Builder 4.5

  • You can get Flex SDK 4.5 already, but there’s also a way to join the private pre-release program to get early access to Flex Builder 4.5. Just visit http://www.surveymonkey.com/s/flexprerelease. They are working on some useful stuff and it might be a good idea to test some of the new features.
  • Deepa Supramaniam mentioned spark MXML skins have performance issues on mobile devices. That’s why they created pure ActionScript spark skins for mobile applications. Hopefully, within the private beta Flex SDKs, we’ll find some great improvements: http://www.riagora.com/2011/03/preview-of-flex-on-ios/.

NUI

  • Wolfgang Henseler (Talk I missed at FFK10) opened my mind according NUI.
  • Don’t think of apps on mobile devices but of services allowing you reaching your goal faster than a website.
  • Think about providing services, combining them, rethinking them.
  • Use less design and let objects provide their functionalities (e.g. tap on image to get some options).
  • My brain is very busy with that NUI thing. E. g. he mentioned the Siri iPhone app. It’s not about how it looks like (not so cool) but how it works! Combining lots of possibilities with a really easy interface (speech) . He was also talking about “in body technology” (sensors and stuff like that.) and http://www.tedmed.com/
  • After Dennis Ippels Kinect (OpenKinect / http://www.primesense.com/) introduction I finally know something about the magic behind this device as well.

Molehill

Additional useful links:

iOS development with AIR 2.6 using FDT and my new friend ANT

Adobe recently released AIR 2.6 with improved iOS support, so I finally had to get into using ADT with ANT. My editor of choice is FDT so I wanted to do as less extra work as possible. Mainly because I’m no terminal-guy. I need a clean GUI holding my hand while setting up workspaces, linking libraries and stuff like that. In other words, command line and compiler arguments are freaking me out. 😉

I read a lot of blogposts and articles (see link list on the bottom of this post) but most of them compile SWFs using ANT, which means setting source path and stuff like that as command line arguments. But hey, FDT does this already during my daily workflow, so to me it seems natural reusing this within the iOS packaging process.

So I won’t comment a lot what I came up with because all of this can be read on one of the sites below, but show you simply a screenshot of my “IOSAIRTest” workspace structure and of course the ANT files. Notice that I’m not into having different directories for debug, publish, testing and so. I like to have all source files clean and separated by file type (would have an mxml folder too):

You will find the most interesting files in src/ant. Let’s start with local.properties which just defines the SDK path:

FLEX_HOME=/Users/{USERNAME}/Path/To/FlexSDKs/4.5.0.17689_AIR_2.6
MXMLC=${FLEX_HOME}/bin/mxmlc
ADT=${FLEX_HOME}/bin/adt

Within build.properties you setup all params regarding your project:

app.rootdir=./../..
app.descriptor=${app.rootdir}/bin/IOSAIRTest-app.xml
app.rootfile=IOSAIRTest.swf
app.sourcedir=${app.rootdir}/src/as
app.bindir=${app.rootdir}/bin
app.source=${app.sourcedir}/de/superclass/IOSAIRTest.as
app.includes=assets icons Default.png Default-Portrait.png
 
build.storetype=pkcs12
build.keystore=${app.rootdir}/resources/ios/iPhoneDevCert.p12
build.storepass={PASSWORD;)}
build.mobileprofile=${app.rootdir}/resources/ios/AIR_TEST.mobileprovision
build.name=IOSAIRTest.ipa
 
fdt.projectname=AIRTest
fdt.mainclass=${app.source}
fdt.target=${app.bindir}/${app.rootfile}

And build.xml contains four ways to create the IPA package and the according FDT tasks:

<?xml version="1.0" encoding="UTF-8"?>
<project name="AIR export" basedir=".">
 
	<property file="local.properties" />
	<property file="build.properties" />
 
	<!-- FDT tasks
 
		see http://fdt.powerflasher.com/docs/FDT_Ant_Tasks#fdt.launch.application - for documentation
		see http://fdt.powerflasher.com/docs/FDT_and_Ant_Tutorial#Your_First_Task:_Compiling_.26_JRE_Error - if you run into errors!
	-->
 
	<target name="FDT create SWF">
		<fdt.launch.resetFlexCompiler/>
		<fdt.launch.application
			projectname="${fdt.projectname}"
			mainclass="${fdt.mainclass}"
			profile="false"
			debug="false"
			target="${fdt.target}"
	    	startswf="false"/>
	  </target>
 
	<target name="FDT create SWF debug">
		<fdt.launch.resetFlexCompiler/>
		<fdt.launch.application
			projectname="${fdt.projectname}"
			mainclass="${fdt.mainclass}"
			profile="false"
			debug="true"
			target="${fdt.target}"
	    	startswf="false"/>
	  </target>
 
	<!-- ADT tasks -->
 
	<target name="iOS create IPA debug" depends="FDT create SWF debug">
		<exec executable="${ADT}">
			<arg line="-package
						-target ipa-debug
						-storetype ${build.storetype}
						-keystore ${build.keystore}
						-storepass ${build.storepass}
						-provisioning-profile ${build.mobileprofile}
						${app.bindir}/${build.name}
						${app.descriptor}
						-C ${app.bindir} ${app.rootfile} ${app.includes}
			"/>
		</exec>
	</target>
 
	<target name="iOS create IPA test" depends="FDT create SWF">
		<exec executable="${ADT}">
			<arg line="-package
						-target ipa-test
						-storetype ${build.storetype}
						-keystore ${build.keystore}
						-storepass ${build.storepass}
						-provisioning-profile ${build.mobileprofile}
						${app.bindir}/${build.name}
						${app.descriptor}
						-C ${app.bindir} ${app.rootfile} ${app.includes}
			"/>
		</exec>
	</target>
 
	<target name="iOS create IPA ad-hoc" depends="FDT create SWF">
		<exec executable="${ADT}">
			<arg line="-package
						-target ipa-ad-hoc
						-storetype ${build.storetype}
						-keystore ${build.keystore}
						-storepass ${build.storepass}
						-provisioning-profile ${build.mobileprofile}
						${app.bindir}/${build.name}
						${app.descriptor}
						-C ${app.bindir} ${app.rootfile} ${app.includes}
			"/>
		</exec>
	</target>
 
	<target name="iOS create IPA app-store" depends="FDT create SWF">
		<exec executable="${ADT}">
			<arg line="-package
						-target ipa-app-store
						-storetype ${build.storetype}
						-keystore ${build.keystore}
						-storepass ${build.storepass}
						-provisioning-profile ${build.mobileprofile}
						${app.bindir}/${build.name}
						${app.descriptor}
						-C ${app.bindir} ${app.rootfile} ${app.includes}
			"/>
		</exec>
	</target>
 
</project>

If you’re not sure how to get started with all this AIR 2.6 stuff because it’s currently not integrated in the Flex SDKs – follow this steps:

Loads of linked informations:

http://blogs.adobe.com/cantrell/archives/2011/03/how-to-use-air-2-6-with-flash-builder-4.html
http://www.mobilerevamp.org/2010/07/30/how-to-build-your-first-air4android-application-using-fdt-and-eclipse/
https://code.google.com/p/air-on-android-with-fdt/
http://www.beautifycode.com/flex-hero-mobile-project-template-for-fdt-4-2
http://www.beautifycode.com/publish-package-an-air-file-with-fdt4
http://labs.almerblank.com/2011/03/using-ant-to-compile-a-flex-mobile-project-for-ios/
http://va.lent.in/blog/2011/03/25/air2-6-app-for-ios/ (Thanks for ANT files!)
http://developerartofwar.com/2011/03/24/air-2-6-on-ipad-2-in-15-mins/
http://karoshiethos.com/2010/04/06/use-fdt-folder-path-variables-in-ant/
http://fdt.powerflasher.com/docs/FDT_Ant_Tasks#fdt.launch.application
http://labs.almerblank.com/2011/03/using-ant-to-compile-a-flex-mobile-project-for-ios/

Update:
http://www.blackcj.com/blog/2011/04/04/ios-android-and-blackberry-in-a-single-click-with-ant/

Flash on iOS issue with flash.net.navigateToUrl( );

I’m playing around with Flash packager for iPad and iPhone and it seems like there might be some restrictions on accessing files bundled with the application and delivered within the application directory.

During some video tests I delivered one h.264 video within the application directory and tried starting it using this code invoked on a MouseDown event:

var file : File = File.applicationDirectory.resolvePath( "video.mp4" );
navigateToURL( new URLRequest( file.url ) );

But nothing happened. Really nothing. No thrown error. It’s like I simply didn’t call navigateToUrl. Of course everything works fine with remote URLs so I’m quite sure I didn’t make a mistake.

After several different approaches I figured out I couldn’t access any of my files within the app:/ directory. Regardless of the filetype. Well, at least it didn’t work on my devices: iPhone with iOS 4.1 and iPad with iOS 3.2.2.

There’s a discussion about that the Adobe forums: http://forums.adobe.com/message/2979185

iPhone / iPad ActionScript Guide quotes

As I mentioned here I strongly recommend to read Adobe’s Building ADOBE® AIR® Applications with the Packager for iPhone® guide or Flash Platform for iPhone.

Just some ActionScript facts:

ActionScript APIs unsupported on mobile devices
ActionScript APIs specific to mobile AIR applications
ActionScript APIs of special interest to mobile application developers

iPhone / iPad Development Guide quotes

Since I’m diving deeper into Flash for iOS devices I strongly recommend to read Adobe’s Building ADOBE® AIR® Applications with the Packager for iPhone® guide or Flash Platform for iPhone.

Beside the know how of subscribing as a Apple developer, obtaining certificates and so on I think this informations are quite valuable but easy to forget:

iPhone icon and initial screen images

The iPhone adds a glare effect to the icon… To remove this default glare effect, add the UIPrerenderedIcon key to the InfoAdditions element in the application descriptor file…

All iPhone applications display an initial image while the application loads on the iPhone. You define the initial image in a PNG file named Default.png stored in the main development directory… The Default.png file is 320 pixels wide by 480 pixels tall, regardless of the initial orientation of the application or whether it is full-screen or not.

The iPhone displays its status bar over the 20 pixel-wide rectangle at the top or left of the default image.

For iPad support, you can define images for each supported initial orientation (Default-Portrait, Default-PortraitUpsideDown, Default-LandscapeLeft, Default-LandscapeRight.png)… Initial screen images for the iPad are 768 pixels wide and 1024 pixels high.

iPhone application settings

There must be way more settings than this:

<iPhone><InfoAdditions><![CDATA[
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleBlackOpaque</string>
<key>UIRequiresPersistentWiFi</key>
<string>NO</string>
]]></InfoAdditions></iPhone>

Debugging an iPhone application

Debugging the iPhone App over Wi-Fi is possible and GPU rendering diagnostics can be activated at compile time.

Continue reading about more specific ActionScript notes here.

iPad says hello to Flash community

Hello iPad. Maybe Apple denied compiling Apps with Flash because they just had problems delivering enough iPads to the Flash community? 😉

Since customer requests grow and a new version of iPad seems to appear on the horizon I decided to get one of the 1. gen. iPads for testing purposes. I’m looking forward developing parallel solutions for the web and the iPad / iPhone and I see myself fighting against system limitations like the old days where we had to test our Flash 4 projects on PCs much slower than current mobile devices.

Ride it baby!