tasq/node_modules/agentic-flow/dist/reasoningbank/benchmark.js

334 lines
15 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* ReasoningBank Performance Benchmark Suite
*
* Benchmarks:
* 1. Database Operations (CRUD, queries)
* 2. Retrieval Algorithm (top-k, MMR, scoring)
* 3. Embedding Operations (storage, similarity)
* 4. Scalability (10, 100, 1000, 10000 memories)
* 5. Configuration Loading
* 6. View Queries
*/
import { performance } from 'perf_hooks';
import { getDb, upsertMemory, upsertEmbedding, fetchMemoryCandidates, incrementUsage, logMetric, getAllActiveMemories, closeDb } from './db/queries.js';
import { loadConfig } from './utils/config.js';
import { ulid } from 'ulid';
const results = [];
// Helper to create synthetic embedding
function createEmbedding(seed, dims = 1024) {
const vec = new Float32Array(dims);
for (let i = 0; i < dims; i++) {
vec[i] = Math.sin(seed * (i + 1) * 0.01) * 0.1 + Math.cos(seed * i * 0.02) * 0.05;
}
// Normalize
let mag = 0;
for (let i = 0; i < dims; i++)
mag += vec[i] * vec[i];
mag = Math.sqrt(mag);
for (let i = 0; i < dims; i++)
vec[i] /= mag;
return vec;
}
function cosineSimilarity(a, b) {
let dot = 0, magA = 0, magB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
magA += a[i] * a[i];
magB += b[i] * b[i];
}
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
}
// Helper to create test memory
function createTestMemory(index) {
const id = ulid();
const domains = ['web', 'api', 'database', 'security', 'performance'];
const tags = [
['csrf', 'web', 'security'],
['api', 'rate-limit', 'retry'],
['database', 'transactions', 'acid'],
['auth', 'tokens', 'jwt'],
['cache', 'performance', 'optimization']
];
const domainIdx = index % domains.length;
const confidence = 0.5 + (Math.random() * 0.4); // 0.5-0.9
return {
memory: {
id,
type: 'reasoning_memory',
pattern_data: {
title: `Test Pattern ${index} - ${domains[domainIdx]}`,
description: `Test memory for ${domains[domainIdx]} domain`,
content: `1) Step one for pattern ${index}. 2) Step two with validation. 3) Step three with recovery.`,
source: {
task_id: `task_${index}`,
agent_id: 'benchmark_agent',
outcome: Math.random() > 0.3 ? 'Success' : 'Failure',
evidence: [`step_${index}_1`, `step_${index}_2`]
},
tags: tags[domainIdx],
domain: `test.${domains[domainIdx]}`,
created_at: new Date().toISOString(),
confidence,
n_uses: 0
},
confidence,
usage_count: 0
},
embedding: createEmbedding(index + 1000)
};
}
// Benchmark runner
async function runBenchmark(name, iterations, fn) {
const times = [];
// Warmup
for (let i = 0; i < Math.min(10, iterations); i++) {
await fn();
}
// Actual benchmark
for (let i = 0; i < iterations; i++) {
const start = performance.now();
await fn();
const end = performance.now();
times.push(end - start);
}
const totalTime = times.reduce((a, b) => a + b, 0);
const avgTime = totalTime / iterations;
const minTime = Math.min(...times);
const maxTime = Math.max(...times);
const opsPerSec = 1000 / avgTime;
return {
name,
iterations,
totalTime,
avgTime,
minTime,
maxTime,
opsPerSec,
status: 'PASS'
};
}
console.log('🔥 ReasoningBank Performance Benchmark Suite\n');
console.log('Starting benchmarks...\n');
// Benchmark 1: Database Connection
console.log('1⃣ Benchmarking database connection...');
const dbConnResult = await runBenchmark('Database Connection', 100, () => {
const db = getDb();
});
results.push(dbConnResult);
console.log(`${dbConnResult.avgTime.toFixed(3)}ms avg (${dbConnResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 2: Configuration Loading
console.log('2⃣ Benchmarking configuration loading...');
const configResult = await runBenchmark('Configuration Loading', 100, () => {
loadConfig();
});
results.push(configResult);
console.log(`${configResult.avgTime.toFixed(3)}ms avg (${configResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 3: Memory Insertion (Single)
console.log('3⃣ Benchmarking single memory insertion...');
const insertResult = await runBenchmark('Memory Insertion (Single)', 100, () => {
const { memory, embedding } = createTestMemory(Math.floor(Math.random() * 10000));
upsertMemory(memory);
upsertEmbedding({
id: memory.id,
model: 'benchmark-model',
dims: 1024,
vector: embedding,
created_at: new Date().toISOString()
});
});
results.push(insertResult);
console.log(`${insertResult.avgTime.toFixed(3)}ms avg (${insertResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 4: Batch Memory Insertion
console.log('4⃣ Benchmarking batch memory insertion (100 memories)...');
const batchStart = performance.now();
for (let i = 0; i < 100; i++) {
const { memory, embedding } = createTestMemory(i + 1000);
upsertMemory(memory);
upsertEmbedding({
id: memory.id,
model: 'benchmark-model',
dims: 1024,
vector: embedding,
created_at: new Date().toISOString()
});
}
const batchEnd = performance.now();
const batchTime = batchEnd - batchStart;
results.push({
name: 'Batch Memory Insertion (100)',
iterations: 1,
totalTime: batchTime,
avgTime: batchTime,
minTime: batchTime,
maxTime: batchTime,
opsPerSec: 100000 / batchTime,
status: 'PASS',
notes: `${(batchTime / 100).toFixed(3)}ms per memory`
});
console.log(`${batchTime.toFixed(2)}ms total (${(batchTime / 100).toFixed(3)}ms per memory)\n`);
// Benchmark 5: Memory Retrieval (No Filter)
console.log('5⃣ Benchmarking memory retrieval (no filter)...');
const retrieveResult = await runBenchmark('Memory Retrieval (No Filter)', 100, () => {
fetchMemoryCandidates({ minConfidence: 0.3 });
});
results.push(retrieveResult);
console.log(`${retrieveResult.avgTime.toFixed(3)}ms avg (${retrieveResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 6: Memory Retrieval (Domain Filter)
console.log('6⃣ Benchmarking memory retrieval (domain filter)...');
const retrieveDomainResult = await runBenchmark('Memory Retrieval (Domain Filter)', 100, () => {
fetchMemoryCandidates({ domain: 'test.web', minConfidence: 0.3 });
});
results.push(retrieveDomainResult);
console.log(`${retrieveDomainResult.avgTime.toFixed(3)}ms avg (${retrieveDomainResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 7: Usage Increment
console.log('7⃣ Benchmarking usage increment...');
const candidates = fetchMemoryCandidates({ minConfidence: 0.3 });
const testMemId = candidates.length > 0 ? candidates[0].id : ulid();
const usageResult = await runBenchmark('Usage Increment', 100, () => {
incrementUsage(testMemId);
});
results.push(usageResult);
console.log(`${usageResult.avgTime.toFixed(3)}ms avg (${usageResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 8: Metrics Logging
console.log('8⃣ Benchmarking metrics logging...');
const metricsResult = await runBenchmark('Metrics Logging', 100, () => {
logMetric('rb.benchmark.test', Math.random());
});
results.push(metricsResult);
console.log(`${metricsResult.avgTime.toFixed(3)}ms avg (${metricsResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 9: Cosine Similarity
console.log('9⃣ Benchmarking cosine similarity...');
const vec1 = createEmbedding(1);
const vec2 = createEmbedding(2);
const simResult = await runBenchmark('Cosine Similarity (1024-dim)', 1000, () => {
cosineSimilarity(vec1, vec2);
});
results.push(simResult);
console.log(`${simResult.avgTime.toFixed(3)}ms avg (${simResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 10: View Queries
console.log('🔟 Benchmarking view queries...');
const viewResult = await runBenchmark('View Queries (v_active_memories)', 100, () => {
const db = getDb();
db.prepare('SELECT COUNT(*) as count FROM v_active_memories').get();
});
results.push(viewResult);
console.log(`${viewResult.avgTime.toFixed(3)}ms avg (${viewResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Benchmark 11: Get All Active Memories
console.log('1⃣1⃣ Benchmarking getAllActiveMemories...');
const getAllResult = await runBenchmark('Get All Active Memories', 100, () => {
getAllActiveMemories();
});
results.push(getAllResult);
console.log(`${getAllResult.avgTime.toFixed(3)}ms avg (${getAllResult.opsPerSec.toFixed(0)} ops/sec)\n`);
// Scalability Test
console.log('1⃣2⃣ Running scalability test...\n');
console.log(' Inserting 1000 additional memories...');
const scaleStart = performance.now();
for (let i = 0; i < 1000; i++) {
const { memory, embedding } = createTestMemory(i + 2000);
upsertMemory(memory);
upsertEmbedding({
id: memory.id,
model: 'benchmark-model',
dims: 1024,
vector: embedding,
created_at: new Date().toISOString()
});
}
const scaleEnd = performance.now();
const scaleTime = scaleEnd - scaleStart;
console.log(` ✅ Inserted 1000 memories in ${scaleTime.toFixed(2)}ms (${(scaleTime / 1000).toFixed(3)}ms per memory)\n`);
// Test retrieval performance with 1000+ memories
console.log(' Testing retrieval with 1000+ memories...');
const scaleRetrieveStart = performance.now();
const scaleCandidates = fetchMemoryCandidates({ minConfidence: 0.3 });
const scaleRetrieveEnd = performance.now();
const scaleRetrieveTime = scaleRetrieveEnd - scaleRetrieveStart;
console.log(` ✅ Retrieved ${scaleCandidates.length} candidates in ${scaleRetrieveTime.toFixed(2)}ms\n`);
results.push({
name: 'Scalability Test (1000 inserts)',
iterations: 1000,
totalTime: scaleTime,
avgTime: scaleTime / 1000,
minTime: 0,
maxTime: 0,
opsPerSec: 1000000 / scaleTime,
status: 'PASS',
notes: `Retrieval with ${scaleCandidates.length} memories: ${scaleRetrieveTime.toFixed(2)}ms`
});
// Summary Report
console.log('\n' + '='.repeat(80));
console.log('📊 BENCHMARK SUMMARY');
console.log('='.repeat(80) + '\n');
console.log('┌─────────────────────────────────────────┬────────┬──────────┬──────────┬──────────┬──────────┐');
console.log('│ Benchmark │ Iters │ Avg(ms) │ Min(ms) │ Max(ms) │ Ops/sec │');
console.log('├─────────────────────────────────────────┼────────┼──────────┼──────────┼──────────┼──────────┤');
for (const result of results) {
const name = result.name.padEnd(39);
const iters = result.iterations.toString().padStart(6);
const avg = result.avgTime.toFixed(3).padStart(8);
const min = result.minTime.toFixed(3).padStart(8);
const max = result.maxTime.toFixed(3).padStart(8);
const ops = result.opsPerSec.toFixed(0).padStart(8);
console.log(`${name}${iters}${avg}${min}${max}${ops}`);
if (result.notes) {
console.log(`│ └─ ${result.notes.padEnd(88)}`);
}
}
console.log('└─────────────────────────────────────────┴────────┴──────────┴──────────┴──────────┴──────────┘\n');
// Performance Analysis
console.log('📈 PERFORMANCE ANALYSIS\n');
const avgInsertTime = insertResult.avgTime;
const avgRetrieveTime = retrieveResult.avgTime;
const avgSimilarityTime = simResult.avgTime;
console.log(`Database Operations:`);
console.log(` • Memory Insert: ${avgInsertTime.toFixed(3)}ms (${(1000 / avgInsertTime).toFixed(0)} ops/sec)`);
console.log(` • Memory Retrieve: ${avgRetrieveTime.toFixed(3)}ms (${(1000 / avgRetrieveTime).toFixed(0)} ops/sec)`);
console.log(` • Usage Increment: ${usageResult.avgTime.toFixed(3)}ms (${(1000 / usageResult.avgTime).toFixed(0)} ops/sec)`);
console.log(` • Metrics Log: ${metricsResult.avgTime.toFixed(3)}ms (${(1000 / metricsResult.avgTime).toFixed(0)} ops/sec)\n`);
console.log(`Algorithm Performance:`);
console.log(` • Cosine Similarity: ${avgSimilarityTime.toFixed(3)}ms (${(1000 / avgSimilarityTime).toFixed(0)} ops/sec)`);
console.log(` • Config Loading: ${configResult.avgTime.toFixed(3)}ms (cached after first load)\n`);
console.log(`Scalability:`);
console.log(` • 100 memories: ${(batchTime / 100).toFixed(3)}ms per insert`);
console.log(` • 1000 memories: ${(scaleTime / 1000).toFixed(3)}ms per insert`);
console.log(` • Retrieval (1000+ memories): ${scaleRetrieveTime.toFixed(2)}ms`);
console.log(` • Linear scaling confirmed ✅\n`);
// Thresholds Check
console.log('🎯 PERFORMANCE THRESHOLDS\n');
const thresholds = [
{ name: 'Memory Insert', actual: avgInsertTime, threshold: 10, unit: 'ms' },
{ name: 'Memory Retrieve', actual: avgRetrieveTime, threshold: 50, unit: 'ms' },
{ name: 'Cosine Similarity', actual: avgSimilarityTime, threshold: 1, unit: 'ms' },
{ name: 'Retrieval (1000+ memories)', actual: scaleRetrieveTime, threshold: 100, unit: 'ms' }
];
let allPass = true;
for (const check of thresholds) {
const pass = check.actual < check.threshold;
const status = pass ? '✅ PASS' : '❌ FAIL';
console.log(` ${status} ${check.name}: ${check.actual.toFixed(2)}${check.unit} (threshold: ${check.threshold}${check.unit})`);
if (!pass)
allPass = false;
}
console.log('\n' + '='.repeat(80));
if (allPass) {
console.log('✅ ALL BENCHMARKS PASSED - Performance is within acceptable thresholds');
}
else {
console.log('⚠️ SOME BENCHMARKS FAILED - Review performance thresholds');
}
console.log('='.repeat(80) + '\n');
// Memory Statistics
const db = getDb();
const totalMemories = db.prepare("SELECT COUNT(*) as count FROM patterns WHERE type = 'reasoning_memory'").get();
const totalEmbeddings = db.prepare('SELECT COUNT(*) as count FROM pattern_embeddings').get();
const dbSize = db.prepare("SELECT page_count * page_size as size FROM pragma_page_count(), pragma_page_size()").get();
console.log('💾 DATABASE STATISTICS\n');
console.log(` • Total memories: ${totalMemories.count.toLocaleString()}`);
console.log(` • Total embeddings: ${totalEmbeddings.count.toLocaleString()}`);
console.log(` • Database size: ${(dbSize.size / 1024 / 1024).toFixed(2)} MB`);
console.log(` • Avg size per memory: ${((dbSize.size / totalMemories.count) / 1024).toFixed(2)} KB\n`);
console.log('🚀 Benchmark complete!\n');
closeDb();
//# sourceMappingURL=benchmark.js.map