// benchmark-suite.js - Comprehensive performance benchmarking suite import { benchmarkLexers } from './lexer-optimized.js'; import { benchmarkScopes } from './scope-stack.js'; import { benchmarkBuiltins } from './builtins-optimized.js'; import { benchmarkASTPool } from './ast-pool.js'; import { BabaYagaEngine } from './engine.js'; import { BabaYagaConfig } from './config.js'; /** * Comprehensive benchmark suite for measuring performance improvements */ export class BenchmarkSuite { constructor() { this.results = {}; this.testPrograms = this.createTestPrograms(); } /** * Create test programs of varying complexity */ createTestPrograms() { return { simple: ` x : 42; y : x + 8; io.out y; `, arithmetic: ` add : x y -> x + y; multiply : x y -> x * y; result : multiply (add 10 20) (add 5 15); io.out result; `, listProcessing: ` numbers : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; doubled : map (x -> x * 2) numbers; evens : filter (x -> x % 2 = 0) doubled; sum : reduce (acc x -> acc + x) 0 evens; io.out sum; `, recursion: ` factorial : n -> when n is 0 then 1 1 then 1 _ then n * (factorial (n - 1)); result : factorial 10; io.out result; `, patternMatching: ` processValue : x -> when x is 0 then "zero" 1 then "one" Int then "integer" String then "string" _ then "other"; values : [0, 1, 42, "hello", true]; results : map processValue values; io.out results; `, complexNested: ` fibonacci : n -> when n is 0 then 0 1 then 1 _ then (fibonacci (n - 1)) + (fibonacci (n - 2)); range : n -> with rec ( helper : i acc -> when i is 0 then acc _ then helper (i - 1) (prepend i acc); ) -> helper n []; fibNumbers : map fibonacci (range 15); evenFibs : filter (x -> x % 2 = 0) fibNumbers; result : reduce (acc x -> acc + x) 0 evenFibs; io.out result; ` }; } /** * Run all benchmarks */ async runAll() { console.log('๐Ÿš€ Starting Baba Yaga Performance Benchmark Suite\n'); await this.benchmarkComponents(); await this.benchmarkPrograms(); await this.generateReport(); return this.results; } /** * Benchmark individual components */ async benchmarkComponents() { console.log('๐Ÿ“Š Benchmarking Individual Components\n'); // Lexer benchmarks console.log('๐Ÿ”ค Lexer Performance:'); this.results.lexer = await benchmarkLexers(this.testPrograms.complexNested, 1000); console.log(''); // Scope stack benchmarks console.log('๐Ÿ“š Scope Stack Performance:'); this.results.scopes = await benchmarkScopes(50000); console.log(''); // Built-in functions benchmarks console.log('โšก Built-in Functions Performance:'); this.results.builtins = await benchmarkBuiltins(5000); console.log(''); // AST Pool benchmarks console.log('๐ŸŠ AST Object Pool Performance:'); this.results.astPool = await benchmarkASTPool(50000); console.log(''); } /** * Benchmark complete programs */ async benchmarkPrograms() { console.log('๐Ÿ“‹ Benchmarking Complete Programs\n'); this.results.programs = {}; for (const [name, code] of Object.entries(this.testPrograms)) { console.log(`๐Ÿงช Testing ${name}:`); const result = await this.benchmarkProgram(code, name); this.results.programs[name] = result; console.log(` Original: ${result.originalTime.toFixed(2)}ms`); console.log(` Optimized: ${result.optimizedTime.toFixed(2)}ms`); console.log(` Speedup: ${result.speedup.toFixed(2)}x`); console.log(''); } } /** * Benchmark a single program with both engines */ async benchmarkProgram(code, name, iterations = 1000) { // Benchmark original engine const originalConfig = new BabaYagaConfig({ enableOptimizations: false, enableDebugMode: false }); const originalEngine = new BabaYagaEngine(originalConfig); // Warm up for (let i = 0; i < 10; i++) { await originalEngine.execute(code); } const originalStart = performance.now(); for (let i = 0; i < iterations; i++) { await originalEngine.execute(code); } const originalTime = performance.now() - originalStart; // Benchmark optimized engine const optimizedConfig = new BabaYagaConfig({ enableOptimizations: true, enableDebugMode: false }); const optimizedEngine = new BabaYagaEngine(optimizedConfig); // Warm up for (let i = 0; i < 10; i++) { await optimizedEngine.execute(code); } const optimizedStart = performance.now(); for (let i = 0; i < iterations; i++) { await optimizedEngine.execute(code); } const optimizedTime = performance.now() - optimizedStart; return { name, iterations, originalTime, optimizedTime, speedup: originalTime / optimizedTime, originalStats: originalEngine.getStats(), optimizedStats: optimizedEngine.getStats() }; } /** * Generate comprehensive performance report */ async generateReport() { console.log('๐Ÿ“ˆ Performance Summary Report\n'); console.log('=' .repeat(60)); // Component improvements console.log('\n๐Ÿ”ง Component-Level Improvements:'); console.log(` Lexer: ${this.results.lexer.speedup.toFixed(2)}x faster`); console.log(` Scope Stack: ${this.results.scopes.speedup.toFixed(2)}x faster`); console.log(` Built-ins: ${this.results.builtins.speedup.toFixed(2)}x faster`); console.log(` AST Pool: ${this.results.astPool.speedup.toFixed(2)}x faster`); // Program-level improvements console.log('\n๐Ÿš€ Program-Level Improvements:'); let totalSpeedup = 0; let programCount = 0; for (const [name, result] of Object.entries(this.results.programs)) { console.log(` ${name.padEnd(15)}: ${result.speedup.toFixed(2)}x faster`); totalSpeedup += result.speedup; programCount++; } const averageSpeedup = totalSpeedup / programCount; console.log(` Average: ${averageSpeedup.toFixed(2)}x faster`); // Memory and efficiency improvements console.log('\n๐Ÿ’พ Memory & Efficiency:'); const astStats = this.results.astPool.stats; console.log(` AST Pool Hit Rate: ${(astStats.hitRate * 100).toFixed(1)}%`); console.log(` Object Reuse Rate: ${(astStats.reuseRate * 100).toFixed(1)}%`); console.log(` Total Objects Pooled: ${astStats.totalPooledObjects}`); const scopeStats = this.results.scopes.stats; console.log(` Scope Hit Rate: ${(scopeStats.hitRate * 100).toFixed(1)}%`); console.log(` Variable Slots: ${scopeStats.totalSlots}`); // Recommendations console.log('\n๐Ÿ’ก Optimization Impact Summary:'); console.log(` ๐ŸŽฏ Best improvement: ${this.getBestImprovement()}`); console.log(` ๐Ÿ“Š Overall speedup: ${averageSpeedup.toFixed(2)}x`); console.log(` ๐Ÿ”‹ Memory efficiency: ${this.getMemoryEfficiency()}`); console.log('\n' + '=' .repeat(60)); } /** * Identify the best performing optimization */ getBestImprovement() { const improvements = { 'Lexer': this.results.lexer.speedup, 'Scope Stack': this.results.scopes.speedup, 'Built-ins': this.results.builtins.speedup, 'AST Pool': this.results.astPool.speedup }; let best = { name: '', speedup: 0 }; for (const [name, speedup] of Object.entries(improvements)) { if (speedup > best.speedup) { best = { name, speedup }; } } return `${best.name} (${best.speedup.toFixed(2)}x)`; } /** * Calculate overall memory efficiency improvement */ getMemoryEfficiency() { const astHitRate = this.results.astPool.stats.hitRate; const scopeHitRate = this.results.scopes.stats.hitRate; const avgHitRate = (astHitRate + scopeHitRate) / 2; if (avgHitRate > 0.8) return 'Excellent'; if (avgHitRate > 0.6) return 'Good'; if (avgHitRate > 0.4) return 'Fair'; return 'Needs improvement'; } /** * Save results to file */ async saveResults(filename = 'benchmark-results.json') { const fs = await import('fs'); const resultsWithMetadata = { timestamp: new Date().toISOString(), nodeVersion: process.version, platform: process.platform, arch: process.arch, ...this.results }; fs.writeFileSync(filename, JSON.stringify(resultsWithMetadata, null, 2)); console.log(`\n๐Ÿ’พ Results saved to ${filename}`); } } /** * Quick benchmark function for CLI usage */ export async function quickBenchmark() { const suite = new BenchmarkSuite(); return await suite.runAll(); } /** * Memory usage benchmark */ export async function benchmarkMemoryUsage() { console.log('๐Ÿง  Memory Usage Benchmark\n'); const testCode = ` range : n -> with rec ( helper : i acc -> when i is 0 then acc _ then helper (i - 1) (prepend i acc); ) -> helper n []; numbers : range 1000; doubled : map (x -> x * 2) numbers; filtered : filter (x -> x > 100) doubled; result : reduce (acc x -> acc + x) 0 filtered; `; // Measure memory before const memBefore = process.memoryUsage(); // Run multiple iterations const engine = new BabaYagaEngine(); for (let i = 0; i < 100; i++) { await engine.execute(testCode); } // Force garbage collection if available if (global.gc) { global.gc(); } // Measure memory after const memAfter = process.memoryUsage(); console.log('Memory Usage:'); console.log(` Heap Used: ${((memAfter.heapUsed - memBefore.heapUsed) / 1024 / 1024).toFixed(2)} MB`); console.log(` Heap Total: ${((memAfter.heapTotal - memBefore.heapTotal) / 1024 / 1024).toFixed(2)} MB`); console.log(` External: ${((memAfter.external - memBefore.external) / 1024 / 1024).toFixed(2)} MB`); return { heapUsedDiff: memAfter.heapUsed - memBefore.heapUsed, heapTotalDiff: memAfter.heapTotal - memBefore.heapTotal, externalDiff: memAfter.external - memBefore.external }; }