#!/usr/bin/env node /** * Node.js benchmark script for jdenticon-js using perf_hooks * Tests performance with JIT warm-up for fair comparison against Go implementation * Run with: node --expose-gc benchmark-js.js */ const fs = require('fs'); const path = require('path'); const { performance } = require('perf_hooks'); // Check if jdenticon-js is available let jdenticon; try { jdenticon = require('../jdenticon-js/dist/jdenticon-node.js'); } catch (err) { console.error('Error: jdenticon-js not found. Please ensure it\'s available in jdenticon-js/dist/'); console.error('You may need to build the JS version first.'); process.exit(1); } // --- Configuration --- const ICON_SIZE = 64; const WARMUP_RUNS = 3; // Load test inputs const inputsPath = path.join(__dirname, 'inputs.json'); if (!fs.existsSync(inputsPath)) { console.error('Error: inputs.json not found. Run generate-inputs.js first.'); process.exit(1); } const inputs = JSON.parse(fs.readFileSync(inputsPath, 'utf8')); const numInputs = inputs.length; console.log('=== jdenticon-js Performance Benchmark ==='); console.log(`Inputs: ${numInputs} unique hash strings`); console.log(`Icon size: ${ICON_SIZE}x${ICON_SIZE} pixels`); console.log(`Format: SVG`); console.log(`Node.js version: ${process.version}`); console.log(`V8 version: ${process.versions.v8}`); console.log(''); // --- Benchmark Function --- function generateAllIcons() { for (let i = 0; i < numInputs; i++) { jdenticon.toSvg(inputs[i], ICON_SIZE); } } // --- Warm-up Phase --- console.log(`Warming up JIT with ${WARMUP_RUNS} runs...`); for (let i = 0; i < WARMUP_RUNS; i++) { console.log(` Warm-up run ${i + 1}/${WARMUP_RUNS}`); generateAllIcons(); } // Force garbage collection for clean baseline (if --expose-gc was used) if (global.gc) { console.log('Forcing garbage collection...'); global.gc(); } else { console.log('Note: Run with --expose-gc for more accurate memory measurements'); } console.log(''); // --- Measurement Phase --- console.log(`Running benchmark with ${numInputs} icons...`); const memBefore = process.memoryUsage(); const startTime = performance.now(); generateAllIcons(); // The actual benchmark run const endTime = performance.now(); const memAfter = process.memoryUsage(); // --- Calculate Metrics --- const totalTimeMs = endTime - startTime; const timePerIconMs = totalTimeMs / numInputs; const timePerIconUs = timePerIconMs * 1000; // microseconds const iconsPerSecond = 1000 / timePerIconMs; // Memory metrics const heapDelta = memAfter.heapUsed - memBefore.heapUsed; const heapDeltaKB = heapDelta / 1024; const heapDeltaPerIcon = heapDelta / numInputs; // --- Results Report --- console.log(''); console.log('=== jdenticon-js Results ==='); console.log(`Total time: ${totalTimeMs.toFixed(2)} ms`); console.log(`Time per icon: ${timePerIconMs.toFixed(4)} ms (${timePerIconUs.toFixed(2)} μs)`); console.log(`Throughput: ${iconsPerSecond.toFixed(2)} icons/sec`); console.log(''); console.log('Memory Usage:'); console.log(` Heap before: ${(memBefore.heapUsed / 1024).toFixed(2)} KB`); console.log(` Heap after: ${(memAfter.heapUsed / 1024).toFixed(2)} KB`); console.log(` Heap delta: ${heapDeltaKB.toFixed(2)} KB`); console.log(` Per icon: ${heapDeltaPerIcon.toFixed(2)} bytes`); console.log(''); console.log('Additional Memory Info:'); console.log(` RSS: ${(memAfter.rss / 1024 / 1024).toFixed(2)} MB`); console.log(` External: ${(memAfter.external / 1024).toFixed(2)} KB`); // --- Save Results for Comparison --- const results = { implementation: 'jdenticon-js', timestamp: new Date().toISOString(), nodeVersion: process.version, v8Version: process.versions.v8, config: { iconSize: ICON_SIZE, numInputs: numInputs, warmupRuns: WARMUP_RUNS }, performance: { totalTimeMs: totalTimeMs, timePerIconMs: timePerIconMs, timePerIconUs: timePerIconUs, iconsPerSecond: iconsPerSecond }, memory: { heapBeforeKB: memBefore.heapUsed / 1024, heapAfterKB: memAfter.heapUsed / 1024, heapDeltaKB: heapDeltaKB, heapDeltaPerIcon: heapDeltaPerIcon, rssKB: memAfter.rss / 1024, externalKB: memAfter.external / 1024 } }; const resultsPath = path.join(__dirname, 'results-js.json'); fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2)); console.log(`Results saved to: ${resultsPath}`); console.log(''); console.log('Run Go benchmark next: go test -bench=BenchmarkGenerate64pxIcon -benchmem ./...');