717ae1031e
Zanzibar-style authorization graph engine (direct/chain/TTU/defeasible/ binary modes, condensed snapshots, value relations) with 39 rigor test campaigns. Includes fixes for snapshot binary writer/reader format mismatch (snapshot-of-snapshot corruption), possibility write-boundary validation, empty-graph snapshot serialization, relation lookup cache direction collision, config-redefinition cache invalidation, binary threshold semantics, defeasible compiled routing, and comparator reason whitelisting.
104 lines
3.1 KiB
JavaScript
104 lines
3.1 KiB
JavaScript
import fs from 'node:fs';
|
|
|
|
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 parseCsv(content) {
|
|
const lines = content.split('\n').map(line => line.trim()).filter(Boolean);
|
|
const data = [];
|
|
for (const line of lines) {
|
|
if (line.startsWith('b2c_auth_bench')) continue;
|
|
if (line.startsWith('scenario,')) continue;
|
|
const parts = line.split(',');
|
|
if (parts.length < 11) continue;
|
|
const [scenario, nodes, edges, buildMs, authMs, authQps, precision, recall, f1, p95, p99] = parts;
|
|
data.push({
|
|
scenario,
|
|
nodes: Number(nodes),
|
|
edges: Number(edges),
|
|
buildMs: Number(buildMs),
|
|
authMs: Number(authMs),
|
|
authQps: Number(authQps),
|
|
precision: Number(precision),
|
|
recall: Number(recall),
|
|
f1: Number(f1),
|
|
p95: Number(p95),
|
|
p99: Number(p99)
|
|
});
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function fitPowerLaw(points, field) {
|
|
const samples = points.filter(point => point[field] > 0 && point.nodes > 0);
|
|
if (samples.length < 2) return null;
|
|
const xs = samples.map(point => Math.log(point.nodes));
|
|
const ys = samples.map(point => Math.log(point[field]));
|
|
const n = xs.length;
|
|
const sumX = xs.reduce((acc, value) => acc + value, 0);
|
|
const sumY = ys.reduce((acc, value) => acc + value, 0);
|
|
const sumXY = xs.reduce((acc, value, index) => acc + value * ys[index], 0);
|
|
const sumX2 = xs.reduce((acc, value) => acc + value * value, 0);
|
|
const denom = n * sumX2 - sumX * sumX;
|
|
if (denom === 0) return null;
|
|
const slope = (n * sumXY - sumX * sumY) / denom;
|
|
const intercept = (sumY - slope * sumX) / n;
|
|
return { slope, intercept };
|
|
}
|
|
|
|
function predictPowerLaw(model, nodes) {
|
|
return Math.exp(model.intercept + model.slope * Math.log(nodes));
|
|
}
|
|
|
|
const args = parseArgs(process.argv);
|
|
const inputPath = args.get('input') || 'new-eval/b2c-auth-bench-output.txt';
|
|
const content = fs.readFileSync(inputPath, 'utf8');
|
|
const data = parseCsv(content);
|
|
const targetNodes = Number(args.get('target') || 1_000_000);
|
|
|
|
const grouped = new Map();
|
|
for (const row of data) {
|
|
if (!grouped.has(row.scenario)) {
|
|
grouped.set(row.scenario, []);
|
|
}
|
|
grouped.get(row.scenario).push(row);
|
|
}
|
|
|
|
const metrics = ['edges', 'buildMs', 'authMs', 'authQps', 'p95', 'p99'];
|
|
console.log('b2c_auth_fit');
|
|
console.log(`target_nodes=${targetNodes}`);
|
|
console.log('scenario,metric,model,predicted');
|
|
|
|
for (const [scenario, points] of grouped.entries()) {
|
|
for (const metric of metrics) {
|
|
const model = fitPowerLaw(points, metric);
|
|
if (!model) continue;
|
|
const predicted = predictPowerLaw(model, targetNodes);
|
|
const modelLabel = `${Math.exp(model.intercept).toFixed(6)} * n^${model.slope.toFixed(3)}`;
|
|
console.log([
|
|
scenario,
|
|
metric,
|
|
modelLabel,
|
|
predicted.toFixed(3)
|
|
].join(','));
|
|
}
|
|
}
|