Friday, March 26, 2010

Adventures with Haxe!

Today this project called Haxe has come to my attention. Its a language very similar to Actionscript3 which can compile to flash bytecode ( among many other possible targets ).

The project claims its compiler produces better performing swf files than the as3 flex compiler and the language adds a features which are just lovely ( Type inference, more detailed function types, c-like local variable scopes, iterators, etc. ) so trying it out was irresistible.

I decided to test the inline function feature by implementing a 2d vector class:

class Vec2f
{
public var x:Float;
public var y:Float;

public function new( x : Float, y : Float ) {
this.x = x;
this.y = y;
}

public inline function inlineAdd( v : Vec2f ) : Vec2f {
x += v.x;
y += v.y;
return this;
}

public function add( v : Vec2f ) : Vec2f {
x += v.x;
y += v.y;
return this;
}
}

And made a few simple benchmarks:

package ;

import flash.geom.Point;
import flash.Lib;
import org.flashdevelop.utils.FlashConnect;

class Main
{
static inline var TestIterations = 99999999;

static inline var Inline = 0;
static inline var NonInline = 1;
static inline var ManualInline = 2;
static inline var ManualVariableInline = 4;

static inline var TestKind = ManualVariableInline;

static function main()
{
if ( TestKind == NonInline ) {

// ***************************************
// Non inline test:
// ***************************************
var v1 = new Vec2f(0, 0);
var v2 = new Vec2f(1, 1);
var startTime : Int = Lib.getTimer();
for ( i in 0...TestIterations ) v1.add( v2 );
var endTime : Int = Lib.getTimer();
FlashConnect.trace( "Non Inline Method: " + (endTime - startTime) );

}else if ( TestKind == Inline ) {

// ***************************************
// Inline test:
// ***************************************
var v1 = new Vec2f(0, 0);
var v2 = new Vec2f(1, 1);
var startTime : Int = Lib.getTimer();
for ( i in 0...TestIterations ) v1.inlineAdd( v2 );
var endTime : Int = Lib.getTimer();
FlashConnect.trace( "Inline Method: " + (endTime - startTime) );

} else if ( TestKind == ManualInline ) {

// ***************************************
// Manually inlined test:
// ***************************************
var v1 = new Vec2f(0, 0);
var v2 = new Vec2f(1, 1);
var startTime : Int = Lib.getTimer();
for ( i in 0...TestIterations ) {
v1.x += v2.x;
v1.y += v2.y;
}
var endTime : Int = Lib.getTimer();
FlashConnect.trace( "Manual Inline: " + (endTime - startTime) );

} else if ( TestKind == ManualVariableInline ) {
// ***************************************
// Manual inline of vector variables:
// ***************************************
var x1 : Float = 0;
var y1 : Float = 0;
var x2 : Float = 1;
var y2 : Float = 1;
var startTime : Int = Lib.getTimer();
for ( i in 0...TestIterations ) {
x1 += x2;
y1 += y2;
}
var endTime : Int = Lib.getTimer();
FlashConnect.trace( "Manual inline of variables: " + (endTime - startTime) );
}
}
}

The results:

Non Inline Method: 9743
Inline Method: 708
Manual Inline: 709
Manual Variables Inline: 963

Method inlining beats the non inline methods by a factor of 14! Unsurprizingly manual inlining performed exactly the same. This is very good news since it will allow Haxe users to abstract things like vectors operations without worrying about the performance cost.

What was very surprizing however, was that inlining the variables and not using the Vec2f class at all was considerably slower. I was expecting it to be faster since the VM stores the variables in local registers instead of having to access heap memory through the Vec2f instance.


No comments:

Post a Comment