dope2/benchmarks/rbtree_bench.js

128 lines
4 KiB
JavaScript

import createTree from "functional-red-black-tree";
import { emptyTrie, insert } from "../lib/util/trie.js";
function benchmark(N) {
// in-place update of native Map: fastest
function map() {
let t = new Map();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
t.set(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durInPlace = (N <= 5000000) ? map() : "(skip)";
console.log("in-place:", durInPlace, "ms");
// purely functional red-black tree: slower by constant factor
function fun() {
let t = createTree();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
t = t.insert(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durFunc = fun();
console.log("functional red-black:", durFunc, "ms");
// purely functional red-black tree (no garbage collection): a bit slower still
function funNoGC() {
const trees = new Array(N);
let t = createTree();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
trees[i] = t; // prevent garbage collection
t = t.insert(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durFuncNoGC = (N <= 1000000) ? funNoGC() : "(skip)";
console.log("functional red-black (no GC):", durFuncNoGC, "ms");
// purely functional radix tree
function trie() {
let t = emptyTrie;
const startTime = Date.now();
for (let i=0; i<N; ++i) {
// of course we can only insert strings into radix tree:
t = insert(t)(String(Math.random()*10))(Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durTrie = trie();
console.log("functional radix trie:", durTrie, "ms");
// purely functional radix tree (no garbage collection)
function trieNoGC() {
const trees = new Array(N);
let t = emptyTrie;
const startTime = Date.now();
for (let i=0; i<N; ++i) {
trees[i] = t; // prevent garbage collection
// of course we can only insert strings into radix tree:
t = insert(t)(String(Math.random()*10))(Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durTrieNoGC = (N <= 1000000) ? trieNoGC() : "(skip)";
console.log("functional radix trie (no GC):", durTrieNoGC, "ms");
// defensive copy of native Map: slowest (won't scale)
function copying() {
let t = new Map();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
t = new Map(t);
t.set(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durCopying = (N <= 10000) ? copying() : "(skip)";
console.log("copying:", durCopying, "ms");
// defensive copy of native Map (no garbage collection): slower than slowest
function copyingNoGC() {
const maps = new Array(N);
let t = new Map();
const startTime = Date.now();
for (let i=0; i<N; ++i) {
maps[i] = t; // prevent garbage collection
t = new Map(t);
t.set(Math.random(), Math.random());
}
const endTime = Date.now();
return endTime - startTime;
}
const durCopyingNoGC = (N <= 10000) ? copyingNoGC() : "(skip)";
console.log("copying (no GC):", durCopyingNoGC, "ms");
return [N, durInPlace, durFunc, durFuncNoGC, durTrie, durTrieNoGC, durCopying, durCopyingNoGC];
}
const startTime = Date.now();
const results = [];
const datapoints = [100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000];
for (let i=0; i<datapoints.length; i++) {
const N = datapoints[i];
console.log("N =", N, `(run ${i+1}/${datapoints.length})`);
results.push(benchmark(N));
}
const endTime = Date.now();
console.log("Benchmark took", endTime-startTime, "ms");
console.log("N;in-place;pure-redblack;pure-redblack-NoGC;pure-radix;pure-radix-NoGC;copying;copying-NoGC");
for (const [N, ...rest] of results) {
console.log(`${N};${rest.join(';')}`);
}