Webworker delegation

JavaScript performance comparison

Revision 3 of this test case created by Jasper

Preparation code

<script>
function stringify(obj) {
        var props;

        if ( Array.isArray(obj) ){
            props = [];
            for ( var i = 0, l = obj.length; i < l; ++i ){
                props.push( stringify(obj[ i ]) );
            }
            return '[' + props.join(',') + ']';
        } else if ( typeof obj !== 'object' ){
            return obj.toString();
        } else {
            props = [];
            for (var key in obj) {
                props.push(key + ':' + stringify(obj[key]));
            }
            return '{' + props.join(',') + '}';
        }
    }

    function Batch(obj) {

        this.init(obj);
    }

    Batch.prototype = {
        init: function (obj) {

            this.init = false;
            // start false, so that check callbacks only executes callbacks if at least one map is called/completed
            this.jobs = false;
            this.callbacks = [];
            this.results = [];

            function setup(obj) {

                self.onmessage = function (e) {

                    self.postMessage( obj.process( e.data.args ) );
                    self.close();
                };
            }

            var blob = new Blob(['!' + setup.toString() + '(' + stringify(obj) + ')']);
            this.blobUrl = window.URL.createObjectURL(blob);
        },

        run: function (args, buffers) {
            var self = this;
            var worker = new Worker(this.blobUrl);
            self.jobs++;
            worker.onmessage = function (e) {
                self.results.push(e.data);
                self.jobs--;
                self.checkFinish();
            };

            worker.postMessage({
                args: args
            }, buffers);
            return this;
        },

        finish: function (fn) {
            if (!fn) {
                return this;
            }
            this.callbacks.push(fn);
            this.checkFinish();
            return this;
        },

        checkFinish: function () {
            if (this.jobs !== 0) {
                return this;
            }

            var fn;

            while (fn = this.callbacks.shift()) {
                fn.call(this, this.results);
            }
            return this;
        },

        delegate: function( data, chunks, transfer ){

            var chunksize = (data.length / chunks)|0;

            if ( transfer ){

                var offset = 0;
                var sub;
                var arr;
                while ( offset < data.length ){
                    sub = data.subarray(offset, offset + chunksize);
                    arr = new (data.constructor)( sub );
                    this.run( arr, [arr.buffer] );
                    offset += chunksize;
                }

            } else {

                while ( data.length ){
                    
                    this.run( data.splice(0, chunksize) );
                }
            }
        }

    };

function myHelper( x ){
    return x * x;
}

function fib(n) {
      return n < 2 ? 1 : fib(n - 1) + fib(n - 2);
    };

var schema = {
    
    foo: 2,
    bar: [ 1, 2, 3 ],
    baz: {
        n: 10
    },
    
    fib: fib,
    
    process: function( chunk ){
        
        var results = new Float64Array( chunk.length );
        
        for ( var i = 0, l = chunk.length; i < l; ++i ){
            
            results[i] = this.fib( chunk[i] );
        }
        
        return results;
    }
};

</script>
      
<script>
Benchmark.prototype.setup = function() {
  var l = 1000;
  var bigData = new Float64Array(l);
  while( l-- ){
      bigData[l] = Math.floor(Math.random() * 10 + 10);
  }
  
  function reduce( results ){
      var ans = 0;
      
      for ( var i = 0, l = results.length; i < l; ++i ){
          for ( var j = 0, ll = results[ i ].length; j < ll; ++j ){
              
              ans += results[ i ][ j ];
          }
      }
  }
  
  var alg = new Batch( schema );

};
</script>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
Inline (chunks: 4)
var data = bigData;
var results = [];
var chunks = 4;
var chunksize = (data.length / chunks)|0;
        
        var offset = 0;
                var sub;
                var arr;
                while ( offset < data.length ){
                    sub = data.subarray(offset, offset + chunksize);
                    arr = new (data.constructor)( sub );
                    results.push(schema.process( arr ));
                    offset += chunksize;
                }
pending…
Async (chunks: 4)
// async test
alg.delegate( bigData, 4, true );
alg.finish( function(){
    deferred.resolve();
});
pending…
Async (chunks: 8)
// async test
alg.delegate( bigData, 8, true );
alg.finish( function(){
    deferred.resolve();
});
pending…
Async (chunks: 16)
// async test
alg.delegate( bigData, 16, true );
alg.finish( function(){
    deferred.resolve();
});
pending…
Async (chunks: 1)
// async test
alg.delegate( bigData, 1, true );
alg.finish( function(){
    deferred.resolve();
});
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

0 Comments