diff options
Diffstat (limited to 'js/baba-yaga/src/benchmarks/benchmark-suite.js')
-rw-r--r-- | js/baba-yaga/src/benchmarks/benchmark-suite.js | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/js/baba-yaga/src/benchmarks/benchmark-suite.js b/js/baba-yaga/src/benchmarks/benchmark-suite.js new file mode 100644 index 0000000..a01bfbd --- /dev/null +++ b/js/baba-yaga/src/benchmarks/benchmark-suite.js @@ -0,0 +1,359 @@ +// 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 + }; +} |