- Core library with SVG and PNG generation - CLI tool with generate and batch commands - Cross-platform path handling for Windows compatibility - Comprehensive test suite with integration tests
140 lines
4.5 KiB
JavaScript
140 lines
4.5 KiB
JavaScript
#!/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 ./...'); |