2025-09-11 16:23:32 -07:00
#!/usr/bin/env node
/ * *
* Performance Profiling - Measure actual performance of each API method
* This will help us identify where we lost the claimed 500 , 000 ops / sec
* /
2025-09-30 17:09:15 -07:00
import { Brainy } from '../../dist/index.js'
import { MemoryStorage } from '../../dist/storage/adapters/memoryStorage.js'
2025-09-11 16:23:32 -07:00
// Performance tracking
class PerformanceProfiler {
constructor ( ) {
this . results = { }
}
async measure ( name , fn , iterations = 100 ) {
// Warmup
for ( let i = 0 ; i < 10 ; i ++ ) {
await fn ( )
}
// Measure
const start = performance . now ( )
for ( let i = 0 ; i < iterations ; i ++ ) {
await fn ( )
}
const end = performance . now ( )
const totalMs = end - start
const perOpMs = totalMs / iterations
const opsPerSec = Math . round ( 1000 / perOpMs )
this . results [ name ] = {
totalMs ,
perOpMs ,
opsPerSec ,
iterations
}
return { perOpMs , opsPerSec }
}
report ( ) {
console . log ( '\n📊 Performance Profile Results\n' )
console . log ( 'Method | ms/op | ops/sec | Status' )
console . log ( '--------------------------------|--------|---------|--------' )
for ( const [ name , stats ] of Object . entries ( this . results ) ) {
const status = stats . opsPerSec > 10000 ? '✅' :
stats . opsPerSec > 1000 ? '⚡' : '🐌'
console . log (
` ${ name . padEnd ( 31 ) } | ${ stats . perOpMs . toFixed ( 2 ) . padStart ( 6 ) } | ${
stats . opsPerSec . toString ( ) . padStart ( 7 )
} | $ { status } `
)
}
// Find bottlenecks
console . log ( '\n🔍 Bottleneck Analysis\n' )
const sorted = Object . entries ( this . results )
. sort ( ( a , b ) => b [ 1 ] . perOpMs - a [ 1 ] . perOpMs )
. slice ( 0 , 5 )
console . log ( 'Slowest Operations:' )
for ( const [ name , stats ] of sorted ) {
console . log ( ` ${ name } : ${ stats . perOpMs . toFixed ( 2 ) } ms per operation ` )
}
}
}
async function profilePerformance ( ) {
console . log ( '🚀 Starting Performance Profile\n' )
const profiler = new PerformanceProfiler ( )
// Initialize Brainy with different configurations
console . log ( 'Initializing Brainy configurations...' )
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
// 1. Minimal config
2025-09-30 17:09:15 -07:00
const minimalBrain = new Brainy ( {
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
storage : new MemoryStorage ( )
2025-09-11 16:23:32 -07:00
} )
await minimalBrain . init ( )
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
// 2. Default config
2025-09-30 17:09:15 -07:00
const defaultBrain = new Brainy ( {
2025-09-11 16:23:32 -07:00
storage : new MemoryStorage ( )
} )
await defaultBrain . init ( )
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
// 3. Full config
2025-09-30 17:09:15 -07:00
const fullBrain = new Brainy ( {
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
storage : new MemoryStorage ( )
2025-09-11 16:23:32 -07:00
} )
await fullBrain . init ( )
console . log ( '✅ All configurations initialized\n' )
// Prepare test data
const testNoun = {
content : 'Test document with some content for searching' ,
title : 'Test Document' ,
tags : [ 'test' , 'performance' , 'benchmark' ]
}
const testMetadata = {
category : 'benchmark' ,
priority : 1
}
// Store some initial data for search/retrieve tests
const setupIds = [ ]
for ( let i = 0 ; i < 100 ; i ++ ) {
const id = await defaultBrain . addNoun (
{ ... testNoun , index : i } ,
'document' ,
{ ... testMetadata , index : i }
)
setupIds . push ( id )
}
console . log ( '📝 Testing Core CRUD Operations\n' )
// Test 1: addNoun performance
let nounCounter = 0
await profiler . measure ( 'addNoun (minimal)' , async ( ) => {
await minimalBrain . addNoun (
{ ... testNoun , id : ` perf_min_ ${ nounCounter ++ } ` } ,
'document' ,
testMetadata
)
} , 100 )
nounCounter = 0
await profiler . measure ( 'addNoun (default)' , async ( ) => {
await defaultBrain . addNoun (
{ ... testNoun , id : ` perf_def_ ${ nounCounter ++ } ` } ,
'document' ,
testMetadata
)
} , 100 )
nounCounter = 0
await profiler . measure ( 'addNoun (full aug)' , async ( ) => {
await fullBrain . addNoun (
{ ... testNoun , id : ` perf_full_ ${ nounCounter ++ } ` } ,
'document' ,
testMetadata
)
} , 100 )
// Test 2: getNoun performance
await profiler . measure ( 'getNoun (default)' , async ( ) => {
await defaultBrain . getNoun ( setupIds [ Math . floor ( Math . random ( ) * setupIds . length ) ] )
} , 1000 )
// Test 3: Search performance
await profiler . measure ( 'searchText (default)' , async ( ) => {
await defaultBrain . searchText ( 'test document' , 10 )
} , 100 )
// Test 4: findSimilar performance
await profiler . measure ( 'findSimilar (default)' , async ( ) => {
await defaultBrain . findSimilar ( setupIds [ 0 ] , 10 )
} , 100 )
// Test 5: Verb operations
let verbCounter = 0
await profiler . measure ( 'addVerb (default)' , async ( ) => {
const source = setupIds [ verbCounter % setupIds . length ]
const target = setupIds [ ( verbCounter + 1 ) % setupIds . length ]
await defaultBrain . addVerb ( {
source ,
target ,
type : 'RelatedTo' ,
weight : Math . random ( )
} )
verbCounter ++
} , 100 )
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
console . log ( '\n🔧 Testing Operation Overhead\n' )
2025-09-11 16:23:32 -07:00
// Measure raw storage performance
const storage = new MemoryStorage ( )
await storage . init ( )
let storageCounter = 0
await profiler . measure ( 'Raw storage.saveNoun' , async ( ) => {
await storage . saveNoun ( {
id : ` storage_ ${ storageCounter ++ } ` ,
vector : new Array ( 384 ) . fill ( 0 ) ,
connections : new Map ( ) ,
level : 0
} )
} , 1000 )
await profiler . measure ( 'Raw storage.getNoun' , async ( ) => {
await storage . getNoun ( ` storage_ ${ Math . floor ( Math . random ( ) * storageCounter ) } ` )
} , 1000 )
console . log ( '\n🧠 Testing Embedding Performance\n' )
// Test embedding generation (this is likely the bottleneck)
const embeddingFunction = defaultBrain . getEmbeddingFunction ( )
await profiler . measure ( 'Embedding generation' , async ( ) => {
await embeddingFunction ( 'Test text for embedding generation' )
} , 50 ) // Only 50 iterations as embeddings are slow
// Test without embeddings (using pre-computed vectors)
const precomputedVector = new Array ( 384 ) . fill ( 0 ) . map ( ( ) => Math . random ( ) )
await profiler . measure ( 'addNoun (with vector)' , async ( ) => {
await defaultBrain . addNoun (
precomputedVector , // Pass vector directly, skip embedding
'document' ,
{ precomputed : true }
)
} , 1000 )
console . log ( '\n⚡ Testing Batch Operations\n' )
// Test batch performance
const batchSize = 100
await profiler . measure ( ` Batch add ( ${ batchSize } items) ` , async ( ) => {
const promises = [ ]
for ( let i = 0 ; i < batchSize ; i ++ ) {
promises . push ( defaultBrain . addNoun (
precomputedVector ,
'document' ,
{ batch : true , index : i }
) )
}
await Promise . all ( promises )
} , 10 ) // 10 batches of 100
// Generate report
profiler . report ( )
// Analyze where we lost performance
console . log ( '\n💡 Performance Loss Analysis\n' )
const minimalPerf = profiler . results [ 'addNoun (minimal)' ]
const defaultPerf = profiler . results [ 'addNoun (default)' ]
const fullPerf = profiler . results [ 'addNoun (full aug)' ]
const embedPerf = profiler . results [ 'Embedding generation' ]
const vectorPerf = profiler . results [ 'addNoun (with vector)' ]
console . log ( 'Overhead breakdown:' )
console . log ( ` Base operation: ${ minimalPerf . perOpMs . toFixed ( 2 ) } ms ` )
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
console . log ( ` Default config: + ${ ( defaultPerf . perOpMs - minimalPerf . perOpMs ) . toFixed ( 2 ) } ms ` )
console . log ( ` Full config: + ${ ( fullPerf . perOpMs - defaultPerf . perOpMs ) . toFixed ( 2 ) } ms ` )
2025-09-11 16:23:32 -07:00
console . log ( ` Embedding generation: ${ embedPerf . perOpMs . toFixed ( 2 ) } ms ` )
console . log ( ` Without embeddings: ${ vectorPerf . perOpMs . toFixed ( 2 ) } ms ` )
const embedOverhead = embedPerf . perOpMs / defaultPerf . perOpMs * 100
console . log ( ` \n 🎯 Embedding overhead: ${ embedOverhead . toFixed ( 1 ) } % of total time ` )
if ( embedOverhead > 80 ) {
console . log ( '❗ Embedding generation is the primary bottleneck' )
console . log ( ' Solutions:' )
console . log ( ' 1. Use pre-computed embeddings when possible' )
console . log ( ' 2. Batch embedding operations' )
console . log ( ' 3. Use worker threads for parallel processing' )
console . log ( ' 4. Consider lighter embedding models' )
}
// Check if we're achieving claimed performance anywhere
const maxOpsPerSec = Math . max ( ... Object . values ( profiler . results ) . map ( r => r . opsPerSec ) )
console . log ( ` \n 📈 Maximum ops/sec achieved: ${ maxOpsPerSec . toLocaleString ( ) } ` )
if ( maxOpsPerSec < 500000 ) {
const gap = ( ( 500000 - maxOpsPerSec ) / 500000 * 100 ) . toFixed ( 1 )
console . log ( ` 📉 Performance gap: ${ gap } % below claimed 500,000 ops/sec ` )
console . log ( '\n🔬 Root Cause:' )
console . log ( ' The 500,000 ops/sec claim was likely based on:' )
console . log ( ' 1. Fake/stub operations that returned immediately' )
console . log ( ' 2. No actual embedding generation' )
console . log ( ' 3. No real storage operations' )
refactor: remove augmentation system and semantic type matching
Remove the entire augmentation pipeline infrastructure (52 files,
~15,000 lines) and the semantic type matching system. These were
unused middleware layers adding complexity without value.
What was removed:
- src/augmentations/ directory (all augmentation implementations)
- src/augmentationManager.ts (pipeline orchestrator)
- src/types/augmentations.ts, src/types/pipelineTypes.ts
- src/shared/default-augmentations.ts
- Semantic type suggestion (BrainyTypes.suggestNoun/suggestVerb)
- src/utils/typeMatching/ (embedding-based type matcher)
What was preserved by relocating:
- Import handlers (CSV, PDF, Excel) -> src/importers/handlers/
- NeuralImportAugmentation -> src/cortex/neuralImportAugmentation.ts
- Type matching utilities -> heuristic inference in consumers
What was simplified:
- brainy.ts: operations call storage directly (no execute() wrapper)
- IntegrationBase: standalone class (no BaseAugmentation parent)
- BrainyTypes: validation-only (nouns, verbs, isValid*, get*)
- Pipeline: direct execution (no augmentation interception)
- index.ts: removed TypeSuggestion, suggestType exports
- package.json: removed stale types/augmentations export
Build passes, 1176 tests pass, 0 failures.
2026-02-01 10:48:56 -08:00
console . log ( ' 4. Direct operation calls' )
2025-09-11 16:23:32 -07:00
console . log ( '\n With real implementations:' )
console . log ( ` - Raw storage: ${ profiler . results [ 'Raw storage.saveNoun' ] ? . opsPerSec || 'N/A' } ops/sec ` )
console . log ( ` - With embeddings: ${ defaultPerf . opsPerSec } ops/sec ` )
console . log ( ` - Without embeddings: ${ vectorPerf . opsPerSec } ops/sec ` )
}
// Cleanup
await minimalBrain . close ( )
await defaultBrain . close ( )
await fullBrain . close ( )
console . log ( '\n✅ Performance profiling complete!' )
}
// Run profiling
profilePerformance ( ) . catch ( error => {
console . error ( '❌ Profiling failed:' , error )
process . exit ( 1 )
} )