web oriented universal language

Flash 9 Optimizations

Posted on 2008-03-08 by Nicolas Cannasse in General

The new virtual machine than can run AS3 and haXe languages in the Flash Player 9 brings a lot of additional speed for many common operations. This is very good news for developers since you can now write more complex algorithms in Flash such as 3D or Physics engine with correct performances.

However, there are still several pitfalls since some operations are pretty slow when compared to others :

  • creating a new object is slow : if you have a lot of short living objects that are allocated frequently, it's better to create a "Allocator" class that will store a list of reusable instances.
  • calling a lot of methods is not so fast : when you have some small methods that are very often called, it's often faster to rewrite the code directly in the calling method. For example, given a Point class :
    var p = new Point(4,5);
    // the expression :
    p.add(p2.x,p2.y);
    // would be faster if written directly :
    p.x += p2.x;
    p.y += p2.y;
    
    This process of replacing a method call with the actual code is called inlining, and haXe compiler has support for an inline keyword so that you can define which methods will be automatically inlined by the compiler when called (see haXe Documentation)
  • accessing static vars and functions is slow : you can either create an instance and use instance variables and methods instead of static ones or use the haXe inline keyword.
  • reading and writing into arrays is slow : this is very bad news. The only native data structure of Flash9 is painfully slow. It's a lot faster to access a typed instance field than to access an array. One way to optimize that is to create your own linked list :
    // a cell containing instances of MyClass
    class MyCell {
        public var elt : MyClass;
        public var next : MyCell;
        public function new( elt, next ) {
            this.elt = elt;
            this.next = next;
        }
    }
    // a list managing a chained list of MyCell
    class MyList {
        public var head : MyCell;
        public function new() {
            head = null;
        }
        // add an element at the beginning of the list 
        public function add( elt : MyClass ) {
            head = new Cell(elt,head);
        }
    }
    // You can then iterate on your list this way :
    var l : MyCell = mylist.head;
    while( l != null ) {
        var e : MyClass = l.elt;
        // ... do something with e ...
        l = l.next;
    }
    

First, the good news : using a typed linked list is 2 to 3 times faster than using an Array ! (if you want to test that in AS3, make sure to type all your variables, the code here is entirely typed thanks to haXe type-inference)

Now the bad news : you will have a define a MyList and MyCell class for each different class you want to store. So you have to copy/paste the same code again and again. Using Dynamic (or * in AS3) is out of question here since that would require a cast for each reading of an element that would be slow again.

Current haXe users know that the language have typed arrays in order to ensure type-safety. You can also define your own parametrized classes, so it's pretty easy to write-once the following :

// a cell containing any instance
class Cell<T> {
    public var elt : T;
    public var next : Cell<T>;
    public function new( elt, next ) {
        this.elt = elt;
        this.next = next;
    }
}
// a list managing a chained list of cells
class List<T> {
    public var head : Cell<T>;
    public function new() {
        head = null;
    }
    // add an element at the beginning of the list 
    public function add( elt : T ) {
        head = new Cell(elt,head);
    }
}

The problem is that typed-parameters are only used for compile-time type checking. Since the Flash9 VM does not support them, they disappear in the compiled code and are then replaced by the AS3 * type, so all your accesses to the List will need an additional cast... we're back the problem.

Thinking about the problem, I was thinking then : why not let the compiler generate a specific version of the List class for each parameter it will be used ? This way it would generate a List_User and a Cell_User class that can contains User instances, and so on.... automatically at compile time !

That approach was proved quite easy to implement, so it works now in haXe. In order to let the user choose between speed and codesize, the default haXe List class has not been modified, but instead a new haxe.FastList class has been added (accessible when compiling for Flash9).

In order to create your own "generic" classes that will be specialized when used with a type parameter, you can simply have your class implements the haxe.rtti.Generic interface.

Both haxe.FastList and haxe.rtti.Generic are now on haXe CVS (you can download and compile it to give it a try) and will be part of the 1.19 Release.

Conclusion : there's a lot of painful things to do when you want to optimize your code to run fast on Flash9. But thanks to haXe inline and generics, it's a lot more easy to do while keeping your code clean and maintainable.

Comments

You are a genius. Thank you for this information.
Posted by Evan , 2008-03-08 21:33:20
Actually, why note to make FastList be the best list representation depending on the platform? It might be Array for Flash8, and standard List for Neko.. Yes, "best" is not always best, but we can aim to cover most cases, and people can always choose manually.

For this reason, however, it might be even better to leave FastList F9-specific, and make smth like haxe.OptimalList or whatever to be the general best list.
Posted by Michael Pliskin , 2008-03-08 23:18:05
"reading and writing" -- you probably mean: "Appending" and "Iterating" -- because it does not look like you are covering what arrays do best: random-accessing.
Posted by bernard , 2008-04-04 05:57:42
Hi Nicolas,

Below the result of my own bench with AS3 code (done on a dual core with Ubuntu Gutsy and the latest Flash Player 9.0.124.0 ) :

fill a linked list with 100000 elements 577 ms
iterate over a linked list of 100000 elements 46 ms
search 1000 times an element in a linked list 13608 ms
access 1000 times to an element in a linked list 4571 ms

fill an array with 100000 elements 284 ms
iterate over an array of 100000 elements 57 ms
search 1000 times an element in an array 5781 ms
access 1000 times to an element in an array 0 ms

I'm not sure that using a linked list instead of an array is really a good pratice. The only case in which the list is faster is when we iterate over it.
Posted by Abe , 2008-04-09 13:31:06
Please make sure that you are not using the Debug Player since this will negatively impact the performances of haxe.FastList, also try using haXe for the test.

My own benchs show a 2x improve of FastList vs Array iteration. I haven't tested other operations. Adding a element should be slower because it implies allocating a Cell object so yes haxe.FastList is better when mostly iterated and rarely modified.

I'm not sure what you are calling "search" and "access", but of course, accessing the nth element of the list will take O(n) on a list and O(1) for an Array, you shouldn't use such operation on lists anyway.
Posted by Nicolas , 2008-04-15 10:28:08
Have you tried testing the linked list speed against a Dictionary class? I've done tests in the past that show Dictionary running faster than Array for modifying and iterating through a set of values
Posted by Rob , 2008-04-18 12:42:33
fill an array with 100000 elements 284 ms
iterate over an array of 100000 elements 57 ms
search 1000 times an element in an array 5781 ms
access 1000 times to an element in an array 0 ms
Posted by kuri , 2008-04-29 11:13:54
I like it a lot! Nice site, I will bookmark! FastList is better when mostly iterated and rarely modified.
Posted by buy tramadol online , 2008-08-29 19:48:51
Nice site! Thanks!
Posted by Ambien , 2008-12-03 23:36:03
very very compliment sir...
Posted by Francesco , 2008-12-11 18:58:46
Well, thank you very much! You really did a good job! Thank you!
Posted by stainless steel accessories suppliers , 2008-12-17 09:08:20
Thanks for sharing!
Posted by In dash DVD player , 2008-12-19 10:03:01
I think you are right! Thank you very much!
Posted by stainless steel jewelry manufacturer , 2008-12-19 10:08:28
I might tend to agree with you.
Posted by Tamper evident seals , 2008-12-19 10:09:33
Fancy rings come in various sizes, shapes and patterns. Platinum jewelry in patterns that are exotic and new has gained a reputation of being classy. Platinum jewelry embedded with diamonds both small and large in unusual patterns is in vogue. Currently fancy rings that fuse yellow and white gold in trend patterns have grasped the attention of the stylish people.
Posted by Chinese karaoke songs , 2008-12-19 10:11:07
Great
Posted by china CNC router , 2008-12-19 10:12:47
Thanks
Posted by Adalat , 2008-12-29 23:50:49
I was under the impression that type parameters in haXe perform a function similiar to templates in C++. But, according to you, reimplementing MyClass and MyList solution with regards to reusability as List<T> and Cell<T> will yield different performance?

Wouldn't haXe generate two classes based on these two parametrized types? Much like a C++ compiler generates classes from templates, and these classes end up being structures with static offsets (for non-virtual members of course) for data and methods? AVM2 uses the same technic for static types, and Adobe says it is what give it the much better speed.

I don't understand the big difference for using haxe.FastList<T> instead of own List<T>. The compiler should, to my (bad) knowledge, just generate the same class as MyList, instead of the programmer writing such class everytime he wants a different list.

Cheers.
Posted by amn , 2009-05-09 16:01:10

Post a comment

Name:
Email:
Url:
Security: Please enter 2703 here.
remember me
Comment:
 
 
Haxe Powered Rss flux Valid XHTML 1.0 Valid CSS