Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More tests, benchmarks, and profiling loops #223

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ec494bb
:wrench: config(hooks): Explicit config path in commit-msg.
make-github-pseudonymous-again Oct 14, 2021
2eabf53
:wrench: config(xo): Use @babel/eslint-parser.
make-github-pseudonymous-again Oct 14, 2021
0fb92a7
:test_tube: test(api): Exhaustive testing of from on small iterables.
make-github-pseudonymous-again Oct 14, 2021
8a73b4c
:package: deps: Relocate deps specific to profiling and benchmarking.
make-github-pseudonymous-again Oct 14, 2021
dc90704
:construction: progress(benchmark): Add fromIterable benchmark.
make-github-pseudonymous-again Oct 14, 2021
2232458
:construction: progress(profiling): Add more profiling loops.
make-github-pseudonymous-again Oct 14, 2021
af7387a
:umbrella: test(concat/append): Prevent regression.
make-github-pseudonymous-again Oct 14, 2021
fee323c
:microscope: test(nodes,from,concat,append,prepend): Increase coverage.
make-github-pseudonymous-again Oct 14, 2021
a7dad80
:test_tube: test: Sketch debug API to avoid private props direct access.
make-github-pseudonymous-again Oct 15, 2021
196675c
:construction: progress(benchmark/fromIterable): Add Array construction.
make-github-pseudonymous-again Oct 1, 2021
2fd09fc
:umbrella: test(append): Prevent regression on append's pureness.
make-github-pseudonymous-again Oct 1, 2021
d299223
:recycle: refactor(profile): Write better code and add analysis script.
make-github-pseudonymous-again Oct 4, 2021
bc858a3
:construction: progress: More benchmarks.
make-github-pseudonymous-again Oct 4, 2021
89f4ab0
:test_tube: test: Do not pull source in fixtures.
make-github-pseudonymous-again Oct 4, 2021
03c005e
:construction: progress: Add code to bench and profile split and iter…
make-github-pseudonymous-again Oct 4, 2021
2c891cf
:microscope: test: Increase coverage.
make-github-pseudonymous-again Oct 15, 2021
7fc67b2
:construction: progress(profile/iterator): Fix timer title.
make-github-pseudonymous-again Oct 15, 2021
a2ee7ff
:construction: progress(benchmark/table): Add filter option.
make-github-pseudonymous-again Oct 14, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions _benchmark/_fixtures.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import fs from 'fs';
import process from 'process';

export function packageInfo(packageName) {
const file = `node_modules/${packageName}/package.json`;
const raw = fs.readFileSync(file);
const json = JSON.parse(raw);
return json;
}

export const load = async (path) => {
const exports = await import(path);
const stats = fs.statSync(path);
const mtime = stats.mtime;
const version = mtime.toISOString();

return {
version,
exports,
};
};

const distPath = (name) => `../dist/index.${name}`;

export const dist = (name) => ({
name,
async load() {
const path = distPath(name);
const {version, exports} = await load(path);
return {
name,
version,
exports,
};
},
});

export const dependency = (name) => ({
name,
async load() {
const path = name;
const exports = await import(path);
const {version} = packageInfo(name);
return {
name,
version,
exports,
};
},
});

export const object = (name, exports) => ({
name,
async load() {
return {
name,
version: process.version,
exports,
};
},
});
32 changes: 10 additions & 22 deletions _benchmark/benchmark.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,20 @@
require('regenerator-runtime/runtime');
import 'regenerator-runtime/runtime.js';

const ArgumentParser = require('argparse').ArgumentParser;
const Benchmark = require('benchmark');
import {ArgumentParser} from 'argparse';
import Benchmark from 'benchmark';

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

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

const fromArray = qiao_fingertree.fromArray;
const empty = fds_finger_tree.empty;
const from = fds_finger_tree.from;
import {FAST_COUNTER as COUNTER} from '../test/src/_fixtures.js';

const COUNTER = {
plus(a, b) {
return a + b;
},
measure(_x) {
return 1;
},
zero() {
return 0;
},
};
const fromArray = qiao_fingertree.fromArray;

const parser = new ArgumentParser();
parser.addArgument(['M']);
const args = parser.parseArgs();
parser.add_argument(['M']);
const args = parser.parse_args();

global.M = args.M;
global.COUNTER = COUNTER;
Expand Down
201 changes: 201 additions & 0 deletions _benchmark/fromIterable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import assert from 'assert';

import 'regenerator-runtime/runtime.js';
import {ArgumentParser} from 'argparse';

import {range} from '@iterable-iterator/range';
import Benchtable from 'benchtable';
import {
FAST_COUNTER as COUNTER,
measure,
measureToString,
iterableToString,
} from '../test/src/_fixtures.js';

import {dist, dependency, object} from './_fixtures.js';

const parser = new ArgumentParser();
parser.add_argument('filter');
const args = parser.parse_args();
const filter = new RegExp(args.filter, 'i');

const cjs = dist('cjs');
const module = dist('module.js');
const modern = dist('modern.js');
const list = dependency('list');
const array = object('Array', Array);

const suite = new Benchtable('Tree Construction', {isTransposed: false});

const add = async (module, fn) => {
if (!filter.test(module.name)) return;
if (!filter.test(fn.name)) return;
const {title, build} = await fn.compile(module);
suite.addFunction(
title,
(measure, iterable) => {
build(measure, iterable);
},
{
maxTime: 5,
},
);
if (!filter.test('measure')) return;
suite.addFunction(
`${title}.measure`,
(measure, iterable, expected) => {
const result = build(measure, iterable).measure();
if (result !== expected) {
throw new Error('wrong measure');
}
},
{
maxTime: 5,
},
);
};

const makeFn = ({name: fnName, build}) => ({
name: fnName,
compile: async (module) => {
const {name, version, exports} = await module.load();
return {
title: `${name} ${version} #${fnName}`,
build: build({exports}),
};
},
});

const from = makeFn({
name: 'from',
build: ({exports}) => {
const from = exports.from;
return (measure, iterable) => from(measure, iterable);
},
});

const append = makeFn({
name: 'append',
build: ({exports}) => {
const empty = exports.empty;
return (measure, iterable) => empty(measure).append(iterable);
},
});

const push = makeFn({
name: 'push',
build: ({exports}) => {
const {empty} = exports;
return (measure, iterable) => {
let l = empty(measure);
for (const x of iterable) l = l.push(x);
return l;
};
},
});

const prepend = makeFn({
name: 'prepend',
build: ({exports}) => {
const empty = exports.empty;
return (measure, iterable) => empty(measure).prepend(iterable);
},
});

const listFrom = makeFn({
name: 'from',
build: ({exports}) => {
const from = exports.from;
return (_measure, iterable) => from(iterable);
},
});

const listAppend = makeFn({
name: 'push',
build: ({exports}) => {
const {empty, append} = exports;
return (_measure, iterable) => {
let l = empty();
for (const x of iterable) l = append(x, l);
return l;
};
},
});

const arrayPush = makeFn({
name: 'push',
build: ({exports}) => {
assert(exports === Array);
return (_measure, iterable) => {
const l = [];
for (const x of iterable) l.push(x);
return l;
};
},
});

await add(cjs, from);
await add(cjs, append);
await add(cjs, prepend);
await add(cjs, push);
await add(module, from);
await add(module, append);
await add(module, prepend);
await add(module, push);
await add(modern, from);
await add(modern, append);
await add(modern, prepend);
await add(modern, push);

await add(list, listFrom);
await add(list, listAppend);
await add(array, listFrom);
await add(array, arrayPush);

const addTitle = (input) => {
const {measure, iterable} = input;
const title = `(${measureToString(measure)}, ${iterableToString(iterable)})`;
return {
...input,
title,
};
};

const addExpected = (input) => {
const expected = measure(input.measure, input.iterable);
return {
...input,
expected,
};
};

const benchmarkInputs = [
{
measure: COUNTER,
iterable: range(1000),
},
{
measure: COUNTER,
iterable: range(10_000),
},
{
measure: COUNTER,
iterable: range(100_000),
},
]
.map(addTitle)
.map(addExpected);

for (const {title, measure, iterable, expected} of benchmarkInputs) {
suite.addInput(title, [measure, iterable, expected]);
}

suite.on('cycle', (evt) => {
console.log(evt.target.name);
});

suite.on('complete', () => {
console.log(suite.table.toString());
});

suite.run();
Loading