Skip to content

Commit bc858a3

Browse files
🚧 progress: More benchmarks.
1 parent d299223 commit bc858a3

File tree

4 files changed

+313
-41
lines changed

4 files changed

+313
-41
lines changed

_benchmark/benchmark.js

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,20 @@
1-
require('regenerator-runtime/runtime');
1+
import 'regenerator-runtime/runtime.js';
22

3-
const ArgumentParser = require('argparse').ArgumentParser;
4-
const Benchmark = require('benchmark');
3+
import {ArgumentParser} from 'argparse';
4+
import Benchmark from 'benchmark';
55

6-
const range = require('@iterable-iterator/range').range;
6+
import {range} from '@iterable-iterator/range';
77

8-
const qiao_fingertree = require('fingertree');
9-
const fds_finger_tree = require('..');
8+
import qiao_fingertree from 'fingertree';
9+
import {empty, from} from '../dist/index.modern.js';
1010

11-
const fromArray = qiao_fingertree.fromArray;
12-
const empty = fds_finger_tree.empty;
13-
const from = fds_finger_tree.from;
11+
import {FAST_COUNTER as COUNTER} from '../test/src/_fixtures.js';
1412

15-
const COUNTER = {
16-
plus(a, b) {
17-
return a + b;
18-
},
19-
measure(_x) {
20-
return 1;
21-
},
22-
zero() {
23-
return 0;
24-
},
25-
};
13+
const fromArray = qiao_fingertree.fromArray;
2614

2715
const parser = new ArgumentParser();
28-
parser.addArgument(['M']);
29-
const args = parser.parseArgs();
16+
parser.add_argument(['M']);
17+
const args = parser.parse_args();
3018

3119
global.M = args.M;
3220
global.COUNTER = COUNTER;

_benchmark/fromLoop.js

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import assert from 'assert';
2+
3+
import 'regenerator-runtime/runtime.js';
4+
import {ArgumentParser} from 'argparse';
5+
6+
import {range} from '@iterable-iterator/range';
7+
8+
import Benchtable from 'benchtable';
9+
import {
10+
FAST_COUNTER as COUNTER,
11+
measure,
12+
measureToString,
13+
} from '../test/src/_fixtures.js';
14+
15+
import {dist, dependency, object} from './_fixtures.js';
16+
17+
const parser = new ArgumentParser();
18+
parser.add_argument('filter');
19+
const args = parser.parse_args();
20+
const filter = new RegExp(args.filter, 'i');
21+
22+
const cjs = dist('cjs');
23+
const module = dist('module.js');
24+
const modern = dist('modern.js');
25+
const list = dependency('list');
26+
const array = object('Array', Array);
27+
28+
const suite = new Benchtable('Tree Construction', {isTransposed: false});
29+
30+
const add = async (module, fn) => {
31+
if (!filter.test(module.name)) return;
32+
if (!filter.test(fn.name)) return;
33+
const {title, build} = await fn.compile(module);
34+
suite.addFunction(
35+
title,
36+
(measure, n) => {
37+
build(measure, n);
38+
},
39+
{
40+
maxTime: 5,
41+
},
42+
);
43+
if (!filter.test('measure')) return;
44+
suite.addFunction(
45+
`${title}.measure`,
46+
(measure, n, expected) => {
47+
const result = build(measure, n).measure();
48+
if (result !== expected) {
49+
throw new Error('wrong measure');
50+
}
51+
},
52+
{
53+
maxTime: 5,
54+
},
55+
);
56+
};
57+
58+
const makeFn = ({name: fnName, build}) => ({
59+
name: fnName,
60+
compile: async (module) => {
61+
const {name, version, exports} = await module.load();
62+
return {
63+
title: `${name} ${version} #${fnName}`,
64+
build: build({exports}),
65+
};
66+
},
67+
});
68+
69+
const treePush = makeFn({
70+
name: 'push',
71+
build: ({exports}) => {
72+
const empty = exports.empty;
73+
return (measure, n) => {
74+
let l = empty(measure);
75+
for (let i = 0; i < n; ++i) l = l.push(i);
76+
return l;
77+
};
78+
},
79+
});
80+
81+
const listAppend = makeFn({
82+
name: 'push',
83+
build: ({exports}) => {
84+
const {empty, append} = exports;
85+
return (_measure, n) => {
86+
let l = empty();
87+
for (let i = 0; i < n; ++i) l = append(i, l);
88+
return l;
89+
};
90+
},
91+
});
92+
93+
const arrayPush = makeFn({
94+
name: 'push',
95+
build: ({exports}) => {
96+
assert(exports === Array);
97+
return (_measure, n) => {
98+
const l = [];
99+
for (let i = 0; i < n; ++i) l.push(i);
100+
return l;
101+
};
102+
},
103+
});
104+
105+
await add(cjs, treePush);
106+
await add(module, treePush);
107+
await add(modern, treePush);
108+
109+
await add(list, listAppend);
110+
await add(array, arrayPush);
111+
112+
const addTitle = (input) => {
113+
const {measure, n} = input;
114+
const title = `(${measureToString(measure)}, ${n})`;
115+
return {
116+
...input,
117+
title,
118+
};
119+
};
120+
121+
const addExpected = (input) => {
122+
const expected = measure(input.measure, range(input.n));
123+
return {
124+
...input,
125+
expected,
126+
};
127+
};
128+
129+
const benchmarkInputs = [
130+
{
131+
measure: COUNTER,
132+
n: 1000,
133+
},
134+
{
135+
measure: COUNTER,
136+
n: 10_000,
137+
},
138+
{
139+
measure: COUNTER,
140+
n: 100_000,
141+
},
142+
]
143+
.map(addTitle)
144+
.map(addExpected);
145+
146+
for (const {title, measure, n, expected} of benchmarkInputs) {
147+
suite.addInput(title, [measure, n, expected]);
148+
}
149+
150+
suite.on('cycle', (evt) => {
151+
console.log(evt.target.name);
152+
});
153+
154+
suite.on('complete', () => {
155+
console.log(suite.table.toString());
156+
});
157+
158+
suite.run();

_benchmark/table.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import 'regenerator-runtime/runtime.js';
2+
3+
import {ArgumentParser} from 'argparse';
4+
import Benchtable from 'benchtable';
5+
6+
import {range} from '@iterable-iterator/range';
7+
8+
import {
9+
FAST_COUNTER as COUNTER,
10+
measureToString,
11+
} from '../test/src/_fixtures.js';
12+
13+
import {dist} from './_fixtures.js';
14+
15+
const parser = new ArgumentParser();
16+
parser.add_argument('M');
17+
const args = parser.parse_args();
18+
19+
global.range = range;
20+
global.n = args.M;
21+
global.measure = COUNTER;
22+
23+
const suite = new Benchtable('Methods', {isTransposed: false});
24+
25+
const modern = dist('modern.js');
26+
const {name, version, exports} = await modern.load();
27+
28+
const {empty, from} = exports;
29+
30+
global.empty = empty;
31+
global.from = from;
32+
33+
global.t = empty(measure);
34+
global.r = range(n);
35+
global.at = from(measure, r);
36+
37+
const splits = [];
38+
for (let i = 0; i < n; ++i) {
39+
splits.push(at.split((m) => m > i));
40+
}
41+
42+
global.splits = splits;
43+
44+
const fds_finger_tree = {
45+
name: '@functional-data-structure/finger-tree',
46+
compile: async () => ({
47+
title: `${name} ${version}`,
48+
methods: {
49+
push: {
50+
run: () => {
51+
let _t = t;
52+
const _n = n;
53+
for (let i = 0; i < _n; ++i) _t = _t.push(i);
54+
},
55+
},
56+
cons: {
57+
run: () => {
58+
let _t = t;
59+
const _n = n;
60+
for (let i = 0; i < _n; ++i) _t = _t.cons(i);
61+
},
62+
},
63+
init: {
64+
run: () => {
65+
let _t = at;
66+
const _n = n;
67+
for (let i = 0; i < _n; ++i) _t = _t.init();
68+
},
69+
},
70+
tail: {
71+
run: () => {
72+
let _t = at;
73+
const _n = n;
74+
for (let i = 0; i < _n; ++i) _t = _t.tail();
75+
},
76+
},
77+
append: {
78+
run: () => {
79+
at.append(r);
80+
},
81+
},
82+
prepend: {
83+
run: () => {
84+
at.prepend(r);
85+
},
86+
},
87+
from: {
88+
run: () => {
89+
from(measure, r);
90+
},
91+
},
92+
split: {
93+
run: () => {
94+
const _at = at;
95+
const _n = n;
96+
for (let i = 0; i < _n; ++i) _at.split((m) => m > i);
97+
},
98+
},
99+
concat: {
100+
run: () => {
101+
const _s = splits;
102+
const _n = n;
103+
for (let i = 0; i < _n; ++i) _s[i][0].concat(_s[i][1]);
104+
},
105+
},
106+
},
107+
}),
108+
};
109+
110+
const add = async (module, api, method) => {
111+
// If (!filter.test(module.name)) return;
112+
const {title, methods} = await api.compile(module);
113+
114+
suite.addFunction(`${title} #${method}`, methods[method].run, {
115+
maxTime: 5,
116+
});
117+
};
118+
119+
await add(modern, fds_finger_tree, 'from');
120+
await add(modern, fds_finger_tree, 'push');
121+
await add(modern, fds_finger_tree, 'cons');
122+
await add(modern, fds_finger_tree, 'init');
123+
await add(modern, fds_finger_tree, 'tail');
124+
await add(modern, fds_finger_tree, 'append');
125+
await add(modern, fds_finger_tree, 'prepend');
126+
await add(modern, fds_finger_tree, 'split');
127+
await add(modern, fds_finger_tree, 'concat');
128+
129+
suite.addInput(`(${measureToString(measure)}, ${n})`, []);
130+
131+
suite.on('cycle', (evt) => {
132+
console.log(`${evt.target.name}: ${evt.target.hz} ops/sec`);
133+
});
134+
135+
suite.on('complete', () => {
136+
console.log(suite.table.toString());
137+
});
138+
139+
suite.run();

_benchmark/tree.js

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
1-
require('regenerator-runtime/runtime');
2-
const range = require('@iterable-iterator/range').range;
3-
const fingertree = require('..');
4-
5-
const empty = fingertree.empty;
6-
const from = fingertree.from;
7-
8-
const COUNTER = {
9-
plus(a, b) {
10-
return a + b;
11-
},
12-
measure(_x) {
13-
return 1;
14-
},
15-
zero() {
16-
return 0;
17-
},
18-
};
1+
import 'regenerator-runtime/runtime.js';
2+
import {range} from '@iterable-iterator/range';
3+
import {empty, from} from '../dist/index.modern.js';
4+
5+
import {FAST_COUNTER as COUNTER} from '../test/src/_fixtures.js';
196

207
let t;
218
let i;
22-
const length = 100_000;
9+
const length = 300_000;
2310

2411
let start = Date.now();
2512

0 commit comments

Comments
 (0)