Categories Displayed in Flash

Archive for the 'performance' Category

AS3: Prelude to Tweeny, a fast and flexible Tweening engine

So I've been working over the weekend on the Tweening engine based on Cogs affectionately called Tweeny. I find it highly amusing as I've been working in Flash since Flash 4, I have built so many presentation engines it borders on comical when every new client inevitably asks for a powerpoint lite clone, and consider myself relatively advanced,..yet how much of a loop this one threw me for.

WhileI had an AS2.0 class already working, it's taken me 3 days to get the basics working in AS3.0. This is because yesterday I totally got schooled on Matrixes with Senocular's most excellent tutorial, (my brain still hurts) and then excited by Penner's lurking MatrixTransform and ended up scrapping several paragraphs that comprise most the standard tween engines. I find myself building this next presentation engine in a way that bears no resemblence to most engines I've used or seen, partly due on the architecture difference between AS3.0 and prior, and partly expanding the role of Tweening beyond the simple display classes. Every time I added a new feature or solved a bug, I found a way to make things simpler.
Matrixes are cool, as you can get away with just easing the Begin and End matrixes rather than doing every calculation, plus you get the ability to offset the registration point and skew, features both very useful for the Authoring type interfaces and kids content I'm creating. More power and more speed to boot! In running performance tests, it's about 2x faster than setting DisplayObject.rotate, DisplayObject.width, scale etc as most tween engines do. Not that running those scripts are typically the limiting factor relative to the overhead in rendering, but still it's nice to know that the underlying code isn't a bottle neck.
Like most Tween engines, Tweeny supports a pluggable easing that affects multiple properties (x, y, width etc) with individual ranges (x[-5, 100], pan[-1,1]). But something my math-whiz girlfriend help me realize was that since duration is fixed, the easing equasion (often filled with expensive Math operations) can be calculated once as the 'normal' and then scaled to the others ranges, cheaply with simple * + . This should significantly reduce tweening calculation overhead,...and dammit I like smart particles flying at 60fps!

To further that I realized that the normalized calculation, is easy to broadcast, so that other listeners keep in synch, and can conceivably modularize or patchwork tweens. One of the things that I've wanted to try for awhlie was a way to balance out top-down easing approaches with bottom up physics routine. This usually involves Euler or Verlet accumulation and integration of forces, but most tweening engines are rather possessive when it comes to updating display objects...only one at a time else they start overwriting, where's the fun in that?
Some other features I like, Sound or SoundChannel volume and pan, colorTransform tweening (which I use a lot for configuration dynamically styled UI's) easier constructors for Bounce and Elastic's extra params which I use with kids games.

One thing that I'm not currently planning on supporting soon is a JSON or XML based interface. I find it poor programming practice to do

TweenEngine.create(target, duration, {x:1,y:2, ....})

in AS3.0 when you can do:

var t:Tweeny = new Tweeny();
t.initFrom(target,duration);
t.x = 1;
t.y = 2;

t.addEventListener(...)

t.startFromBeginning();

Because using fully typed classes allow for autocomplete to help fill out the values, offer stricter type checking and setting of defaults. When they are on a line by line they are easy to comment out to turn on and off. There isn't any overhead to parse XML or JSON into useable values. Since it's part of the Class definition it should also be significantly faster than dynamically allocated Object properties on the prototype.
Keeping a tween around, keeps memory and garbage collection from churning, especially for most applications where the tween is reused over and over again to put thing back and forth. I realize why many tween engines opt not to go this route as managing transitions on top of other transitions can get tricky. But know that I know about these issues I'm glad I spent the extra time. Since Tweeny uses the Playhead API, it supports stop, rewind, play, playbackward etc, it's not really different than keeping an mp3 or swf around.
So far it's about 10K, so 3x larger than say Tweenlite, but much of that is the inclusion of the framework/Cogs is useful for many other things, websites and games especially, and I'm still working on it.
The morning had an epiphany and I was able to tie together many of the related ideas into a cohesive model, so I have a roadmap for the next few months, and even a relatively simple Authoring UI for all the features exposed. Looking at the one pager of noteobook, probably 7 boxes, and only a few UI elements, in that largely what I'm working on is creating much of the same metaphors (e.g. timeline) of Flash inside of Flash...just like Web 2.0 is largely recreating the OS inside of the WebBrowser. And Virtualization is recreating the connectivity of electronics. One that note, if your looking for good book on self-referentiality check out Gödel, Escher, Bach .

FlashCS3: Tip to speed compilation

Flash CS3 has improved compiling speed over Flash8, however seemingly innocent use fonts can still bring compile times to a halt. with a font like Futura, an missed 'embed All' can turn your compile times to 30-45 seconds, as every compiler requires Flash to copy every character in the entire world...every time. Needless to say 15-30 seconds doesn't seem like much, but if your compiling often, this can reduce

Going through and removing font embedding from every textfield is somewhat tedious. But you can use the MovieExplorer to help drill down, you may even find text fields you've missed. I'm sure somebody has a JSFL to help.
The other tips are when using Flash CS3 and blessed with a timeline, put a temporary script (gotoAndPlay) to skip the intros and tutorials to delve into the heart of the what your working on at any given time. When using Cogs you can do similar things by passing a non-default initial state in the constructor.

AS3 Performance relative to Java, Javascript, AS2

Good article. For most things Java was 3 times faster, but of course nobody really writes for Java applets. Javascript versus Flash is tricker, and as one can see highly browser dependent...huge differences! I'm so glad I'm not working directly on DHTML apps.
http://www.oddhammer.com/actionscriptperformance/set4/

Working in flash is a bit like a cake on a platter. The cake (your swf) can come in all sorts of flavors that you as a cook can make, and is flexible in shapes, but when hitting the platter (the flash player) you lose this customizability, it's there to allow your cake to stand.

When dealing with actionscript, some code is the icing (your classes), some the cake (flash's instrinsic classes), and some is the platter (functions that are actually natively implemented in C). Depending on how many layers of icing and cake one has to get to before hitting platter, can make orders of magnitude difference. The fastest interpretted actionscript is always slower than the native function calls, as in the end everything has to get boiled down to simpler native calls.
There are many features in flash implemented 'natively' (event dispatching, e4X, binary data + AMF) and as such using them when possible over rolling your own classes, as it may be an order of magnitude faster. This is why it's good to spend time just reading through the packages to understand what is possible, prior to writing your own, as there are many portals into the underlying player substrate.

This has implications on architecting applications. Even if the algorithm in has been tweaked for hours, the 'cleanest' solution may ironically perfom worse, because you're only adding layers of cake and icing instead of going lower.. This often happens when porting proven projects from other languages, or keeping application frameworks in synch on a webserver and flash.

AS3 and Serialization, Memento Pattern

Starting to work on porting the persistence aspect of Prevayler to Flash/AS3. It's a perfect fit with Flash, as Prevaylence assumes that everthing can fit into RAM (which flash does, aside from loading new things in), and changes have to be synchronized, which seeing as it's a primarily a single thread doesn't have to worry about synchronizing multiple writes.
Prevaylence relies heavily on understanding the serialization of objects, both the commands and the business object state should be save and restoreable. Since ByteArray supports AMF packets (as does shared object) this means that private vars and Class definitions, functions should be able to be written to disk and brought back from dead...but this leaves the larger question, just like the dinosaurs ...should they be brought back?
It's certainly tempting.  Java has faced this for years in it's serialization routines. In general built in serializing is good, but doing it across version is bad, as it's inevitable that the Class definition will change, adding, removing variables and methods ...even changing types, during refactoring. When reconstituting things may not serialize properly much as you don't fit into your GI Joe pajamas from kindergarden (well hopefully). It's unpredictable what the Flash player will do when forced to put version 1.2 into 1.3 shoes, or potentially version 1.4 into 1.2.  So it's important to know exactly what is being saved and how flexible it is.

Since I was working on Trace.me this week, and private, protected, etc variables didn't show up in the output, (which is proper Object encapsulation), I was curious as to if the variables were invisible or lost. I remembered  hitting similar things when working with and on openAMF, so I dug a bit, and just found a document I wrote a few years ago, on openAMF, ah good times...

http://openamf.cvs.sourceforge.net/*checkout*/openamf/openamf/docs/understanding.htm?revision=1.1

There the issue there was different, was actually whether java's accessors e.g. get someValue and set someValue translated across the wire. The serialization in Java openAMF calls the accessors and puts them into a hashmap, before sending across the wire. Flash does something similar when sending back to the server, skipping the accessors as back then it didn't really know what those were. But I wasn't sure if this was the case when targetting ByteArray and Shared Local Object for output.

I have an dummy object called IntrospectableObject, it has all manner of public, private, protected etc vars of all different types (well at least enough to test), I've been using to test. I've added a few accessors and a toString method which outputs everything.

The code to test ByteArray as a serialization is simple

import flash.net.SharedObject;
import com.troyworks.prevayler.*;
import flash.utils.ByteArray;
import flash.net.registerClassAlias;
import flash.utils.describeType;

////////////// BYTE ARRAY TESTS ////////////////

var bA:ByteArray = new ByteArray();
//registerClassAlias("com.troyworks.prevayler.IntrospectableObj", IntrospectableObj);
var iObj:IntrospectableObj = new IntrospectableObj();

bA.writeObject(iObj);
bA.position = 0;
var aObj:Object = bA.readObject();
trace("aObj " + aObj.toString());

trace("XML " + describeType(iObj).toXMLString());
trace("attempting to introspect ");
for (var i:String in aObj){
trace( i + " " + aObj[i]);
}

It outputs:

new Introspectable //consturctor of source
aObj [object Object]
attempting to introspect
pubStrVar public testString
pubBooTrueVar true
pubVar undefined
pubUIntVar 1
pubIntVar -1
pubNumVar 0.5
pubBooFalseVar false
pubDateVar Wed Aug 29 02:40:48 GMT-0700 2007

which reveals no accessors are called, and nothing but public vars are called, which is to be expected. Uncommenting:

registerClassAlias("com.troyworks.prevayler.IntrospectableObj", IntrospectableObj);

We get something completely different. As it's creating a new class upon reconstitution, and then calling it's toString() which has access to the private/internal so can see more. This means that ByteArray does get the whole picture even if it doesn't share all of it.

new Introspectable //constructor of source
new Introspectable  //constructor of reconstructed
aObj pubStrVar public testString
pubNumVar 0.5
pubIntVar -1
pubUIntVar 1
pubBooFalseVar false
pubBooTrueVar true
pubDateVar Wed Aug 29 03:00:12 GMT-0700 2007
priStrVar priTestString
priNumVar 0.2
priIntVar 2
priUIntVar 2
priBooFalseVar false
priBooTrueVar true
pritDateVar Wed Aug 29 03:00:12 GMT-0700 2007
attempting to introspect
--none--- //can't see anything as it's now class based.

What interesting is simliar to AMF, the constructor is called by Flash/AS3, but the values of the items as serialzed overwrite, bypassing the encapsulation layer (and thus any events). This is good if sometimes tricky to remember. It's resetting the snapshot of the object's state. Which compared to broadcasting a dozen+ change events makes sense, as it really hasn't changed, it's just been restored. This is basically what we want but as prior this may hit the shoes don't fit problem, break on newer swfs with different code coming out.

What this indicates to me is that serialization for Prevayler like approaches, should be done via the memento pattern, and only the mementos should be serialized. Wikipedia has a good article on it.
http://en.wikipedia.org/wiki/Memento_pattern  which interestingly links to a large page on finite state machines. which uses the memento pattern to save state/shallow history, with extended variables.
http://en.wikipedia.org/wiki/Finite_state_machine

Both the business logic and the commands should implement the pattern.  Mementos immutable read-only ideally, with all values passed into the constructor and only accessible via getters. But if the number of attributes are large, I could see a Object/struct with purely public variables may be better for useability and performance, as Mementos shouldn't do anything. In addition, Mementos should have a version number of the 'file format', and preferrably some mechanism can faciliate putting the data in via calling getters on the originator object, if they aren't marked as non-serializable (e.g. calculated results like totals shouldn't be serialized). Which I often like to put into a separate class, as the serialization/deserialization may be for different formats, XML, and they aren't really 'business object' concerns. One could even use the namespace feature to manage which one is being used.
This is exciting to me as Shared Local Object is cheap and fast and shared..a great place for multiple flash movies potentially in different web pages, maintaining a common log. Inside AIR's using it's DB, is another good place to store offline/online commands that get synched back up..potentially against other users making changes at one, when connected again.
This would take Flash RIA's closer to conventional applications, even if they are microcontent. It's always annoyed me how long running flash games how some don't remember where you are, using cheat codes so you can jump to a particular level, and that undo is so problematic, so it's either being petrified to explore for fear of making a mistake or having to do the same thing over and over again. There are many games I'd play longer if these capabilities existed. Flash makes these features easy,  it's just that most applications aren't written to support.
Since ByteArray can be compressed and written to Strings, this means they can be files, and thus to disk somewhere, be it SaveAs in AIR,  POST, XML. Sockets, meaning that a saving a application and then logging into another machine and getting everything back would be easy, or potentially opening and saving multiple versions so people can try things or create things easily.

AS3 Performance Optimizations

Summary, use linked lists instead of Array indexes for fastest performance in traversing collections.
http://blog.je2050.de/2007/06/06/lists-faster-than-array/

Performance: Strict equality === versus compare by value ==

One of the cool features little used in actionscript is the strict equality operator '===' what this does is evaluate if two pointers endup at the same address in memory, rather than the contents of that address. This is similar to the performance increase of looking at the mailing address on two envelopes rather than actually going to the address, knocking on the door to see who lives there. But this only works for pass by reference (Object) vrs pass value types (e.g. int, uint, boolean) and during comparions those that don't compare by value (e.g. Number, String).

Coding wise, I also like switch statements, they are clean visually and semantically, and AS3 has the neat feature to allow any type to act as a switch value, other languages like Java/.Net restrict case statements to primitives numbers, or strings.

I created a class to test raw performance of different types/approaches used in switch statements, primarily to determine whether strings (as passed by event e.g. Event.type), numbers or signals (as done by cogs) is faster approach, and if switch statements could use strict equality or by value.
Full Fledged Classes used as the case statement and switch are the fastest at close to 1/3 the time. This is great as it offers author time compile checking, strong typing at runtime. Lookups are likely by identity (===) instead of by value (==) as in data types even when those are marked static and constant, which means performance is about twice that of using a value comparison, in addition, since they are fullfledged objects they can contain all sorts of things (e.g. toString, operations).
Downside is that no numerical id is attached by number by default, so it's harder to index and later lookup these values when they exist in a random collection of some sort, but since it's a full fledged object, adding an id variable is easy.

In the class containing the switch, e.g.

//277ms for 100K
switch(stringVal){

case JanuaryStaticConst:
case "January":
break;
}

//177ms for 100K
switch(intVal){

case 22:
break;
}

//166 ms for 100K iterations

switch(objRef){

case Class.StaticVal:
break;
}

//98 ms for 100K iterations

static const var StaticVal = Class.StaticVal;
switch(objRef){

case StaticVal:
break;
}

Flash's compiler doesn't replace Class.StaticVal, with StaticVal so there is a lookup overhead. So it's recommended that you capture a reference in a static const (see recommendations at end)
For primitive data types (String, number, int, etc), strings are about 70% slower than any numbers, potentially the length of
the string may also impact the performance (not tested). Note that even making the string a static const string offered
no performance increase (though probably a significant memory performance increase) because your using value comparison (==) in the switch statement
versus identity (===).

The fastest numerical type, was an typically an int though this wasn't really repeatable, or significant. But might
make sense to use if your using it as bitflag.

Test Results for 100K iterations:
SwitchNumber 177
switchInt 176
switchUInt 170
switchString 277
switchStringConst 275
switchIntConst 175
switchCogSignal 166 <-- lookup of CogSignal.SIGNAL
switchCogSignalB 97 <-- 'cached' CogSignal.SIGNAL pointer (set via static constructor)
switchSwitchSignal 98 <- declaring it internally
Recommendations:
1) use a custom class, static const on the class
e.g.

//cache the value during class/static initialization
public static const C_0:SwitchSignal = SwitchSignal.C_0;

and later

public function switchSwitchSignal(sig:SwitchSignal):void{
switch(sig){
case C_0: //SwitchSignal.C_0, but no lookup overhead.

2) for raw data types use int, instead of (uint, Number).