Files
core/benchmarks/sharded-snapshot-build-complex.js
T

167 lines
5.0 KiB
JavaScript
Raw Normal View History

import fs from 'node:fs';
import path from 'node:path';
import { CondensedGraph } from '../src/core/CondensedGraph.js';
import { ShardedSnapshotBuilder } from '../src/core/shards/ShardedSnapshotBuilder.js';
function parseArgs(argv) {
const args = new Map();
for (let i = 2; i < argv.length; i++) {
const value = argv[i];
if (!value.startsWith('--')) continue;
const [key, inline] = value.slice(2).split('=');
if (inline !== undefined) {
args.set(key, inline);
continue;
}
const next = argv[i + 1];
if (next && !next.startsWith('--')) {
args.set(key, next);
i++;
} else {
args.set(key, true);
}
}
return args;
}
function makeRng(seed = 1337) {
let state = seed >>> 0;
return () => {
state = (state * 1664525 + 1013904223) >>> 0;
return state / 0xffffffff;
};
}
function makeZipfSampler(count, skew, seed = 1337) {
const weights = new Float64Array(count);
let sum = 0;
for (let i = 1; i <= count; i++) {
const w = 1 / Math.pow(i, skew);
weights[i - 1] = w;
sum += w;
}
const cdf = new Float64Array(count);
let acc = 0;
for (let i = 0; i < count; i++) {
acc += weights[i] / sum;
cdf[i] = acc;
}
let state = seed >>> 0;
const rand = () => {
state = (state * 1664525 + 1013904223) >>> 0;
return state / 0xffffffff;
};
return () => {
const r = rand();
let lo = 0;
let hi = cdf.length - 1;
while (lo < hi) {
const mid = (lo + hi) >> 1;
if (r <= cdf[mid]) {
hi = mid;
} else {
lo = mid + 1;
}
}
return lo;
};
}
const args = parseArgs(process.argv);
const edges = Number(args.get('edges') || 1000000);
const users = Number(args.get('users') || 100000);
const groups = Number(args.get('groups') || 5000);
const docs = Number(args.get('docs') || 500000);
const bucketSize = Number(args.get('bucket') || 4096);
const output = args.get('output') || 'tmp/shards-complex-1m';
const userSkew = Number(args.get('user-skew') || 1.2);
const groupSkew = Number(args.get('group-skew') || 1.1);
const docSkew = Number(args.get('doc-skew') || 1.15);
const directions = args.get('directions')
? String(args.get('directions')).split(',')
: ['out', 'in'];
const shardMode = args.get('shard-mode') || 'range';
const componentRelations = args.get('component-relations')
? String(args.get('component-relations')).split(',')
: null;
const rng = makeRng(42);
console.log('Build complex sharded snapshot');
console.log(` edges: ${edges}`);
console.log(` users: ${users}`);
console.log(` groups: ${groups}`);
console.log(` docs: ${docs}`);
console.log(` bucket: ${bucketSize}`);
console.log(` output: ${output}`);
console.log(` shard mode: ${shardMode}`);
if (componentRelations) {
console.log(` component relations: ${componentRelations.join(',')}`);
}
console.log(` user-skew: ${userSkew}`);
console.log(` group-skew: ${groupSkew}`);
console.log(` doc-skew: ${docSkew}`);
const graph = new CondensedGraph();
const memberEdges = Math.floor(edges * 0.3);
const viewerEdges = Math.floor(edges * 0.3);
const ownerEdges = Math.floor(edges * 0.1);
const riskEdges = Math.floor(edges * 0.2);
let riskLimitEdges = edges - memberEdges - viewerEdges - ownerEdges - riskEdges;
if (riskLimitEdges < 0) riskLimitEdges = 0;
const userSampler = makeZipfSampler(users, userSkew, 7);
const groupSampler = makeZipfSampler(groups, groupSkew, 11);
const docSampler = makeZipfSampler(docs, docSkew, 13);
for (let i = 0; i < memberEdges; i++) {
const userId = userSampler();
const groupId = groupSampler();
graph.addEdge(`user:${userId}`, 'member', `group:${groupId}`);
}
for (let i = 0; i < viewerEdges; i++) {
const groupId = groupSampler();
const docId = docSampler();
graph.addEdge(`group:${groupId}`, 'viewer', `doc:${docId}`);
}
for (let i = 0; i < ownerEdges; i++) {
const userId = userSampler();
const docId = docSampler();
graph.addEdge(`user:${userId}`, 'owner', `doc:${docId}`);
}
for (let i = 0; i < riskEdges; i++) {
const userId = userSampler();
const docId = docSampler();
const value = Math.min(1, Math.max(0, rng()));
graph.addEdge(`user:${userId}`, 'risk', `doc:${docId}`, { value, possibility: 1.0, reliability: 1.0 });
}
for (let i = 0; i < riskLimitEdges; i++) {
const docId = docSampler();
const value = 0.5;
graph.addEdge(`doc:${docId}`, 'risk_limit', `doc:${docId}`, { value, possibility: 1.0, reliability: 1.0 });
}
graph.finalizePerfectHash();
graph.finalizeWaveletAdjacency({ dropAdjacencyList: true });
fs.mkdirSync(output, { recursive: true });
const snapshot = graph.toBinary();
const snapshotPath = path.join(output, 'snapshot.bin');
fs.writeFileSync(snapshotPath, new Uint8Array(snapshot));
console.log(` snapshot MB: ${(snapshot.byteLength / 1024 / 1024).toFixed(2)}`);
const builder = new ShardedSnapshotBuilder({
bucketSize,
includeDirections: directions,
shardMode,
componentRelations
});
const manifest = builder.build(graph, output);
console.log(` shards: ${manifest.shards.length}`);
console.log(` manifest: ${path.join(output, 'manifest.json')}`);