# @stackline/grunt-benchmark > Grunt task for benchmarking. [![npm version](https://img.shields.io/npm/v/@stackline/grunt-benchmark.svg?style=flat-square)](https://www.npmjs.com/package/@stackline/grunt-benchmark) [![license](https://img.shields.io/npm/l/@stackline/grunt-benchmark.svg?style=flat-square)](https://github.com/alexandroit/stackline-grunt-benchmark) [![GitHub repository](https://img.shields.io/badge/GitHub-repository-181717?style=flat-square&logo=github)](https://github.com/alexandroit/stackline-grunt-benchmark) [![Docs](https://img.shields.io/badge/docs-alexandro.net-0f766e?style=flat-square)](https://alexandro.net/docs/vanilla/grunt-benchmark/) [![Reddit community](https://img.shields.io/badge/community-r%2FStackline-ff4500?style=flat-square&logo=reddit&logoColor=white)](https://www.reddit.com/r/Stackline/) **[Documentation](https://alexandro.net/docs/vanilla/grunt-benchmark/)** | **[npm](https://www.npmjs.com/package/@stackline/grunt-benchmark)** | **[Issues](https://github.com/alexandroit/stackline-grunt-benchmark/issues)** | **[Repository](https://github.com/alexandroit/stackline-grunt-benchmark)** **Current package version:** `1.0.2` --- ## Why this package? `@stackline/grunt-benchmark` is the Stackline-maintained distribution of `grunt-benchmark@1.0.0`. It is an independent continuation of [grunt-benchmark](https://github.com/shama/grunt-benchmark); original authors and licenses remain credited below. ## Compatibility | Item | Value | | :--- | :--- | | Package | `@stackline/grunt-benchmark@1.0.2` | | API target | `grunt-benchmark@1.0.0` | | Supported Node.js | `>= 0.10.0` | | License | `MIT` | | Main entry | `lib/grunt-benchmark.js` | | Runtime dependencies | `benchmark, cli-table` | ## Installation ```bash npm install @stackline/grunt-benchmark ``` Preserve existing imports and plugin resolution with an npm alias: ```bash npm install grunt-benchmark@npm:@stackline/grunt-benchmark ``` ## Usage and API reference ### grunt-benchmark Grunt task for benchmarking with [Benchmark.js]. ## Getting Started Install this grunt plugin next to your project's [Gruntfile][getting_started] with: `npm install @stackline/grunt-benchmark` Then add this line to your project's Gruntfile: ```javascript grunt.loadNpmTasks('@stackline/grunt-benchmark'); ``` ## Documentation ### Basic Usage Example Create a `benchmarks/` folder and create a benchmark script within that folder, ie `fibonacci.js`: ```javascript 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: ```javascript 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]. ```javascript 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. ```javascript 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]. ```javascript 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]. ```javascript 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: ```javascript // benchmarks/watch.js // Create a spawnable watch task. Doesn't actually spawn until called. var watchTask = require('@stackline/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. ```javascript 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: ```javascript 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](https://github.com/LearnBoost/cli-table). It will automatically pick up the `dest` property, so that must be set for this to work. ```javascript 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: ```bash 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][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. [grunt]: https://github.com/gruntjs/grunt [getting_started]: https://gruntjs.com/getting-started [Benchmark.js]: http://benchmarkjs.com/ [task options]: http://benchmarkjs.com/docs#options ## Credits and original authors - Original project: [grunt-benchmark](https://github.com/shama/grunt-benchmark). - Kyle Robinson Young. - Stackline maintenance: [Alexandro Paixao Marques](https://www.linkedin.com/in/aleinfo/) and [Stackline contributors](https://github.com/alexandroit). Original copyright, license notices and contributor acknowledgements remain part of this distribution. Stackline maintenance does not replace authorship of the original work. ## Community and Links - [Stackline website](https://alexandro.net/) - [GitHub projects](https://github.com/alexandroit) - [npm packages](https://www.npmjs.com/~alex360qc) - [Reddit community — r/Stackline](https://www.reddit.com/r/Stackline/) - [Maintainer LinkedIn](https://www.linkedin.com/in/aleinfo/) Use this repository's issue tracker for reproducible bugs and feature requests. Join r/Stackline for examples, usage questions and release discussions. Documentation-only release: runtime file bytes and dependencies are unchanged from 1.0.0. Release: https://github.com/alexandroit/stackline-grunt-benchmark/releases/tag/docs-stackline-grunt-benchmark-v1.0.2