🐗⌚️ Grunt task for benchmarking
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
benchmarks
lib
tasks
test/lib
.editorconfig
.gitignore
.jshintrc
Gruntfile.js
LICENSE-MIT
README.md
package.json

README.md

grunt-benchmark

Grunt task for benchmarking with Benchmark.js.

Getting Started

Install this grunt plugin next to your project's Gruntfile with: npm install grunt-benchmark

Then add this line to your project's Gruntfile:

grunt.loadNpmTasks('grunt-benchmark');

Documentation

Basic Usage Example

Create a benchmarks/ folder and create a benchmark script within that folder, ie fibonacci.js:

var fibonacci = function(n) {
  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};

module.exports = function() {
  fibonacci(10);
};

Then setup your Gruntfile config to run the benchmarks within the benchmarks/ folder:

grunt.initConfig({
  benchmark: {
    all: {
      src: ['benchmarks/*.js'],
      dest: 'benchmarks/results.csv'
    }
  }
});

Then run the task:

$ grunt benchmark
Running "benchmark:all" (benchmark) task
Benchmarking "0" [benchmarks/test-timeout.js] x10...
>> test-timeout x 418,070 ops/sec ±12.73% (46 runs sampled)

Benchmark name, date, times and per iteration will be logged in a csv format.

Test Options

You can add test options to pass to Benchmark.js by exporting an object of [test options].

module.exports = {
  name: 'Timeout (asynchronous)',
  maxTime: 2,
  defer: true,
  onComplete: function() {
    console.log('Hooray!');
  },
  fn: function(deferred) {
    setTimeout(function() {
      deferred.resolve();
    }, 500);
  }
};

Result:

$ grunt benchmark
Running "benchmark:singleTest" (benchmark) task
Benchmarking "Timeout (asynchronous)" [benchmarks/singleTest.js]...
Hooray!
>> Timeout (asynchronous) x 2.00 ops/sec ±0.14% (8 runs sampled)

Test Suite

You can pit implementations against one another by creating a test suite.

var fibonacci = function(n) {
  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};

var fibonacci_memoized = (function (  ) {
  var memo = [0, 1];
  var fib = function (n) {
    var result = memo[n];
    if (typeof result !== 'number') {
      result = fib(n - 1) + fib(n - 2);
      memo[n] = result;
    }
    return result;
  };
  return fib;
}());

// A test suite
module.exports = {
  name: 'Fibonacci Showdown',
  tests: {
    'Fibonacci': function() {
      fibonacci(10);
      fibonacci(5);
    },
    'Fibonacci2': function() {
      fibonacci_memoized(10);
      fibonacci_memoized(5);
    }
  }
};

Result:

$ grunt benchmark
Running "benchmark:fibonacci" (benchmark) task
Benchmarking suite "Fibonacci" [benchmarks/fibonacci.js]...
>> fibonacci x 13,386,628 ops/sec ±8.63% (74 runs sampled)
>> fibonacci_memoized x 30,509,658 ops/sec ±2.10% (89 runs sampled)
Fastest is fibonacci_memoized

exports.tests as an Object:

Set exports.tests to an Object that maps test names to functions and or [Benchmark.js test options].

module.exports = {
  name: 'Timeout Showdown',
  tests: {
    'Return immediately (synchronous)': function() {
      return;
    },
    'Timeout: 50ms (asynchronous)': {
      defer: true,
      fn: function(deferred) {
        setTimeout(deferred.resolve, 50);
      }
    },
    'Timeout: 100ms (asynchronous)': {
      defer: true,
      fn: function(done) {
        setTimeout(deferred.resolve, 100);
      }
    }
  }
};

exports.tests as an Array:

Set exports.tests to an Array of functions and or [Benchmark.js test options].

module.exports = {
  name: 'Timeout Showdown',
  tests: [
    {
      name: 'Return immediately (synchronous)',
      fn: function() {
        return;
      }
    },
    {
      name: 'Timeout: 50ms (asynchronous)',
      defer: true,
      fn: function(done) {
        setTimeout(done, 50);
      }
    },
    {
      name: 'Timeout: 100ms (asynchronous)',
      defer: true,
      fn: function(done) {
        setTimeout(done, 100);
      }
    }
  ]
};

Benchmarking Tasks

Included is a helper, spawnTask, for running Grunt tasks within your benchmarks. This example will create a function to run the watch task:

// benchmarks/watch.js
// Create a spawnable watch task. Doesn't actually spawn until called.
var watchTask = require('grunt-benchmark').spawnTask('watch', {

  // Text trigger to look for to know when to run the next step or exit
  trigger: 'Waiting...',

  // Base folder and Gruntfile
  // You'll want to setup a fixture base folder and Gruntfile.js
  // to ensure your Grunt'ing appropriately
  base: 'path/to/a/gruntfile-base',
  gruntfile: 'path/to/a/Gruntfile.js'

  // Additional Grunt options can be specified here
});

// Our actual benchmark
module.exports = function(done) {

  // start the watch task
  watchTask([function() {

    // After trigger found, run this sync function
    // this will trigger the watch task
    grunt.file.write('path/to/file.js', 'var test = false;');

  }, function() {

    // After the previous funciton has ran and another trigger hit...
    // run this next sync function
    grunt.file.delete('path/to/file.js');

  }], function(result) {

    // All done, do something more with the output result or finish up the benchmark
    done();

  });

};

Saving output

Test results will be saved to a file if a destination file is provided.

grunt.initConfig({
  benchmark: {
    singleTest: {
      src: ['benchmarks/fibonacci.js'],
      dest: 'results/fibonacci.csv'
    }
  }
});

Results can be saved as 'csv' or 'json'. The format is determined from the dest file extension or by setting the format option:

grunt.initConfig({
  benchmark: {
    singleTest: {
      src: ['benchmarks/fibonacci.js'],
      dest: 'results/fibonacci.txt',
      options : {
        format: 'csv'
      }
    }
  }
});

You can specify a truthy displayResults option inside your Grunt config to display the results using cli-table.

It will automatically pick up the dest property, so that must be set for this to work.

grunt.initConfig({
  benchmark: {
    options: {
      // This can also be set inside specific tests.
      displayResults: true
    },

    singleTest: {
      src: ['benchmarks/fibonacci.js'],
      dest: 'results/fibonacci.csv'
    }
  }
});

The output will look something like:

Running "benchmark:fibonacci" (benchmark) task

Running suite Fibonacci [benchmarks/fibonacci.js]...
>> fibonacci x 13,386,628 ops/sec ±8.63% (74 runs sampled)
>> fibonacci_memoized x 30,509,658 ops/sec ±2.10% (89 runs sampled)

Results:
┌──────────────────────┬───────────────────────────────────────────┬───────┬─────────┬────────┬────────────────────┐
│ name                 │ date                                      │ error │ count   │ cycles │ hz                 │
├──────────────────────┼───────────────────────────────────────────┼───────┼─────────┼────────┼────────────────────┤
│ "fibonacci""Tue Apr 23 2013 21:25:49 GMT-0700 (PDT)" │       │ 906237  │ 4      │ 15154635.038364386 │
├──────────────────────┼───────────────────────────────────────────┼───────┼─────────┼────────┼────────────────────┤
│ "fibonacci_memoized""Fri May 24 2013 19:52:02 GMT-0400 (EDT)" │       │ 1804104 │ 4      │ 31131880.83560733  │
├──────────────────────┼───────────────────────────────────────────┼───────┼─────────┼────────┼────────────────────┤
│ "fibonacci""Tue Apr 23 2013 22:10:55 GMT-0700 (PDT)" │       │ 910791  │ 4      │ 13386627.749339204 │
├──────────────────────┼───────────────────────────────────────────┼───────┼─────────┼────────┼────────────────────┤
│ "fibonacci_memoized""Fri May 24 2013 19:52:11 GMT-0400 (EDT)" │       │ 1764921 │ 4      │ 30509657.596336514 │
└──────────────────────┴───────────────────────────────────────────┴───────┴─────────┴────────┴────────────────────┘

Contributing

In lieu of a formal styleguide, take care to maintain the existing coding style. Lint and test your code using grunt.

Release History

  • 1.0.0 Support multiple suites in one file (@zoltan-mihalyi). Update deps.
  • 0.3.0 Add json output format (@creynders).
  • 0.2.0 Switched to benchmark.js. Huge thanks to @lazd!
  • 0.1.3 Ability to log dest to a csv file. Support Grunt@0.4.0rc7.
  • 0.1.2 Update to work with Grunt@0.4.0rc3.
  • 0.1.1 Fix require path
  • 0.1.0 Initial release

License

Copyright (c) 2016 Kyle Robinson Young
Licensed under the MIT license.