diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 916f865d..2987224a 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -29,15 +29,25 @@ jobs: id: bench run: | echo "Running performance benchmarks..." - pnpm run bench 2>&1 | tee bench-output.txt + pnpm exec vitest bench --run --config vitest.bench.config.mjs --outputJson bench-results.json 2>&1 | tee bench-output.txt - name: Generate benchmark summary if: always() run: | - echo "## 📊 Performance Benchmark Results" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY + # Parse JSON and create markdown table + if [ -f bench-results.json ]; then + node scripts/format-benchmarks.mjs bench-results.json >> $GITHUB_STEP_SUMMARY + else + echo "## 📊 Performance Benchmark Results" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "⚠️ No benchmark results found" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + # Show terminal output + echo "### Terminal Output" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY - cat bench-output.txt >> $GITHUB_STEP_SUMMARY + sed 's/\x1b\[[0-9;]*m//g' bench-output.txt >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY - name: Check for regressions (informational) diff --git a/scripts/format-benchmarks.mjs b/scripts/format-benchmarks.mjs new file mode 100755 index 00000000..48645374 --- /dev/null +++ b/scripts/format-benchmarks.mjs @@ -0,0 +1,65 @@ +#!/usr/bin/env node + +import { readFileSync } from 'fs'; + +function addCommas(num) { + const str = num.toString(); + if (str.length <= 3) return str; + return addCommas(str.slice(0, -3)) + ',' + str.slice(-3); +} + +function formatNumber(num, decimals = 4) { + const multiplier = Math.pow(10, decimals); + return (Math.round(num * multiplier) / multiplier).toString(); +} + +function formatBenchmarkResults(jsonFile) { + const data = JSON.parse(readFileSync(jsonFile, 'utf8')); + + const lines = []; + lines.push('## 📊 Performance Benchmark Results'); + lines.push(''); + lines.push('| Benchmark | Hz | Min | Max | Mean | P75 | P99 | P995 | P999 |'); + lines.push('|-----------|-------|------|------|------|------|------|------|------|'); + + let totalBenchmarks = 0; + + for (const file of data.files) { + for (const group of file.groups) { + for (const benchmark of group.benchmarks) { + totalBenchmarks++; + + const row = [ + benchmark.name, + addCommas(Math.floor(benchmark.hz)), + formatNumber(benchmark.min), + formatNumber(benchmark.max), + formatNumber(benchmark.mean), + formatNumber(benchmark.p75), + formatNumber(benchmark.p99), + formatNumber(benchmark.p995), + formatNumber(benchmark.p999) + ]; + + lines.push('| ' + row.join(' | ') + ' |'); + } + } + } + + lines.push(''); + lines.push(`_Total benchmarks: ${totalBenchmarks}_`); + lines.push(''); + + return lines.join('\n'); +} + +// Main execution +const jsonFile = process.argv[2] || 'bench-results.json'; + +try { + const markdown = formatBenchmarkResults(jsonFile); + console.log(markdown); +} catch (error) { + console.error('Error formatting benchmark results:', error.message); + process.exit(1); +}