#!/usr/bin/env node /** * Compare benchmark results between Go and JavaScript implementations */ const fs = require('fs'); // Read results const jsResults = JSON.parse(fs.readFileSync('./results-js.json', 'utf8')); const goResults = JSON.parse(fs.readFileSync('./results-go.json', 'utf8')); console.log('=== jdenticon-js vs go-jdenticon Performance Comparison ===\n'); console.log('Environment:'); console.log(` JavaScript: Node.js ${jsResults.nodeVersion}, V8 ${jsResults.v8Version}`); console.log(` Go: ${goResults.goVersion}`); console.log(` Test inputs: ${jsResults.config.numInputs} unique hash strings`); console.log(` Icon size: ${jsResults.config.iconSize}x${jsResults.config.iconSize} pixels\n`); console.log('Performance Results:'); console.log('┌─────────────────────────┬─────────────────┬─────────────────┬──────────────────┐'); console.log('│ Metric │ jdenticon-js │ go-jdenticon │ Go vs JS │'); console.log('├─────────────────────────┼─────────────────┼─────────────────┼──────────────────┤'); // Time per icon const jsTimeMs = jsResults.performance.timePerIconMs; const goTimeMs = goResults.performance.timePerIconMs; const timeDelta = ((goTimeMs - jsTimeMs) / jsTimeMs * 100); const timeComparison = timeDelta > 0 ? `+${timeDelta.toFixed(1)}% slower` : `${Math.abs(timeDelta).toFixed(1)}% faster`; console.log(`│ Time/Icon (ms) │ ${jsTimeMs.toFixed(4).padStart(15)} │ ${goTimeMs.toFixed(4).padStart(15)} │ ${timeComparison.padStart(16)} │`); // Throughput const jsThroughput = jsResults.performance.iconsPerSecond; const goThroughput = goResults.performance.iconsPerSecond; const throughputDelta = ((goThroughput - jsThroughput) / jsThroughput * 100); const throughputComparison = throughputDelta > 0 ? `+${throughputDelta.toFixed(1)}% faster` : `${Math.abs(throughputDelta).toFixed(1)}% slower`; console.log(`│ Throughput (icons/sec) │ ${jsThroughput.toFixed(2).padStart(15)} │ ${goThroughput.toFixed(2).padStart(15)} │ ${throughputComparison.padStart(16)} │`); // Memory - Report side-by-side without direct comparison (different methodologies) const jsMemoryKB = jsResults.memory.heapDeltaKB; const goMemoryB = goResults.memory.bytesPerOp; console.log(`│ JS Heap Delta (KB) │ ${jsMemoryKB.toFixed(2).padStart(15)} │ ${'-'.padStart(15)} │ ${'N/A'.padStart(16)} │`); console.log(`│ Go Allocs/Op (bytes) │ ${'-'.padStart(15)} │ ${goMemoryB.toString().padStart(15)} │ ${'N/A'.padStart(16)} │`); console.log('└─────────────────────────┴─────────────────┴─────────────────┴──────────────────┘\n'); console.log('Additional Go Metrics:'); console.log(` Allocations per icon: ${goResults.memory.allocsPerOp} allocs`); console.log(` Benchmark iterations: ${goResults.config.benchmarkIterations}\n`); console.log('Summary:'); const faster = timeDelta < 0 ? 'Go' : 'JavaScript'; const fasterPercent = Math.abs(timeDelta).toFixed(1); console.log(`• ${faster} is ${fasterPercent}% faster in CPU time`); const targetMet = Math.abs(timeDelta) <= 20; const targetStatus = targetMet ? 'MEETS' : 'DOES NOT MEET'; console.log(`• Go implementation ${targetStatus} the target of being within 20% of jdenticon-js performance`); console.log(`• JS shows a heap increase of ${jsMemoryKB.toFixed(0)} KB for the batch of ${jsResults.config.numInputs} icons`); console.log(`• Go allocates ${goMemoryB} bytes per icon generation (different measurement methodology)`); console.log(`• Go has excellent memory allocation profile with only ${goResults.memory.allocsPerOp} allocations per icon`); if (targetMet) { console.log('\n✅ Performance target achieved! Go implementation is competitive with JavaScript.'); } else { console.log('\n⚠️ Performance target not met. Consider optimization opportunities.'); }