├── .blah ├── README.ejs └── licenses │ └── license.ejs ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── benchtable.js ├── examples ├── string_search.js └── string_search_transposed.js ├── package.json └── screenshot.png /.blah/README.ejs: -------------------------------------------------------------------------------- 1 | <% 2 | var projectRoot = _.path 3 | , projectName = _.pack.name 4 | , fs = require('fs') 5 | , path = require('path') 6 | ; 7 | 8 | function getExample (file) { 9 | return fs.readFileSync( 10 | path.join( 11 | projectRoot 12 | , 'examples' 13 | , file 14 | ) 15 | , 'utf-8' 16 | ) 17 | .replace(/\.\.\//g, projectName) 18 | .trimRight() 19 | } 20 | %> 21 | 22 | 23 | # Benchtable 24 | 25 | Benchtable is a NodeJS module which provides an easy way to run performance tests for a set of JavaScript functions on a set of inputs, and display the evaluation results as an ASCII table. 26 | 27 | This is useful for situations when you are: 28 | 29 | * evaluating the performance of a single function for a range of inputs (e.g. of different size) 30 | * comparing the performance of a set of functions for a specific input (e.g. different implementations of same functionality) 31 | * comparing the performance of a set of functions for the same set of inputs 32 | 33 | Benchtable is not a new JavaScript benchmarking framework -- it extends the already excellent [benchmark.js](https://github.com/bestiejs/benchmark.js) framework. 34 | Benchmarks are executed using benchmark.js and displayed using [cli-table](https://github.com/LearnBoost/cli-table). 35 | 36 | ![Screenshot](/screenshot.png) 37 | 38 | ## Features 39 | 40 | * a Benchtable suite is an extension (subclass) of the [Benchmark.js Suite API](http://benchmarkjs.com/docs#Suite) 41 | * a simple API for defining benchmarks functions and inputs 42 | * display of benchmarking results as an ASCII table, with ops/sec measure used for table data 43 | * simple visual identification of functions with best and worst performance for each input using color highlighting (red = worst, green = best) 44 | 45 | ## Installation 46 | 47 | ```sh 48 | npm i --save <%- _.pack.name %> 49 | ``` 50 | 51 | ## API and usage 52 | `BenchTable` is a class extended from the benchmark.js's [`Benchmark.Suite`](http://benchmarkjs.com/docs#Suite) class - all 53 | functions exposed by `Benchmark.Suite` are also provided by Benchtable and therefore a Benchtable object may be used like 54 | an ordinary `Benchmark.Suite`. 55 | 56 | The `Benchmark.Suite.prototype.add` method can be used to add functions to be benchmarked, and while such functions will 57 | indeed be benchmarked with Benchtable–their results will not be shown in the results ASCII table. 58 | 59 | Please use the `BenchTable`'s `addFunction` and `addInput` methods for specifying BenchTable benchmarks, as shown below. 60 | 61 | <% docs = docs.split("\n").slice(3).join("\n"); %> 62 | <%- docs %> 63 | 64 | ### Events 65 | 66 | #### `complete` 67 | Get results table. 68 | 69 | After all benchmarks are finished, the `complete` event is fired and the `cli-table` table instance with the results is 70 | available through the `BenchTable.prototype.table` property. 71 | 72 | The ASCII string serialization of the table is obtained by calling `.toString()` on that object. 73 | 74 | ```js 75 | var suite = new BenchTable(); 76 | ... 77 | suite.on('complete', () => { 78 | suite.table.toString(); 79 | }); 80 | ``` 81 | 82 | ## Examples 83 | 84 | This is the Benchtable version of the example from the [Benchmark.js homepage](http://benchmarkjs.com). 85 | Also available in the [examples directory](/examples/string_search.js). 86 | 87 | ### Default behavior 88 | 89 | ```js 90 | <%- getExample("string_search.js") %> 91 | ``` 92 | 93 | ## Transposed table 94 | 95 | If the Benchtable object is initialized with the `{isTransposed : true}` option (see [this example](/examples/string_search_transposed.js)), the script produces the same output but with rows and columns transposed: 96 | 97 | ```js 98 | ... 99 | var suite = new BenchTable('test', {isTransposed : true}); 100 | ... 101 | // => 102 | // RegExp#test for inputs Short string x 11,139,499 ops/sec ±0.56% (97 runs sampled) 103 | // RegExp#test for inputs Long string x 10,370,952 ops/sec ±0.66% (97 runs sampled) 104 | // RegExp#test for inputs Very long string x 7,386,009 ops/sec ±0.60% (98 runs sampled) 105 | // RegExp#test for inputs Extremely long string x 297,936 ops/sec ±0.40% (99 runs sampled) 106 | // String#indexOf for inputs Short string x 12,844,042 ops/sec ±0.44% (96 runs sampled) 107 | // String#indexOf for inputs Long string x 12,474,178 ops/sec ±0.48% (98 runs sampled) 108 | // String#indexOf for inputs Very long string x 8,471,914 ops/sec ±0.36% (94 runs sampled) 109 | // String#indexOf for inputs Extremely long string x 301,176 ops/sec ±0.43% (93 runs sampled) 110 | // Fastest is String#indexOf for inputs Short string 111 | // +-----------------------+--------------------+--------------------+ 112 | // | │ RegExp#test │ String#indexOf | 113 | // +-----------------------+--------------------+--------------------+ 114 | // | Short string │ 11,139,499 ops/sec │ 12,844,042 ops/sec | 115 | // +-----------------------+--------------------+--------------------+ 116 | // | Long string │ 10,370,952 ops/sec │ 12,474,178 ops/sec | 117 | // +-----------------------+--------------------+--------------------+ 118 | // | Very long string │ 7,386,009 ops/sec │ 8,471,914 ops/sec | 119 | // +-----------------------+--------------------+--------------------+ 120 | // | Extremely long string │ 297,936 ops/sec │ 301,176 ops/sec | 121 | // +-----------------------+--------------------+--------------------+ 122 | ``` 123 | 124 | ## Contributing 125 | 126 | Want to contribute to this project? See information [here](CONTRIBUTING.md). 127 | 128 | ## Credits 129 | Benchtable is developed by [Ivan Zuzak](http://ivanzuzak.info) \. 130 | 131 | Benchtable is built with or uses many open-source projects: 132 | 133 | * [`cli-table`](https://github.com/LearnBoost/cli-table) - used for drawing ASCII tables 134 | * [`benchmark.js`](https://github.com/bestiejs/benchmark.js) - used for running benchmarks 135 | * [`color-it`](https://github.com/IonicaBizau/node-color-it/) - used for coloring of worst and best results in tables 136 | 137 | ## License 138 | 139 | Licensed under the [Apache 2.0 License](/LICENSE.md). 140 | -------------------------------------------------------------------------------- /.blah/licenses/license.ejs: -------------------------------------------------------------------------------- 1 | Copyright <%- _.license_year %> <%- _.pack.author %> 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | *.swp 10 | 11 | pids 12 | logs 13 | results 14 | 15 | node_modules 16 | npm-debug.log 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing: 2 | 3 | * Fork and clone repo: `https://github.com/izuzak/benchtable` 4 | * Change dir to benchtable: `cd benchtable` 5 | * Install dependencies: `npm install` 6 | * Make changes to benchtable source (`./benchtable.js`), or examples (`./examples`) 7 | * Commit, push and [make pull request](https://github.com/izuzak/benchtable/pull/new/master). I will also accept patches sent by [e-mail](mailto:izuzak@gmail.com). 8 | * [E-mail](mailto:izuzak@gmail.com) me if you have questions. 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-16 Ivan Zuzak (http://ivanzuzak.info) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Benchtable 2 | 3 | Benchtable is a NodeJS module which provides an easy way to run performance tests for a set of JavaScript functions on a set of inputs, and display the evaluation results as an ASCII table. 4 | 5 | This is useful for situations when you are: 6 | 7 | * evaluating the performance of a single function for a range of inputs (e.g. of different size) 8 | * comparing the performance of a set of functions for a specific input (e.g. different implementations of same functionality) 9 | * comparing the performance of a set of functions for the same set of inputs 10 | 11 | Benchtable is not a new JavaScript benchmarking framework -- it extends the already excellent [benchmark.js](https://github.com/bestiejs/benchmark.js) framework. 12 | Benchmarks are executed using benchmark.js and displayed using [cli-table](https://github.com/LearnBoost/cli-table). 13 | 14 | ![Screenshot](/screenshot.png) 15 | 16 | ## Features 17 | 18 | * a Benchtable suite is an extension (subclass) of the [Benchmark.js Suite API](http://benchmarkjs.com/docs#Suite) 19 | * a simple API for defining benchmarks functions and inputs 20 | * display of benchmarking results as an ASCII table, with ops/sec measure used for table data 21 | * simple visual identification of functions with best and worst performance for each input using color highlighting (red = worst, green = best) 22 | 23 | ## Installation 24 | 25 | ```sh 26 | npm i --save benchtable 27 | ``` 28 | 29 | ## API and usage 30 | `BenchTable` is a class extended from the benchmark.js's [`Benchmark.Suite`](http://benchmarkjs.com/docs#Suite) class - all 31 | functions exposed by `Benchmark.Suite` are also provided by Benchtable and therefore a Benchtable object may be used like 32 | an ordinary `Benchmark.Suite`. 33 | 34 | The `Benchmark.Suite.prototype.add` method can be used to add functions to be benchmarked, and while such functions will 35 | indeed be benchmarked with Benchtable–their results will not be shown in the results ASCII table. 36 | 37 | Please use the `BenchTable`'s `addFunction` and `addInput` methods for specifying BenchTable benchmarks, as shown below. 38 | 39 | ### `BenchTable(name, options)` 40 | The `BenchTable` constructor. `BenchTable` is extended from [Benchmark.Suite](http://benchmarkjs.com/docs#Suite). 41 | 42 | #### Params 43 | - **String** `name`: A name to identify the suite. 44 | - **String** `options`: Options object. A special boolean option `isTransposed` is available for Benchtable–if set to `true`, the output ASCII table will be 45 | transposed: the benchmarked functions will be organized into columns, while 46 | inputs will be organized into rows. This is useful for situations where the 47 | number of inputs is large, and the number of functions is small. This option 48 | defaults to `false`. 49 | 50 | Use the 'cycle' event to store results and build a table 51 | after all BenchTable functions are evaluated for all inputs. 52 | 53 | ### `run(config)` 54 | Runs the suite. 55 | 56 | #### Params 57 | - **Object** `config`: The options object. [See `benchmark.js` API docs.](http://benchmarkjs.com/docs#Suite_prototype_run) 58 | 59 | ### `addFunction(name, fun, options)` 60 | Specify functions to be benchmarked. 61 | This function may be called multiple times to add multiple functions. 62 | 63 | #### Params 64 | - **String** `name`: A name to identify the function. 65 | - **Function** `fun`: The test to benchmark. 66 | - **Object** `options`: The options object. 67 | 68 | #### Return 69 | - **BenchTable** The `BenchTable` instance. 70 | 71 | ### `addInput(name, input)` 72 | Specify inputs for functions. 73 | This function may be called multiple times to add multiple inputs. 74 | 75 | #### Params 76 | - **String** `name`: A name to identify the input. 77 | - **Array** `input`: The array containing arguments that will be passed to each benchmarked function. Therefore, the number of 78 | elements in the `input` array should match the number of arguments of 79 | each specified function (i.e. the array will be "unpacked" when 80 | invoking functions, they will not receive a single array argument). 81 | 82 | #### Return 83 | - **BenchTable** The `BenchTable` instance. 84 | 85 | ### Events 86 | 87 | #### `complete` 88 | Get results table. 89 | 90 | After all benchmarks are finished, the `complete` event is fired and the `cli-table` table instance with the results is 91 | available through the `BenchTable.prototype.table` property. 92 | 93 | The ASCII string serialization of the table is obtained by calling `.toString()` on that object. 94 | 95 | ```js 96 | var suite = new BenchTable(); 97 | ... 98 | suite.on('complete', () => { 99 | suite.table.toString(); 100 | }); 101 | ``` 102 | 103 | ## Examples 104 | 105 | This is the Benchtable version of the example from the [Benchmark.js homepage](http://benchmarkjs.com). 106 | Also available in the [examples directory](/examples/string_search.js). 107 | 108 | ### Default behavior 109 | 110 | ```js 111 | // Import the benchtable module 112 | var BenchTable = require('benchtable'); 113 | 114 | // Create benchtable suite 115 | var suite = new BenchTable(); 116 | 117 | suite 118 | // Add functions for benchmarking 119 | .addFunction('RegExp#test', s => /o/.test(s)) 120 | .addFunction('String#indexOf', s => s.indexOf('o') > -1) 121 | // Add inputs 122 | .addInput('Short string', ['Hello world!']) 123 | .addInput('Long string', ['This is a very big string, isnt it? It is. Really. So, hello world!']) 124 | .addInput('Very long string', [`This is a ${new Array(100).join('very ')} + 'big string, isnt it? It is. ${new Array(100).join('Really. ')} So, hello world!`]) 125 | .addInput('Extremely long string', [`This is a ${new Array(10000).join('very ')} + 'big string, isnt it? It is. ${new Array(10000).join('Really. ')} So, hello world!`]) 126 | // Add listeners 127 | .on('cycle', event => { 128 | console.log(event.target.toString()); 129 | }) 130 | .on('complete', () => { 131 | console.log('Fastest is ' + suite.filter('fastest').map('name')); 132 | console.log(suite.table.toString()); 133 | }) 134 | // Run async 135 | .run({ async: false }) 136 | ; 137 | 138 | // => 139 | // RegExp#test for inputs Short string x 11,037,873 ops/sec ±0.57% (100 runs sampled) 140 | // RegExp#test for inputs Long string x 10,114,587 ops/sec ±0.42% (100 runs sampled) 141 | // RegExp#test for inputs Very long string x 7,534,743 ops/sec ±0.33% (101 runs sampled) 142 | // RegExp#test for inputs Extremely long string x 304,666 ops/sec ±0.25% (101 runs sampled) 143 | // String#indexOf for inputs Short string x 13,400,084 ops/sec ±0.28% (99 runs sampled) 144 | // String#indexOf for inputs Long string x 12,947,759 ops/sec ±0.33% (100 runs sampled) 145 | // String#indexOf for inputs Very long string x 8,489,440 ops/sec ±0.31% (101 runs sampled) 146 | // String#indexOf for inputs Extremely long string x 306,018 ops/sec ±0.26% (100 runs sampled) 147 | // Fastest is String#indexOf for inputs Short string 148 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 149 | // | │ Short string │ Long string │ Very long string │ Extremely long string | 150 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 151 | // | RegExp#test │ 11,037,873 ops/sec │ 10,114,587 ops/sec │ 7,534,743 ops/sec │ 304,666 ops/sec | 152 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 153 | // | String#indexOf │ 13,400,084 ops/sec │ 12,947,759 ops/sec │ 8,489,440 ops/sec │ 306,018 ops/sec | 154 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 155 | ``` 156 | 157 | ## Transposed table 158 | 159 | If the Benchtable object is initialized with the `{isTransposed : true}` option (see [this example](/examples/string_search_transposed.js)), the script produces the same output but with rows and columns transposed: 160 | 161 | ```js 162 | ... 163 | var suite = new BenchTable('test', {isTransposed : true}); 164 | ... 165 | // => 166 | // RegExp#test for inputs Short string x 11,139,499 ops/sec ±0.56% (97 runs sampled) 167 | // RegExp#test for inputs Long string x 10,370,952 ops/sec ±0.66% (97 runs sampled) 168 | // RegExp#test for inputs Very long string x 7,386,009 ops/sec ±0.60% (98 runs sampled) 169 | // RegExp#test for inputs Extremely long string x 297,936 ops/sec ±0.40% (99 runs sampled) 170 | // String#indexOf for inputs Short string x 12,844,042 ops/sec ±0.44% (96 runs sampled) 171 | // String#indexOf for inputs Long string x 12,474,178 ops/sec ±0.48% (98 runs sampled) 172 | // String#indexOf for inputs Very long string x 8,471,914 ops/sec ±0.36% (94 runs sampled) 173 | // String#indexOf for inputs Extremely long string x 301,176 ops/sec ±0.43% (93 runs sampled) 174 | // Fastest is String#indexOf for inputs Short string 175 | // +-----------------------+--------------------+--------------------+ 176 | // | │ RegExp#test │ String#indexOf | 177 | // +-----------------------+--------------------+--------------------+ 178 | // | Short string │ 11,139,499 ops/sec │ 12,844,042 ops/sec | 179 | // +-----------------------+--------------------+--------------------+ 180 | // | Long string │ 10,370,952 ops/sec │ 12,474,178 ops/sec | 181 | // +-----------------------+--------------------+--------------------+ 182 | // | Very long string │ 7,386,009 ops/sec │ 8,471,914 ops/sec | 183 | // +-----------------------+--------------------+--------------------+ 184 | // | Extremely long string │ 297,936 ops/sec │ 301,176 ops/sec | 185 | // +-----------------------+--------------------+--------------------+ 186 | ``` 187 | 188 | ## Contributing 189 | 190 | Want to contribute to this project? See information [here](CONTRIBUTING.md). 191 | 192 | ## Credits 193 | Benchtable is developed by [Ivan Zuzak](http://ivanzuzak.info) \. 194 | 195 | Benchtable is built with or uses many open-source projects: 196 | 197 | * [`cli-table`](https://github.com/LearnBoost/cli-table) - used for drawing ASCII tables 198 | * [`benchmark.js`](https://github.com/bestiejs/benchmark.js) - used for running benchmarks 199 | * [`color-it`](https://github.com/IonicaBizau/node-color-it/) - used for coloring of worst and best results in tables 200 | 201 | ## License 202 | 203 | Licensed under the [Apache 2.0 License](/LICENSE.md). -------------------------------------------------------------------------------- /benchtable.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // Module dependencies. 4 | const Benchmark = require('benchmark'); 5 | const Table = require('cli-table'); 6 | const colorIt = require('color-it'); 7 | 8 | module.exports = class BenchTable extends Benchmark.Suite { 9 | /** 10 | * BenchTable 11 | * The `BenchTable` constructor. `BenchTable` is extended from [Benchmark.Suite](http://benchmarkjs.com/docs#Suite). 12 | * 13 | * @name BenchTable 14 | * @function 15 | * @param {String} name A name to identify the suite. 16 | * @param {String} options Options object. A special boolean option `isTransposed` 17 | * is available for Benchtable–if set to `true`, the output ASCII table will be 18 | * transposed: the benchmarked functions will be organized into columns, while 19 | * inputs will be organized into rows. This is useful for situations where the 20 | * number of inputs is large, and the number of functions is small. This option 21 | * defaults to `false`. 22 | */ 23 | constructor(name, options) { 24 | 25 | super(name, options); 26 | 27 | this._functions = []; 28 | this._functionNames = []; 29 | this._functionOptions = []; 30 | this._inputs = []; 31 | this._inputNames = []; 32 | 33 | this._results = {}; 34 | 35 | // mappings from benchmark names to function and input indices 36 | // as { funcIdx, inputIdx } 37 | this._mappings = {}; 38 | 39 | // if transposed, then functions are in columns and inputs are in rows 40 | this._transposed = options && options.isTransposed; 41 | 42 | /** 43 | * Use the 'cycle' event to store results and build a table 44 | * after all BenchTable functions are evaluated for all inputs. 45 | **/ 46 | 47 | this.on('cycle', event => { 48 | var key = event.target.name; 49 | var worst_idx, best_idx, worst, best, curr; 50 | var i, j; 51 | var funName, inputName, item; 52 | 53 | if (!(key in this._mappings)) { 54 | return; 55 | } 56 | 57 | // store current result 58 | funName = this._functionNames[this._mappings[key].funcIdx]; 59 | this._results[funName].push(event.target); 60 | this._counter -= 1; 61 | 62 | if (this._counter !== 0) { 63 | return; 64 | } 65 | 66 | // compute best and worst results for each input 67 | for (i = 0; i < this._inputs.length; i++) { 68 | worst_idx = 0, best_idx = 0; 69 | best = this._results[this._functionNames[best_idx]][i]; 70 | worst = this._results[this._functionNames[worst_idx]][i]; 71 | 72 | for (j = 0; j < this._functions.length; j++) { 73 | curr = this._results[this._functionNames[j]][i]; 74 | 75 | if (curr.hz <= worst.hz) { 76 | worst_idx = j; 77 | worst = this._results[this._functionNames[worst_idx]][i]; 78 | } 79 | 80 | if (curr.hz >= best.hz) { 81 | best_idx = j; 82 | best = this._results[this._functionNames[best_idx]][i]; 83 | } 84 | } 85 | 86 | worst._isWorst = true; 87 | best._isBest = true; 88 | } 89 | 90 | function toTableStr(par) { 91 | if (par.error) { 92 | return 'ERROR'; 93 | } else { 94 | return Benchmark.formatNumber(par.hz.toFixed(par.hz < 100 ? 2 : 0)) + ' ops/sec'; 95 | } 96 | } 97 | 98 | // create cli-table based on results 99 | var headers = this._transposed ? [""].concat(this._functionNames) : [""].concat(this._inputNames); 100 | 101 | this.table = new Table({ 102 | head: headers, 103 | chars: { 104 | 'top': '-', 105 | 'top-mid': '+', 106 | 'top-left': '+', 107 | 'top-right': '+', 108 | 'bottom': '-', 109 | 'bottom-mid': '+', 110 | 'bottom-left': '+', 111 | 'bottom-right': '+', 112 | 'left': '|', 113 | 'left-mid': '+', 114 | 'mid': '-', 115 | 'mid-mid': '+', 116 | 'right': '|', 117 | 'right-mid': '+' 118 | }, 119 | truncate: '…' 120 | }); 121 | 122 | if (!this._transposed) { 123 | for (i = 0; i < this._functions.length; i++) { 124 | item = {}; 125 | funName = this._functionNames[i]; 126 | item[funName] = []; 127 | 128 | for (j = 0; j < this._results[funName].length; j++) { 129 | curr = this._results[funName][j]; 130 | item[funName].push(toTableStr(curr)); 131 | 132 | if (this._functions.length > 1) { 133 | if (curr._isWorst) { 134 | item[funName][j] = colorIt(item[funName][j]).red().toString(); 135 | } else if (curr._isBest) { 136 | item[funName][j] = colorIt(item[funName][j]).green().toString(); 137 | } 138 | } 139 | } 140 | 141 | this.table.push(item); 142 | } 143 | } else { 144 | for (i = 0; i < this._inputs.length; i++) { 145 | item = {}; 146 | inputName = this._inputNames[i]; 147 | item[inputName] = []; 148 | 149 | for (j = 0; j < this._functionNames.length; j++) { 150 | funName = this._functionNames[j]; 151 | curr = this._results[funName][i]; 152 | item[inputName].push(toTableStr(curr)); 153 | 154 | if (this._functions.length > 1) { 155 | if (curr._isWorst) { 156 | item[inputName][j] = colorIt(item[inputName][j]).red().toString(); 157 | } else if (curr._isBest) { 158 | item[inputName][j] = colorIt(item[inputName][j]).green().toString(); 159 | } 160 | } 161 | } 162 | 163 | this.table.push(item); 164 | } 165 | } 166 | }); 167 | } 168 | 169 | /** 170 | * run 171 | * Runs the suite. 172 | * 173 | * @name run 174 | * @function 175 | * @param {Object} config The options object. [See `benchmark.js` API docs.](http://benchmarkjs.com/docs#Suite_prototype_run) 176 | */ 177 | run(config) { 178 | var mapkey, mapfun; 179 | 180 | let createBenchmarkFunction = (fun, options, input) => { 181 | if (options.defer) { 182 | return deferred => { 183 | fun.apply(this, [deferred].concat(input)) 184 | }; 185 | } 186 | return () => { 187 | fun.apply(this, input); 188 | }; 189 | } 190 | 191 | for (var i = 0; i < this._functions.length; i++) { 192 | for (var j = 0; j < this._inputs.length; j++) { 193 | mapkey = this._functionNames[i] + " for inputs " + this._inputNames[j]; 194 | mapfun = createBenchmarkFunction(this._functions[i], this._functionOptions[i], this._inputs[j]); 195 | this.add(mapkey, mapfun, this._functionOptions[i]); 196 | this._mappings[mapkey] = { 197 | funcIdx: i, 198 | inputIdx: j 199 | }; 200 | } 201 | } 202 | 203 | this._counter = this._functions.length * this._inputs.length; 204 | 205 | super.run(config); 206 | } 207 | 208 | /** 209 | * addFunction 210 | * Specify functions to be benchmarked. 211 | * This function may be called multiple times to add multiple functions. 212 | * 213 | * @name addFunction 214 | * @function 215 | * @param {String} name A name to identify the function. 216 | * @param {Function} fun The test to benchmark. 217 | * @param {Object} options The options object. 218 | * @return {BenchTable} The `BenchTable` instance. 219 | */ 220 | addFunction(name, fun, options) { 221 | this._functions.push(fun); 222 | this._functionNames.push(name); 223 | this._functionOptions.push(options || {}); 224 | this._results[name] = []; 225 | return this; 226 | } 227 | 228 | /** 229 | * addInput 230 | * Specify inputs for functions. 231 | * This function may be called multiple times to add multiple inputs. 232 | * 233 | * @name addInput 234 | * @function 235 | * @param {String} name A name to identify the input. 236 | * @param {Array} input The array containing arguments that will be 237 | * passed to each benchmarked function. Therefore, the number of 238 | * elements in the `input` array should match the number of arguments of 239 | * each specified function (i.e. the array will be "unpacked" when 240 | * invoking functions, they will not receive a single array argument). 241 | * @return {BenchTable} The `BenchTable` instance. 242 | */ 243 | addInput(name, input) { 244 | this._inputs.push(input); 245 | this._inputNames.push(name); 246 | return this; 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /examples/string_search.js: -------------------------------------------------------------------------------- 1 | // Import the ../ module 2 | var BenchTable = require('../'); 3 | 4 | // Create benchtable suite 5 | var suite = new BenchTable(); 6 | 7 | suite 8 | // Add functions for benchmarking 9 | .addFunction('RegExp#test', s => /o/.test(s)) 10 | .addFunction('String#indexOf', s => s.indexOf('o') > -1) 11 | // Add inputs 12 | .addInput('Short string', ['Hello world!']) 13 | .addInput('Long string', ['This is a very big string, isnt it? It is. Really. So, hello world!']) 14 | .addInput('Very long string', [`This is a ${new Array(100).join('very ')} + 'big string, isnt it? It is. ${new Array(100).join('Really. ')} So, hello world!`]) 15 | .addInput('Extremely long string', [`This is a ${new Array(10000).join('very ')} + 'big string, isnt it? It is. ${new Array(10000).join('Really. ')} So, hello world!`]) 16 | // Add listeners 17 | .on('cycle', event => { 18 | console.log(event.target.toString()); 19 | }) 20 | .on('complete', () => { 21 | console.log('Fastest is ' + suite.filter('fastest').map('name')); 22 | console.log(suite.table.toString()); 23 | }) 24 | // Run async 25 | .run({ async: false }) 26 | ; 27 | 28 | // => 29 | // RegExp#test for inputs Short string x 11,037,873 ops/sec ±0.57% (100 runs sampled) 30 | // RegExp#test for inputs Long string x 10,114,587 ops/sec ±0.42% (100 runs sampled) 31 | // RegExp#test for inputs Very long string x 7,534,743 ops/sec ±0.33% (101 runs sampled) 32 | // RegExp#test for inputs Extremely long string x 304,666 ops/sec ±0.25% (101 runs sampled) 33 | // String#indexOf for inputs Short string x 13,400,084 ops/sec ±0.28% (99 runs sampled) 34 | // String#indexOf for inputs Long string x 12,947,759 ops/sec ±0.33% (100 runs sampled) 35 | // String#indexOf for inputs Very long string x 8,489,440 ops/sec ±0.31% (101 runs sampled) 36 | // String#indexOf for inputs Extremely long string x 306,018 ops/sec ±0.26% (100 runs sampled) 37 | // Fastest is String#indexOf for inputs Short string 38 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 39 | // | │ Short string │ Long string │ Very long string │ Extremely long string | 40 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 41 | // | RegExp#test │ 11,037,873 ops/sec │ 10,114,587 ops/sec │ 7,534,743 ops/sec │ 304,666 ops/sec | 42 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 43 | // | String#indexOf │ 13,400,084 ops/sec │ 12,947,759 ops/sec │ 8,489,440 ops/sec │ 306,018 ops/sec | 44 | // +----------------+--------------------+--------------------+-------------------+-----------------------+ 45 | -------------------------------------------------------------------------------- /examples/string_search_transposed.js: -------------------------------------------------------------------------------- 1 | // Import the ../ module 2 | var BenchTable = require('../'); 3 | 4 | // Create benchtable suite 5 | var suite = new BenchTable('test', {isTransposed : true}); 6 | 7 | suite 8 | // Add functions for benchmarking 9 | .addFunction('RegExp#test', s => /o/.test(s)) 10 | .addFunction('String#indexOf', s => s.indexOf('o') > -1) 11 | // Add inputs 12 | .addInput('Short string', ['Hello world!']) 13 | .addInput('Long string', ['This is a very big string, isnt it? It is. Really. So, hello world!']) 14 | .addInput('Very long string', [`This is a ${new Array(100).join('very ')} + 'big string, isnt it? It is. ${new Array(100).join('Really. ')} So, hello world!`]) 15 | .addInput('Extremely long string', [`This is a ${new Array(10000).join('very ')} + 'big string, isnt it? It is. ${new Array(10000).join('Really. ')} So, hello world!`]) 16 | // Add listeners 17 | .on('cycle', event => { 18 | console.log(event.target.toString()); 19 | }) 20 | .on('complete', () => { 21 | console.log('Fastest is ' + suite.filter('fastest').map('name')); 22 | console.log(suite.table.toString()); 23 | }) 24 | // Run async 25 | .run({ async: false }) 26 | ; 27 | 28 | // => 29 | // RegExp#test for inputs Short string x 11,139,499 ops/sec ±0.56% (97 runs sampled) 30 | // RegExp#test for inputs Long string x 10,370,952 ops/sec ±0.66% (97 runs sampled) 31 | // RegExp#test for inputs Very long string x 7,386,009 ops/sec ±0.60% (98 runs sampled) 32 | // RegExp#test for inputs Extremely long string x 297,936 ops/sec ±0.40% (99 runs sampled) 33 | // String#indexOf for inputs Short string x 12,844,042 ops/sec ±0.44% (96 runs sampled) 34 | // String#indexOf for inputs Long string x 12,474,178 ops/sec ±0.48% (98 runs sampled) 35 | // String#indexOf for inputs Very long string x 8,471,914 ops/sec ±0.36% (94 runs sampled) 36 | // String#indexOf for inputs Extremely long string x 301,176 ops/sec ±0.43% (93 runs sampled) 37 | // Fastest is String#indexOf for inputs Short string 38 | // +-----------------------+--------------------+--------------------+ 39 | // | │ RegExp#test │ String#indexOf | 40 | // +-----------------------+--------------------+--------------------+ 41 | // | Short string │ 11,139,499 ops/sec │ 12,844,042 ops/sec | 42 | // +-----------------------+--------------------+--------------------+ 43 | // | Long string │ 10,370,952 ops/sec │ 12,474,178 ops/sec | 44 | // +-----------------------+--------------------+--------------------+ 45 | // | Very long string │ 7,386,009 ops/sec │ 8,471,914 ops/sec | 46 | // +-----------------------+--------------------+--------------------+ 47 | // | Extremely long string │ 297,936 ops/sec │ 301,176 ops/sec | 48 | // +-----------------------+--------------------+--------------------+ 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "benchtable", 3 | "preferGlobal": false, 4 | "version": "0.0.6", 5 | "author": "Ivan Zuzak (http://ivanzuzak.info)", 6 | "description": "Benchmark.js results in ascii tables for NodeJS", 7 | "bugs": { 8 | "url": "https://github.com/izuzak/benchtable/issues" 9 | }, 10 | "homepage": "https://github.com/izuzak/benchtable", 11 | "main": "./benchtable.js", 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/izuzak/benchtable.git" 15 | }, 16 | "keywords": [ 17 | "nodejs", 18 | "benchmarking", 19 | "performance", 20 | "table", 21 | "colors", 22 | "javascript" 23 | ], 24 | "dependencies": { 25 | "benchmark": "^2.0.0", 26 | "cli-table": "^0.3.1", 27 | "color-it": "^1.2.0" 28 | }, 29 | "engines": { 30 | "node": ">=4.0.0" 31 | }, 32 | "directories": { 33 | "example": "examples" 34 | }, 35 | "scripts": { 36 | "test": "echo \"Error: no test specified\" && exit 1" 37 | }, 38 | "license": "Apache-2.0" 39 | } 40 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izuzak/benchtable/9e1f64a7aa4806a9dd90e1429231ca25b3cfeaab/screenshot.png --------------------------------------------------------------------------------