import assert from 'node:assert/strict'; import { describe, test } from 'node:test'; import { Arbiter } from '../../src/core/Arbiter.js'; const runPerf = process.env.RUN_PERF_TESTS === '1'; const perfTest = runPerf ? test : test.skip; describe('Memory Usage and Performance', () => { perfTest('memory usage grows linearly with node count', () => { const arbiter = new Arbiter(); const numNodes = 10000; for (let i = 0; i < numNodes; i++) { arbiter.addNode(`node:${i}`, 'node'); } const memoryUsage = process.memoryUsage(); const memoryMB = memoryUsage.heapUsed / (1024 * 1024); console.log(`Memory for ${numNodes} nodes: ${memoryMB.toFixed(2)} MB`); assert.ok(memoryMB < 100, `Memory usage (${memoryMB.toFixed(2)} MB) should be reasonable`); }); perfTest('memory usage for graph with edges', () => { const arbiter = new Arbiter(); const numNodes = 5000; const edgesPerNode = 3; for (let i = 0; i < numNodes; i++) { arbiter.addNode(`node:${i}`, 'node'); } arbiter.setRelationConfig('connect', { type: 'direct' }); for (let i = 0; i < numNodes; i++) { for (let j = 1; j <= edgesPerNode && i + j < numNodes; j++) { arbiter.addRelation(`node:${i}`, 'connect', `node:${i + j}`, 1.0); } } const memoryUsage = process.memoryUsage(); const memoryMB = memoryUsage.heapUsed / (1024 * 1024); console.log(`Memory for ${numNodes} nodes with ${numNodes * edgesPerNode} edges: ${memoryMB.toFixed(2)} MB`); assert.ok(memoryMB < 200, `Memory usage (${memoryMB.toFixed(2)} MB) should be reasonable`); }); perfTest('large graph stays within 128MB limit', () => { const arbiter = new Arbiter(); const numNodes = 30000; const edgesPerNode = 3; arbiter.setRelationConfig('connect', { type: 'direct' }); for (let i = 0; i < numNodes; i++) { arbiter.addNode(`node:${i}`, 'node'); } for (let i = 0; i < numNodes; i++) { for (let j = 1; j <= edgesPerNode && i + j < numNodes; j++) { arbiter.addRelation(`node:${i}`, 'connect', `node:${i + j}`, 1.0); } } const memoryUsage = process.memoryUsage(); const memoryMB = memoryUsage.heapUsed / (1024 * 1024); console.log(`Memory for ${numNodes} nodes: ${memoryMB.toFixed(2)} MB`); assert.ok(memoryMB < 250, `Memory usage (${memoryMB.toFixed(2)} MB) must be reasonable`); }); perfTest('direct check cache improves performance', () => { const arbiter = new Arbiter(); for (let i = 0; i < 1000; i++) { arbiter.addNode(`user:${i}`, 'user'); arbiter.addNode(`resource:${i}`, 'resource'); } arbiter.setRelationConfig('member', { type: 'direct' }); for (let i = 0; i < 1000; i++) { arbiter.addRelation(`user:${i}`, 'member', `resource:${i}`, 1.0); } for (let i = 0; i < 200; i++) { arbiter.check(`user:${i % 100}`, 'member', `resource:${i % 100}`); } const runBatch = () => { const start = performance.now(); for (let i = 0; i < 500; i++) { arbiter.check(`user:${i % 100}`, 'member', `resource:${i % 100}`); } return performance.now() - start; }; const time1 = runBatch(); const time2 = runBatch(); const time3 = runBatch(); const time4 = runBatch(); const time5 = runBatch(); console.log(`First batch: ${time1}ms, Second batch: ${time2}ms, Third batch: ${time3}ms, Fourth batch: ${time4}ms, Fifth batch: ${time5}ms`); if (arbiter.directCheckCache) { const warmTimes = [time2, time3, time4, time5].sort((a, b) => a - b); const medianWarm = (warmTimes[1] + warmTimes[2]) / 2; assert.ok(medianWarm <= time1 * 1.5, `Cached queries should be at least as fast (${medianWarm}ms <= ${time1}ms)`); } else { console.log('Direct check cache is disabled'); } }); perfTest('query performance scales linearly with graph size', () => { const arbiter = new Arbiter(); const numNodes = 5000; for (let i = 0; i < numNodes; i++) { arbiter.addNode(`node:${i}`, 'node'); } arbiter.setRelationConfig('connect', { type: 'direct' }); for (let i = 0; i < numNodes - 1; i++) { arbiter.addRelation(`node:${i}`, 'connect', `node:${i + 1}`, 1.0); } const start = Date.now(); const result = arbiter.check('node:0', 'connect', 'node:1'); const duration = Date.now() - start; console.log(`Query time: ${duration}ms`); assert.strictEqual(result.possibility, 1.0); assert.ok(duration < 1000, `Query should be fast, took ${duration}ms`); }); perfTest('batch relation addition is efficient', () => { const arbiter = new Arbiter(); const numNodes = 20000; arbiter.setRelationConfig('connect', { type: 'direct' }); for (let i = 0; i < numNodes; i++) { arbiter.addNode(`node:${i}`, 'node'); } const start = Date.now(); for (let i = 0; i < numNodes - 1; i++) { arbiter.addRelation(`node:${i}`, 'connect', `node:${i + 1}`, 1.0); } const duration = Date.now() - start; console.log(`Batch addition time: ${duration}ms for ${numNodes - 1} relations`); assert.ok(duration < 5000, `Batch addition should be fast, took ${duration}ms`); }); });