add radix tree benchmark
This commit is contained in:
parent
fe978c5b41
commit
a839d69c0e
2 changed files with 63 additions and 23 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
import createTree from "functional-red-black-tree";
|
import createTree from "functional-red-black-tree";
|
||||||
|
import { emptyTrie, insert } from "../lib/util/trie.js";
|
||||||
|
|
||||||
function benchmark(N) {
|
function benchmark(N) {
|
||||||
// fastest
|
// in-place update of native Map: fastest
|
||||||
function map() {
|
function map() {
|
||||||
let t = new Map();
|
let t = new Map();
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
@ -11,10 +12,10 @@ function benchmark(N) {
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
return endTime - startTime;
|
return endTime - startTime;
|
||||||
}
|
}
|
||||||
const durInPlace = map();
|
const durInPlace = (N <= 5000000) ? map() : "(skip)";
|
||||||
console.log("in-place:", durInPlace, "ms");
|
console.log("in-place:", durInPlace, "ms");
|
||||||
|
|
||||||
// slower by constant factor
|
// purely functional red-black tree: slower by constant factor
|
||||||
function fun() {
|
function fun() {
|
||||||
let t = createTree();
|
let t = createTree();
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
@ -25,25 +26,55 @@ function benchmark(N) {
|
||||||
return endTime - startTime;
|
return endTime - startTime;
|
||||||
}
|
}
|
||||||
const durFunc = fun();
|
const durFunc = fun();
|
||||||
console.log("functional:", durFunc, "ms");
|
console.log("functional red-black:", durFunc, "ms");
|
||||||
|
|
||||||
// a bit slower still
|
// purely functional red-black tree (no garbage collection): a bit slower still
|
||||||
function funNoGC() {
|
function funNoGC() {
|
||||||
const old = new Array(N);
|
const trees = new Array(N);
|
||||||
let t = createTree();
|
let t = createTree();
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
for (let i=0; i<N; ++i) {
|
for (let i=0; i<N; ++i) {
|
||||||
old[i] = t; // prevent garbage collection
|
trees[i] = t; // prevent garbage collection
|
||||||
t = t.insert(Math.random(), Math.random());
|
t = t.insert(Math.random(), Math.random());
|
||||||
}
|
}
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
return endTime - startTime;
|
return endTime - startTime;
|
||||||
|
|
||||||
}
|
}
|
||||||
const durFuncNoGC = (N <= 1000000) ? funNoGC() : "";
|
const durFuncNoGC = (N <= 1000000) ? funNoGC() : "(skip)";
|
||||||
console.log("functional (no GC):", durFuncNoGC, "ms");
|
console.log("functional red-black (no GC):", durFuncNoGC, "ms");
|
||||||
|
|
||||||
// slowest (won't scale)
|
// 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() {
|
function copying() {
|
||||||
let t = new Map();
|
let t = new Map();
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
@ -54,35 +85,44 @@ function benchmark(N) {
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
return endTime - startTime;
|
return endTime - startTime;
|
||||||
}
|
}
|
||||||
const durCopying = (N <= 50000) ? copying() : "";
|
const durCopying = (N <= 10000) ? copying() : "(skip)";
|
||||||
console.log("copying:", durCopying, "ms");
|
console.log("copying:", durCopying, "ms");
|
||||||
|
|
||||||
// slower than slowest
|
// defensive copy of native Map (no garbage collection): slower than slowest
|
||||||
function copyingNoGC() {
|
function copyingNoGC() {
|
||||||
const old = new Array(N);
|
const maps = new Array(N);
|
||||||
let t = new Map();
|
let t = new Map();
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
for (let i=0; i<N; ++i) {
|
for (let i=0; i<N; ++i) {
|
||||||
old[i] = t; // prevent garbage collection
|
maps[i] = t; // prevent garbage collection
|
||||||
t = new Map(t);
|
t = new Map(t);
|
||||||
t.set(Math.random(), Math.random());
|
t.set(Math.random(), Math.random());
|
||||||
}
|
}
|
||||||
const endTime = Date.now();
|
const endTime = Date.now();
|
||||||
return endTime - startTime;
|
return endTime - startTime;
|
||||||
}
|
}
|
||||||
const durCopyingNoGC = (N <= 10000) ? copyingNoGC() : "";
|
const durCopyingNoGC = (N <= 10000) ? copyingNoGC() : "(skip)";
|
||||||
console.log("copying (no GC):", durCopyingNoGC, "ms");
|
console.log("copying (no GC):", durCopyingNoGC, "ms");
|
||||||
|
|
||||||
return [N, durInPlace, durFunc, durFuncNoGC, durCopying, durCopyingNoGC];
|
return [N, durInPlace, durFunc, durFuncNoGC, durTrie, durTrieNoGC, durCopying, durCopyingNoGC];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
for (const N of [100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000]) {
|
const datapoints = [100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000];
|
||||||
console.log("N =", N);
|
|
||||||
|
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));
|
results.push(benchmark(N));
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("N;in-place;functional;functional-NoGC;copying;copying-NoGC");
|
const endTime = Date.now();
|
||||||
for (const [N, durInPlace, durFunc, durFuncNoGC, durCopying, durCopyingNoGC] of results) {
|
|
||||||
console.log(`${N};${durInPlace};${durFunc};${durFuncNoGC};${durCopying};${durCopyingNoGC}`);
|
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(';')}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// A purely functional Trie
|
// A purely functional Radix Trie
|
||||||
// https://en.wikipedia.org/wiki/Trie
|
// https://en.wikipedia.org/wiki/Radix_tree
|
||||||
|
|
||||||
|
|
||||||
export const emptyTrie = {
|
export const emptyTrie = {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue