PixInsight 1.8.0 Ripley: More JavaScript Benchmarks

Juan Conejero

PixInsight Staff
Staff member
In a recent post, we have seen a performance comparison between the JavaScript engines in the latest (final) version of PixInsight 1.8.0 Ripley and previous versions. We have compared the performance of the new SpiderMonkey 24.1 engine with respect to SM 17, which is the engine embedded in PixInsight Core builds older than 1065. In that comparison, we have seen that the performance gains that can be expected for scripts that make extensive use of PJSR core objects is about a 12-15%.

This time we are going to do a similar comparison, but with pure JavaScript code. This is the benchmark script:

Code:
/*
 * PixInsight Pure JavaScript Benchmark
 */

#define MATRIX_SIZE           50
#define NUMBER_OF_ITERATIONS  5000
#define NUMBER_OF_TESTS       200

function JMatrix( rows, cols )
{
   this.rows = rows;
   this.cols = cols;

   this.data = [];
   for ( var i = 0; i < rows; ++i )
      this.data.push( new Array( cols ) );

   this.setRandom = function()
   {
      for ( var i = 0; i < this.rows; ++i )
      {
         var r = this.data[i];
         for ( var j = 0; j < this.cols; ++j )
            r[j] = Math.random() * 10;
      }
   };

   this.forEach = function( f )
   {
      for ( var i = 0; i < this.rows; ++i )
      {
         var r = this.data[i];
         for ( var j = 0; j < this.cols; ++j )
            f( r[j] );
      }
   };

   this.mutableForEach = function( f )
   {
      for ( var i = 0; i < this.rows; ++i )
      {
         var r = this.data[i];
         for ( var j = 0; j < this.cols; ++j )
            r[j] = f( r[j] );
      }
   };

   this.benchmark = function( iterations, f )
   {
      var start = Date.now();
      for ( var i = 0; i < iterations; ++i )
         this.forEach( f );
      return Date.now() - start;
   };

   this.mutableBenchmark = function( iterations, f )
   {
      var start = Date.now();
      for ( var i = 0; i < iterations; ++i )
         this.mutableForEach( f );
      return Date.now() - start;
   };
}

var max = -Infinity;
function maxElement( x )
{
   if ( max < x )
      max = x;
}

function squareOrHalf( x )
{
   return (x < 10000) ? x*x : x/2;
}

console.show();
console.writeln( "<end><cbr>Performing benchmarks. Please wait..." );
console.flush();

var A = new JMatrix( MATRIX_SIZE, MATRIX_SIZE );
var immutableTimes = [];
var mutableTimes = [];
for ( var i = 0; i < NUMBER_OF_TESTS; ++i )
{
   A.setRandom();
   immutableTimes.push( A.benchmark( NUMBER_OF_ITERATIONS, maxElement ) );
   mutableTimes.push( A.mutableBenchmark( NUMBER_OF_ITERATIONS, squareOrHalf ) );
}

function WinsorizedMean( a, k )
{
   a.sort( function( a, b ) { return (a < b) ? -1 : ((b < a) ? +1 : 0); } );
   var n = Math.trunc( Math.min( k, 0.5 ) * a.length );
   for ( var i = 0; i < n; ++i )
   {
      a[i] = a[n];
      a[a.length-i-1] = a[a.length-n-1];
   }
   return Math.mean( a );
}

console.writeln( format( "forEach()        : %4.0f ms", WinsorizedMean( immutableTimes, 0.2 ) ) );
console.writeln( format( "mutableForEach() : %4.0f ms", WinsorizedMean( mutableTimes, 0.2 ) ) );
A = null;

Note that with the only exception of some calls to Math methods, console.writeln() and format()---which have no repercussion on measured execution times---, this script executes 100% pure JavaScript code. In fact, if you remove the console.writeln(), format() and Math.mean() calls, as well as the preprocessor directives (which are exclusive to PixInsight's JavaScript runtime), the above code could be executed on any web browser without further modification.

The results speak by themselves:

Code:
PixInsight Core 01.08.00.1065 Ripley (x64) - SpiderMonkey 24.1
forEach()        :   33 ms
mutableForEach() :   61 ms

Code:
PixInsight Core 01.08.00.1054 Ripley (x64) - SpiderMonkey 17.0
forEach()        :   99 ms
mutableForEach() :  174 ms

So the new JavaScript engine is about three times faster than the old one in this benchmark.

What makes such a large difference in performance? It is the just-in-time compiler, of course. The IonMonkey JIT implemented in SM 24 is a big step forward with respect to the JaegerMonkey JIT in SM 17. In the above script, the inner loop calls in the JMatrix.forEach() and JMatrix.mutableForEach() methods are being inlined and translated to machine code much more efficiently by the new JIT. This is a big step forward for Mozilla's JavaScript engine, and the same for PixInsight, too.
 
Amazing Juan!  You're like the "man behind the curtain", but in this case for real.
You've built a hell of an engine, and it just keeps getting better.
Thanks,

Mark
 
Back
Top