> and suprinsingly I obtain
>
> mode: empty
> testDivide: 8936
> --------------
> mode: standard
> testDivide: 8974
> --------------
> mode: optimized
> testDivide: 9363
> --------------
>

humm going a little further in the tests,
there is one absolute gotcha to know: never use trace while iterating the tests

iterating x times to execute a function is not a real statistic,
you need to run that time sample multiple time if you want to obtain
consistent results

with
        standard function testDivide( num:Number ):void
            {
            var local:Number = num / 2;
            }

        optimized1 function testDivide( num:Number ):void
            {
            var local:Number = num * 0.5;
            }

        optimized2 function testDivide( num:Number ):void
            {
            var local:Number = num >> 1;
            }

        optimized3 function testDivide( num:Number ):void
            {
            var local:Number = num >>> 1;
            }

I can obtain that
var t:Benchmarks = new Benchmarks( 10000000, true ); //10.000.000
    t.runStatistics( 5, "testDivide" );
-------------------------------
  standard testDivide - min:  875, average: 1199.8, max: 1474
optimized1 testDivide - min: 1392, average: 1519  , max: 1698
optimized2 testDivide - min:  768, average:  802.8, max:  839
optimized3 testDivide - min: 2495, average: 2562.6, max: 2671
-------------------------------

var t:Benchmarks = new Benchmarks( 1000000, true ); //1.000.000
    t.runStatistics( 5, "testDivide" );
-------------------------------
  standard testDivide - min:   63, average:   92.2, max:  113
optimized1 testDivide - min:  105, average:  125.4, max:  141
optimized2 testDivide - min:   54, average:   61  , max:   71
optimized3 testDivide - min:  216, average:  241.2, max:  270
-------------------------------

var t:Benchmarks = new Benchmarks( 100000, true ); //100.000
    t.runStatistics( 5, "testDivide" );
-------------------------------
  standard testDivide - min:    7, average:   13.6, max:   24
optimized1 testDivide - min:    9, average:   13.6, max:   18
optimized2 testDivide - min:    5, average:    8.8, max:   12
optimized3 testDivide - min:   21, average:   28  , max:   40
-------------------------------

note:
 - a little too few iteration and you could obtain negatives number
which flaw the test
 - I used 5 samples, but you could go for 10, 15 and more (till flash
break ;)) the results stay consistent

what we learn with those stats

(value *.5) is slower than (value/2)
(value>>>1) is slower than (value>>1)

the standard way of doing a division is not that bad,
the bitshift win overwall


I just forgot my log/pwd for OSFlash wiki, but here the code used

--------------------------

package test
    {
    import flash.utils.getTimer;

    public class Benchmarks
        {
        public namespace empty      = "empty";
        public namespace standard   = "standard";
        public namespace optimized1 = "optimized1";
        public namespace optimized2 = "optimized2";
        public namespace optimized3 = "optimized3";

        public var mode:Namespace = empty;

        private var _maxOptimizedTest:int = 3;

        private var _iteration:int
        private var _emptyTestTime:Object;
        private var _substractEmptyTest:Boolean;
        private var _showEmptyTest:Boolean;

        private var _separator:String;
        private var _logs:String;
        private var _statistics:Object;
        private var _keepStats:Boolean;

        public function Benchmarks( iteration:int = 10000000,
                                    substractEmptyTest:Boolean = false,
                                    showEmptyTest:Boolean = false )
            {
            _keepStats     = false;
            _logs          = "";
            _statistics    = {};
            _resetStats();
            _emptyTestTime = {};
            _separator     = "-------------------------------";

            _iteration = iteration;
            _substractEmptyTest = substractEmptyTest;
            _showEmptyTest = showEmptyTest;
            }

        private function _resetStats():void
            {
            _statistics.standard = {};
            for( var i:int = 1; i<_maxOptimizedTest+1; i++ )
                {
                _statistics["optimized"+i] = {};
                }
            }

        private function _addMethodToStats( method:String ):void
            {
            if( _statistics.standard[ method ] != undefined )
                {
                //trace( "method " + method + " already in statistics" );
                return;
                }

            _statistics.standard[ method ] = [];

            for( var i:int = 1; i<_maxOptimizedTest+1; i++ )
                {
                _statistics["optimized"+i][ method ] = [];
                }

            }

        private function _showStats():void
            {
            //standard testDivide - min: 0, average:5, max:10

            var samples:Array;
            var min:Number;
            var average:Number;
            var max:Number;

            var accumulate:Function = function( data:Array ):Number
                {
                var sum:Number = 0;
                for( var i:int = 0; i<data.length; i++ )
                    {
                    sum += data[i];
                    }
                return sum;
                }

            for( var ns:String in _statistics )
                {
                for( var method:String in _statistics[ns] )
                    {
                    samples = _statistics[ns][method];
                    samples.sort( Array.NUMERIC );
                    min = samples[0];
                    max = samples[ samples.length-1 ];
                    average = accumulate( samples ) / samples.length;
                    log( ns +" "+method +" - min: "+min+", average:
"+average+", max: "+max );
                    }
                }

            }

        private function _runAll( method:String = "" ):void
            {
            mode = standard;
            run( method );

            mode = optimized1;
            run( method );

            mode = optimized2;
            run( method );

            mode = optimized3;
            run( method );
            }


        public function log( message:String ):void
            {
            _logs += message + "\n";
            }

        public function runAll( ...methods ):void
            {
            for( var i:int=0; i<methods.length; i++ )
                {
                if( _keepStats )
                    {
                    _addMethodToStats( methods[i] );
                    }
                _runAll( methods[i] );
                log( _separator );
                }

            if( !_keepStats )
                {
                trace( _logs );
                }
            }

        public function runStatistics( samples:int, ...methods ):void
            {
            _keepStats = true;
            for( var i:int=0; i<samples; i++ )
                {
                runAll.apply( this, methods );
                }

            _logs = "";
            log( _separator );
            _showStats();
            log( _separator );
            trace( _logs );
            }

        public function run( method:String = "", showLog:Boolean = false ):void
            {
            if( method == "" )
                {
                log( "test method is empty" );
                return;
                }

            try
                {
                var exists:* = mode::[method];
                }
            catch( e:Error )
                {
                if( e.errorID == 1065 )
                    {
                    //log( "test method \""+method+"\" does not exists
in ["+mode+"]" );
                    return;
                    }
                }

            if( (mode != empty) && !_emptyTestTime[method] )
                {
                var original:Namespace = mode;
                mode = empty;
                run( method );
                mode = original;
                }

            var i:Number;
            var max:Number = _iteration;
            var t1:int  = getTimer();

            for( i=0; i<max; i++ )
                {
                mode::[method]( i );
                }

            var t2:int = getTimer();

            if( mode == empty )
                {
                _emptyTestTime[method] = (t2-t1);
                }

            var result:int;
            if( _substractEmptyTest && (_emptyTestTime[method] != 0) )
                {
                result = ((t2-t1)-_emptyTestTime[method]);
                }
            else
                {
                result = (t2-t1);
                }

            if( !_showEmptyTest && (mode == empty) )
                {
                return;
                }

            if( _keepStats && (mode != empty) )
                {
                _statistics[ mode.toString() ][ method ].push( result );
                }

            log( mode + " " + method+": " + result );
            log( _separator );

            if( showLog )
                {
                trace( _logs );
                }
            }

        empty function testDivide( num:Number ):void
            {

            }

        standard function testDivide( num:Number ):void
            {
            var local:Number = num / 2;
            }

        optimized1 function testDivide( num:Number ):void
            {
            var local:Number = num * 0.5;
            }

        optimized2 function testDivide( num:Number ):void
            {
            var local:Number = num >> 1;
            }

        optimized3 function testDivide( num:Number ):void
            {
            var local:Number = num >>> 1;
            }

        }

    }


--------------------------

zwetan

_______________________________________________
osflash mailing list
[email protected]
http://osflash.org/mailman/listinfo/osflash_osflash.org

Reply via email to