Created some benchmarks for the expression parser

This commit is contained in:
jos 2017-06-05 11:53:15 +02:00
parent 943a99df71
commit fb8a4e0a0e
9 changed files with 3513 additions and 117 deletions

View File

@ -1,41 +1,32 @@
# Benchmarks
These are some rough benchmarks to get an idea of the performance of math.js compared to other JavaScript libraries and to Octave (C++). They only give an _indication_ of the order of magnitude difference meant to see were math.js has room for improvements, it's not a fully fletched benchmark suite.
This directory contains benchmarks which can be used when working on
performance improvements of math.js.
## How to run
### JavaScript library benchmarks
Install the dependencies once:
To run all benchmarks:
```
npm install
node index.js
```
run the tests:
To run a single set of benchmarks:
```
node benchmark.js
node expression_parser.js
```
### Octave benchmarks
## Octave benchmarks
Open Octave, run the script `benchmark_octave.m`
For matrix operations, there is a small benchmark for Octave.
Open Octave, run the script `matrix_operations_octave.m`
## To do
- compare with python and Octave
- compare matrix operations with python
- use larger matrix, like 250x250 instead of 25x25
- Compare expression parsers
evaluate the following function thousand times
f(x) = (sin(x) + cos(x/2)) * 5
Libraries:
- math.js
- expr-eval
- jsep

View File

@ -0,0 +1,34 @@
// test performance of the expression parser in node.js
var Benchmark = require('benchmark');
var padRight = require('pad-right');
var math = require('../index');
function pad (text) {
return padRight(text, 40, ' ');
}
var expr = '2 + 3 * sin(pi / 4) - 4x';
var scope = {x: 2};
var compiled = math.parse(expr).compile();
var suite = new Benchmark.Suite();
suite
.add(pad('expression parse and evaluate'), function() {
var res = math.eval(expr, scope);
})
.add(pad('expression parse and compile'), function() {
var c = math.parse('2 + 3 * sin(pi / 4) - 4x').compile();
})
.add(pad('expression parse'), function() {
var node = math.parse('2 + 3 * sin(pi / 4) - 4x');
})
.add(pad('evaluate'), function() {
var res = compiled.eval(scope);
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
})
.run();

3
benchmark/index.js Normal file
View File

@ -0,0 +1,3 @@
// run all benchmarks
require ('./expression_parser');
require ('./matrix_operations');

View File

@ -1,13 +1,21 @@
/**
* Benchmark
*
* Compare performance of basic matrix operations of a number of math libraries.
* Compare performance of basic matrix operations of a number of math libraries.
*
* These are some rough benchmarks to get an idea of the performance of math.js
* compared to other JavaScript libraries and to Octave (C++). They only give an
* _indication_ of the order of magnitude difference meant to see were math.js
* has room for improvements, it's not a fully fletched benchmark suite.
*/
var padLeft = require('pad-left')
var padRight = require('pad-right')
var Benchmark = require('benchmark');
var padRight = require('pad-right');
var suite = new Benchmark.Suite();
var iterations = 1000
function pad (text) {
return padRight(text, 40, ' ');
}
// fiedler matrix 25 x 25
var fiedler = [
@ -36,89 +44,62 @@ var fiedler = [
[22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2],
[23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1],
[24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
]
];
// mathjs
{
var math = require('../index')
var A = math.matrix(fiedler)
(function () {
var math = require('../index');
var A = math.matrix(fiedler);
var res;
measure ('mathjs', 'A+A', function () { res = math.add(A, A) })
measure ('mathjs', 'A*A', function () { res = math.multiply(A, A) })
measure ('mathjs', 'A\'', function () { res = math.transpose(A) })
measure ('mathjs', 'det(A)', function () { res = math.det(A) })
}
suite.add(pad('matrix operations mathjs A+A'), function () { res = math.add(A, A) });
suite.add(pad('matrix operations mathjs A*A'), function () { res = math.multiply(A, A) });
suite.add(pad('matrix operations mathjs A\''), function () { res = math.transpose(A) });
suite.add(pad('matrix operations mathjs det(A)'), function () { res = math.det(A) });
})();
// sylvester
{
var sylvester = require('sylvester')
var A = sylvester.Matrix.create(fiedler)
(function () {
var sylvester = require('sylvester');
var A = sylvester.Matrix.create(fiedler);
measure ('sylvester', 'A+A', function () { A.add(A) })
measure ('sylvester', 'A*A', function () { A.multiply(A) })
measure ('sylvester', 'A\'', function () { A.transpose() })
measure ('sylvester', 'det(A)', function () { A.det() })
}
suite.add(pad('matrix operations sylvester A+A'), function () { A.add(A) });
suite.add(pad('matrix operations sylvester A*A'), function () { A.multiply(A) });
suite.add(pad('matrix operations sylvester A\''), function () { A.transpose() });
suite.add(pad('matrix operations sylvester det(A)'), function () { A.det() });
})();
// numericjs
{
var numeric = require('numericjs')
var A = fiedler
(function () {
var numeric = require('numericjs');
var A = fiedler;
measure ('numericjs', 'A+A', function () { numeric.add(A, A) })
measure ('numericjs', 'A*A', function () { numeric.dot(A, A) })
measure ('numericjs', 'A\'', function () { numeric.transpose(A) })
measure ('numericjs', 'det(A)', function () { numeric.det(A) })
}
suite.add(pad('matrix operations numericjs A+A'), function () { numeric.add(A, A) });
suite.add(pad('matrix operations numericjs A*A'), function () { numeric.dot(A, A) });
suite.add(pad('matrix operations numericjs A\''), function () { numeric.transpose(A) });
suite.add(pad('matrix operations numericjs det(A)'), function () { numeric.det(A) });
})();
// ndarray
{
var ndarray = require('ndarray')
var gemm = require('ndarray-gemm')
var zeros = require('zeros')
var ops = require('ndarray-ops')
var pack = require('ndarray-pack')
var det = require('ndarray-determinant')
(function () {
var ndarray = require('ndarray');
var gemm = require('ndarray-gemm');
var zeros = require('zeros');
var ops = require('ndarray-ops');
var pack = require('ndarray-pack');
var det = require('ndarray-determinant');
var A = pack(fiedler)
var B = zeros([25, 25])
var A = pack(fiedler);
var B = zeros([25, 25]);
measure('ndarray', 'A+A', function () { ops.add(B, A, A) })
measure('ndarray', 'A*A', function () { gemm(B, A, A) })
measure('ndarray', 'A\'', function () { ops.assign(B, A); B.transpose(1, 0); })
measure('ndarray', 'det(A)', function () { det(A) })
}
suite.add(pad('matrix operations ndarray A+A'), function () { ops.add(B, A, A) });
suite.add(pad('matrix operations ndarray A*A'), function () { gemm(B, A, A) });
suite.add(pad('matrix operations ndarray A\''), function () { ops.assign(B, A); B.transpose(1, 0); });
suite.add(pad('matrix operations ndarray det(A)'), function () { det(A) });
})();
/**
* Repeatedly execute test and print the average duration
* @param {string} library
* @param {string} description
* @param {function} test
*/
function measure (library, description, test) {
// warm up
test()
var start = Date.now()
for (var i = 0; i < iterations / 10; i++) {
// ten times to minimize the impact of the duration of the for loop itself
test()
test()
test()
test()
test()
test()
test()
test()
test()
test()
}
var end = Date.now()
var duration = Math.round((end - start) * 1000 / (iterations)) // in microseconds
console.log(padRight(library, 12, ' ') + padRight(description, 8, ' ') + padLeft(duration, 6, ' ') + ' microseconds')
}
function flatten (arr) {
return [].concat.apply([], arr)
}
suite
.on('cycle', function(event) {
console.log(String(event.target));
})
.run();

View File

@ -1,17 +0,0 @@
{
"dependencies": {
"expr-eval": "1.0.0",
"jsep": "0.3.0",
"math-expression-evaluator": "1.2.16",
"ndarray": "1.0.18",
"ndarray-determinant": "1.0.0",
"ndarray-gemm": "1.0.0",
"ndarray-ops": "1.2.2",
"ndarray-pack": "1.2.1",
"numericjs": "1.2.6",
"pad-left": "2.1.0",
"pad-right": "0.2.2",
"sylvester": "0.0.21",
"zeros": "1.0.0"
}
}

3390
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -81,25 +81,38 @@
"unit"
],
"dependencies": {
"seed-random": "2.2.0",
"tiny-emitter": "1.0.2",
"complex.js": "2.0.1",
"decimal.js": "7.1.1",
"fraction.js": "4.0.0",
"complex.js": "2.0.1",
"seed-random": "2.2.0",
"tiny-emitter": "1.0.2",
"typed-function": "0.10.5"
},
"devDependencies": {
"benchmark": "2.1.4",
"expr-eval": "1.0.0",
"glob": "7.1.1",
"gulp": "3.9.1",
"gulp-util": "3.0.8",
"istanbul": "0.4.5",
"jsep": "0.3.0",
"math-expression-evaluator": "1.2.16",
"mkdirp": "0.5.1",
"mocha": "3.2.0",
"ndarray": "1.0.18",
"ndarray-determinant": "1.0.0",
"ndarray-gemm": "1.0.0",
"ndarray-ops": "1.2.2",
"ndarray-pack": "1.2.1",
"numericjs": "1.2.6",
"pad-right": "0.2.2",
"q": "1.4.1",
"sylvester": "0.0.21",
"tar": "2.2.1",
"uglify-js": "2.7.5",
"underscore": "1.8.3",
"webpack": "2.2.1"
"webpack": "2.2.1",
"zeros": "1.0.0"
},
"main": "./index",
"scripts": {
@ -114,5 +127,6 @@
},
"engines": {
"node": ">= 0.1"
}
},
"false": {}
}