Skip to content

Commit 8b1f2d3

Browse files
author
Andre Medeiros
committed
perf(filter-map-reduce): add preliminary perf micro benchmarks
1 parent 2caa2ca commit 8b1f2d3

File tree

3 files changed

+274
-0
lines changed

3 files changed

+274
-0
lines changed

perf/filter-map-reduce.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
var Benchmark = require('benchmark');
2+
var xstream = require('../lib/index').default;
3+
var most = require('most');
4+
var rx = require('rx');
5+
var rxjs = require('@reactivex/rxjs')
6+
var kefir = require('kefir');
7+
var bacon = require('baconjs');
8+
var lodash = require('lodash');
9+
var highland = require('highland');
10+
11+
var runners = require('./runners');
12+
var kefirFromArray = runners.kefirFromArray;
13+
14+
// Create a stream from an Array of n integers
15+
// filter out odds, map remaining evens by adding 1, then reduce by summing
16+
var n = runners.getIntArg(1000000);
17+
var a = new Array(n);
18+
for(var i = 0; i< a.length; ++i) {
19+
a[i] = i;
20+
}
21+
22+
var suite = Benchmark.Suite('filter -> map -> reduce ' + n + ' integers');
23+
var options = {
24+
defer: true,
25+
onError: function(e) {
26+
e.currentTarget.failure = e.error;
27+
}
28+
};
29+
30+
suite
31+
.add('most', function(deferred) {
32+
runners.runMost(deferred, most.from(a).filter(even).map(add1).reduce(sum, 0));
33+
}, options)
34+
.add('rx 4', function(deferred) {
35+
runners.runRx(deferred, rx.Observable.fromArray(a).filter(even).map(add1))//.reduce(sum, 0));
36+
}, options)
37+
.add('rx 5', function(deferred) {
38+
runners.runRx5(deferred,
39+
rxjs.Observable.fromArray(a).filter(even).map(add1))//.reduce(sum, 0));
40+
}, options)
41+
.add('xstream', function(deferred) {
42+
runners.runXStream(deferred,
43+
xstream.from(a).filter(even).map(add1))//.reduce(sum, 0));
44+
}, options)
45+
.add('kefir', function(deferred) {
46+
runners.runKefir(deferred, kefirFromArray(a).filter(even).map(add1).scan(sum, 0).last());
47+
}, options)
48+
.add('bacon', function(deferred) {
49+
runners.runBacon(deferred, bacon.fromArray(a).filter(even).map(add1))//.reduce(0, sum));
50+
}, options)
51+
.add('highland', function(deferred) {
52+
runners.runHighland(deferred, highland(a).filter(even).map(add1))//.reduce(0, sum));
53+
}, options)
54+
.add('lodash', function() {
55+
return lodash(a).filter(even).map(add1)//.reduce(sum, 0);
56+
})
57+
.add('Array', function() {
58+
return a.filter(even).map(add1)//.reduce(sum, 0);
59+
});
60+
61+
runners.runSuite(suite);
62+
63+
function add1(x) {
64+
return x + 1;
65+
}
66+
67+
function even(x) {
68+
return x % 2 === 0;
69+
}
70+
71+
function sum(x, y) {
72+
return x + y;
73+
}

perf/package.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "xstream-perf",
3+
"version": "0.0.0",
4+
"description": "Perf tests for most.js",
5+
"author": "Andre Staltz <andre+npm@staltz.com> (http://andre.staltz.com/)",
6+
"license": "MIT",
7+
"scripts": {
8+
"concatMap": "node ./concatMap.js",
9+
"filter-map-reduce": "node ./filter-map-reduce",
10+
"flatMap": "node ./flatMap.js",
11+
"merge": "node ./merge.js",
12+
"scan": "node ./scan.js",
13+
"skipRepeats": "node ./skipRepeats.js",
14+
"zip": "node ./zip.js",
15+
"start": "npm run filter-map-reduce && npm run flatMap && npm run concatMap && npm run merge && npm run zip && npm run scan && npm run skipRepeats"
16+
},
17+
"dependencies": {
18+
"@reactivex/rxjs": "^5.0.0-beta.0",
19+
"baconjs": "^0.7.82",
20+
"benchmark": "github:bestiejs/benchmark.js#master",
21+
"highland": "^2.5.1",
22+
"kefir": "^3.2.0",
23+
"lodash": "^3.10.1",
24+
"most": "^0.18.1",
25+
"rx": "^4.0.8"
26+
}
27+
}

perf/runners.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
var kefir = require('kefir');
2+
kefir.DEPRECATION_WARNINGS = false;
3+
4+
exports.runSuite = runSuite;
5+
6+
exports.runMost = runMost;
7+
exports.runRx = runRx;
8+
exports.runRx5 = runRx5;
9+
exports.runXStream = runXStream;
10+
exports.runKefir = runKefir;
11+
exports.kefirFromArray = kefirFromArray;
12+
exports.runBacon = runBacon;
13+
exports.runHighland = runHighland;
14+
15+
exports.getIntArg = getIntArg;
16+
exports.getIntArg2 = getIntArg2;
17+
exports.logResults = logResults;
18+
19+
function noop() {}
20+
21+
function _getIntArg(defaultValue, index) {
22+
var n = parseInt(process.argv[index]);
23+
return isNaN(n) ? defaultValue : n;
24+
}
25+
26+
function getIntArg(defaultValue) {
27+
return _getIntArg(defaultValue, process.argv.length - 1);
28+
}
29+
30+
function getIntArg2(default1, default2) {
31+
var m = _getIntArg(default1, process.argv.length - 2);
32+
var n = _getIntArg(default2, process.argv.length - 1);
33+
return [m, n];
34+
}
35+
36+
function logResults(e) {
37+
var t = e.target;
38+
39+
if(t.failure) {
40+
console.error(padl(10, t.name) + 'FAILED: ' + e.target.failure);
41+
} else {
42+
var result = padl(10, t.name)
43+
+ padr(13, t.hz.toFixed(2) + ' op/s')
44+
+ ' \xb1' + padr(7, t.stats.rme.toFixed(2) + '%')
45+
+ padr(15, ' (' + t.stats.sample.length + ' samples)');
46+
47+
console.log(result);
48+
}
49+
}
50+
51+
function logStart() {
52+
console.log(this.name);
53+
console.log('-------------------------------------------------------');
54+
}
55+
56+
function logComplete() {
57+
console.log('-------------------------------------------------------');
58+
}
59+
60+
function runSuite(suite) {
61+
return suite
62+
.on('start', logStart)
63+
.on('cycle', logResults)
64+
.on('complete', logComplete)
65+
.run();
66+
}
67+
68+
function runMost(deferred, mostPromise) {
69+
mostPromise.then(function() {
70+
deferred.resolve();
71+
}, function(e) {
72+
deferred.benchmark.emit({ type: 'error', error: e });
73+
deferred.resolve(e);
74+
});
75+
}
76+
77+
function runRx(deferred, rxStream) {
78+
rxStream.subscribe({
79+
onNext: noop,
80+
onCompleted: function() {
81+
deferred.resolve();
82+
},
83+
onError: function(e) {
84+
deferred.benchmark.emit({ type: 'error', error: e });
85+
deferred.resolve(e);
86+
}
87+
});
88+
}
89+
90+
function runRx5(deferred, rxStream) {
91+
rxStream.subscribe({
92+
next: noop,
93+
complete: function() {
94+
deferred.resolve();
95+
},
96+
error: function(e) {
97+
deferred.benchmark.emit({ type: 'error', error: e });
98+
deferred.resolve(e);
99+
}
100+
});
101+
}
102+
103+
function runXStream(deferred, xstream) {
104+
xstream.subscribe({
105+
next: noop,
106+
complete: function() {
107+
deferred.resolve();
108+
},
109+
error: function(e) {
110+
deferred.benchmark.emit({ type: 'error', error: e });
111+
deferred.resolve(e);
112+
}
113+
});
114+
}
115+
116+
function runKefir(deferred, kefirStream) {
117+
kefirStream.onValue(noop);
118+
kefirStream.onEnd(function() {
119+
deferred.resolve();
120+
});
121+
}
122+
123+
function kefirFromArray(array) {
124+
return kefir.stream(function(emitter) {
125+
for(var i=0; i<array.length; ++i) {
126+
emitter.emit(array[i]);
127+
}
128+
emitter.end();
129+
});
130+
}
131+
132+
function runBacon(deferred, baconStream) {
133+
try {
134+
baconStream.onValue(noop);
135+
baconStream.onEnd(function() {
136+
deferred.resolve();
137+
});
138+
baconStream.onError(function(e) {
139+
deferred.benchmark.emit({ type: 'error', error: e });
140+
deferred.resolve(e);
141+
});
142+
} catch(e) {
143+
deferred.benchmark.emit({ type: 'error', error: e });
144+
deferred.resolve(e);
145+
}
146+
}
147+
148+
// Using pull() seems to give the fastest results for highland,
149+
// but will only work for test runs that reduce a stream to a
150+
// single value.
151+
function runHighland(deferred, highlandStream) {
152+
highlandStream.pull(function(err, z) {
153+
if(err) {
154+
deferred.reject(err);
155+
return;
156+
}
157+
158+
deferred.resolve(z);
159+
});
160+
}
161+
162+
function padl(n, s) {
163+
while(s.length < n) {
164+
s += ' ';
165+
}
166+
return s;
167+
}
168+
169+
function padr(n, s) {
170+
while (s.length < n) {
171+
s = ' ' + s;
172+
}
173+
return s;
174+
}

0 commit comments

Comments
 (0)