|
| 1 | +/** |
| 2 | + * Run complete benchmark suite |
| 3 | + * |
| 4 | + * Usage: npx tsx runners/run-all.ts [--skip-compile] [--skip-prove] |
| 5 | + */ |
| 6 | + |
| 7 | +import * as fs from 'fs'; |
| 8 | +import * as path from 'path'; |
| 9 | +import { fileURLToPath } from 'url'; |
| 10 | +import { ALL_CONFIGS, SCALING_CONFIGS, RSA_CONFIGS, FEATURE_CONFIGS, PRECOMPUTE_CONFIGS, PRECOMPUTE_REDUCED_CONFIGS } from '../config/circuits.config.js'; |
| 11 | +import { BENCHMARK_CONFIG } from '../config/benchmark.config.js'; |
| 12 | +import { generateAllCircuits } from '../lib/circuit-generator.js'; |
| 13 | +import { compileAllCircuits, ConstraintInfo } from '../lib/constraint-counter.js'; |
| 14 | +import { runBenchmarks, ProvingResult } from '../lib/prover.js'; |
| 15 | +import { generateReport, saveReports } from '../lib/reporter.js'; |
| 16 | + |
| 17 | +const __dirname = path.dirname(fileURLToPath(import.meta.url)); |
| 18 | + |
| 19 | +async function main() { |
| 20 | + const args = process.argv.slice(2); |
| 21 | + const skipCompile = args.includes('--skip-compile'); |
| 22 | + const skipProve = args.includes('--skip-prove'); |
| 23 | + const category = args.find(a => ['--scaling', '--rsa', '--features', '--precompute'].includes(a)); |
| 24 | + |
| 25 | + // Select configs based on category |
| 26 | + let configs = ALL_CONFIGS; |
| 27 | + let categoryName = 'All'; |
| 28 | + |
| 29 | + if (category === '--scaling') { |
| 30 | + configs = SCALING_CONFIGS; |
| 31 | + categoryName = 'Scaling'; |
| 32 | + } else if (category === '--rsa') { |
| 33 | + configs = RSA_CONFIGS; |
| 34 | + categoryName = 'RSA'; |
| 35 | + } else if (category === '--features') { |
| 36 | + configs = FEATURE_CONFIGS; |
| 37 | + categoryName = 'Features'; |
| 38 | + } else if (category === '--precompute') { |
| 39 | + configs = [...PRECOMPUTE_CONFIGS, ...PRECOMPUTE_REDUCED_CONFIGS]; |
| 40 | + categoryName = 'Precompute'; |
| 41 | + } |
| 42 | + |
| 43 | + console.log('═'.repeat(60)); |
| 44 | + console.log(` ZK-Email-Verify Benchmark Suite (${categoryName})`); |
| 45 | + console.log('═'.repeat(60)); |
| 46 | + console.log(); |
| 47 | + |
| 48 | + // Check prerequisites |
| 49 | + if (!skipProve && !fs.existsSync(BENCHMARK_CONFIG.ptauFile)) { |
| 50 | + console.error(`Error: Powers of tau file not found: ${BENCHMARK_CONFIG.ptauFile}`); |
| 51 | + console.error('Download with:'); |
| 52 | + console.error(` wget -O "${BENCHMARK_CONFIG.ptauFile}" https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_22.ptau`); |
| 53 | + process.exit(1); |
| 54 | + } |
| 55 | + |
| 56 | + // Check for input files |
| 57 | + const inputsExist = configs.some(c => |
| 58 | + fs.existsSync(path.join(BENCHMARK_CONFIG.inputsDir, `${c.id}.json`)) |
| 59 | + ); |
| 60 | + |
| 61 | + if (!skipProve && !inputsExist) { |
| 62 | + console.error('Error: No input files found. Run these steps first:'); |
| 63 | + console.error(' npm run generate-keys'); |
| 64 | + console.error(' npm run generate-emails'); |
| 65 | + console.error(' npm run generate-circuit-inputs'); |
| 66 | + process.exit(1); |
| 67 | + } |
| 68 | + |
| 69 | + let constraintResults: Map<string, ConstraintInfo> = new Map(); |
| 70 | + let provingResults: ProvingResult[] = []; |
| 71 | + |
| 72 | + // Phase 1: Generate circuits |
| 73 | + console.log('Phase 1: Generating circuit files...'); |
| 74 | + console.log('─'.repeat(40)); |
| 75 | + const circuitPaths = generateAllCircuits(configs); |
| 76 | + console.log(`Generated ${circuitPaths.size} circuits\n`); |
| 77 | + |
| 78 | + // Phase 2: Compile and count constraints |
| 79 | + if (!skipCompile) { |
| 80 | + console.log('Phase 2: Compiling circuits and counting constraints...'); |
| 81 | + console.log('─'.repeat(40)); |
| 82 | + console.log('This may take a while for large circuits...\n'); |
| 83 | + |
| 84 | + console.log('ID\t\t\tConstraints\tTime'); |
| 85 | + console.log('─'.repeat(60)); |
| 86 | + |
| 87 | + constraintResults = await compileAllCircuits(configs, false); |
| 88 | + |
| 89 | + console.log('─'.repeat(60)); |
| 90 | + console.log(`Compiled ${constraintResults.size} circuits\n`); |
| 91 | + } else { |
| 92 | + console.log('Phase 2: Skipped (--skip-compile)\n'); |
| 93 | + } |
| 94 | + |
| 95 | + // Phase 3: Run proving benchmarks |
| 96 | + if (!skipProve) { |
| 97 | + console.log(`Phase 3: Running proving benchmarks (${BENCHMARK_CONFIG.numRuns} runs each)...`); |
| 98 | + console.log('─'.repeat(40)); |
| 99 | + |
| 100 | + provingResults = await runBenchmarks(configs, BENCHMARK_CONFIG.numRuns); |
| 101 | + |
| 102 | + const successful = provingResults.filter(r => r.success).length; |
| 103 | + console.log(`\nCompleted ${provingResults.length} runs (${successful} successful)\n`); |
| 104 | + } else { |
| 105 | + console.log('Phase 3: Skipped (--skip-prove)\n'); |
| 106 | + } |
| 107 | + |
| 108 | + // Phase 4: Generate reports |
| 109 | + if (constraintResults.size > 0 || provingResults.length > 0) { |
| 110 | + console.log('Phase 4: Generating reports...'); |
| 111 | + console.log('─'.repeat(40)); |
| 112 | + |
| 113 | + const report = generateReport( |
| 114 | + Array.from(constraintResults.values()), |
| 115 | + provingResults |
| 116 | + ); |
| 117 | + |
| 118 | + const paths = saveReports(report); |
| 119 | + |
| 120 | + console.log(` JSON: ${paths.jsonPath}`); |
| 121 | + console.log(` CSV: ${paths.csvPath}`); |
| 122 | + console.log(` MD: ${paths.mdPath}`); |
| 123 | + console.log(); |
| 124 | + } |
| 125 | + |
| 126 | + // Summary |
| 127 | + console.log('═'.repeat(60)); |
| 128 | + console.log(' Benchmark Complete'); |
| 129 | + console.log('═'.repeat(60)); |
| 130 | + |
| 131 | + if (constraintResults.size > 0) { |
| 132 | + const constraints = Array.from(constraintResults.values()).map(c => c.constraints); |
| 133 | + console.log(`\nConstraint Range: ${Math.min(...constraints).toLocaleString()} - ${Math.max(...constraints).toLocaleString()}`); |
| 134 | + } |
| 135 | + |
| 136 | + if (provingResults.length > 0) { |
| 137 | + const successful = provingResults.filter(r => r.success); |
| 138 | + if (successful.length > 0) { |
| 139 | + const avgProve = successful.reduce((a, b) => a + b.provingTimeMs, 0) / successful.length; |
| 140 | + console.log(`Avg Proving Time: ${(avgProve / 1000).toFixed(2)}s`); |
| 141 | + } |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +main().catch(console.error); |
0 commit comments