From b8c1c856945e8d83de2229c24ea8d562d6542f3a Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 6 Oct 2025 18:00:05 +0000 Subject: [PATCH 1/5] Strip ANSI control codes from benchmark output in GitHub Actions summary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use sed to remove ANSI escape sequences (color/formatting codes) before appending benchmark results to the GitHub Actions summary, ensuring clean, readable output without terminal control characters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/performance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 916f865d..40bdbcb7 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -37,7 +37,7 @@ jobs: echo "## 📊 Performance Benchmark Results" >> $GITHUB_STEP_SUMMARY echo "" >> $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) From e89a9a858c0193853fa6ef3e26e9d4744d1b8d18 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 6 Oct 2025 19:30:46 +0000 Subject: [PATCH 2/5] Generate markdown table from JSON benchmark results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Parse JSON output with jq to create formatted markdown table - Add thousand separators to operations/sec column - Convert time values from seconds to milliseconds - Include both markdown table and raw terminal output - Terminal output still has ANSI codes stripped 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/performance.yml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 40bdbcb7..b977c83a 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -29,13 +29,39 @@ 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 + echo "| Benchmark | Operations/sec | Mean (ms) | Min (ms) | Max (ms) | P99 (ms) |" >> $GITHUB_STEP_SUMMARY + echo "|-----------|----------------|-----------|----------|----------|----------|" >> $GITHUB_STEP_SUMMARY + + jq -r ' + def format_number: tostring | + (. / ".") as $parts | + if ($parts | length) == 2 then + ($parts[0] | gsub("(?[0-9])(?([0-9]{3})+$)"; "\(.x),\(.y)")) + "." + $parts[1] + else + $parts[0] | gsub("(?[0-9])(?([0-9]{3})+$)"; "\(.x),\(.y)") + end; + + .files[].groups[].benchmarks[] | + "| \(.name) | \(.hz | floor | format_number) | \((.mean * 1000) | (. * 100 | round / 100)) | \((.min * 1000) | (. * 100 | round / 100)) | \((.max * 1000) | (. * 100 | round / 100)) | \((.p99 * 1000) | (. * 100 | round / 100)) |" + ' bench-results.json >> $GITHUB_STEP_SUMMARY + + echo "" >> $GITHUB_STEP_SUMMARY + echo "_Total benchmarks: $(jq '[.files[].groups[].benchmarks[]] | length' bench-results.json)_" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + # Show terminal output + echo "### Terminal Output" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY sed 's/\x1b\[[0-9;]*m//g' bench-output.txt >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY From d605d5eae7d1a3b85b0101d69ac92bcc32f20a5d Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 6 Oct 2025 19:44:51 +0000 Subject: [PATCH 3/5] Fix benchmark table: match ASCII output format and correct units MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Values are already in milliseconds, removed incorrect *1000 multiplication - Reordered columns to match ASCII output: Hz, Min, Max, Mean, P75, P99, P995, P999 - Fixed thousands separator to handle large numbers correctly (e.g., 4,198,728) - Uses recursive add_commas function instead of regex 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/performance.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index b977c83a..90e0b3c4 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -39,20 +39,20 @@ jobs: # Parse JSON and create markdown table if [ -f bench-results.json ]; then - echo "| Benchmark | Operations/sec | Mean (ms) | Min (ms) | Max (ms) | P99 (ms) |" >> $GITHUB_STEP_SUMMARY - echo "|-----------|----------------|-----------|----------|----------|----------|" >> $GITHUB_STEP_SUMMARY + echo "| Benchmark | Hz | Min | Max | Mean | P75 | P99 | P995 | P999 |" >> $GITHUB_STEP_SUMMARY + echo "|-----------|-------|------|------|------|------|------|------|------|" >> $GITHUB_STEP_SUMMARY jq -r ' - def format_number: tostring | - (. / ".") as $parts | - if ($parts | length) == 2 then - ($parts[0] | gsub("(?[0-9])(?([0-9]{3})+$)"; "\(.x),\(.y)")) + "." + $parts[1] - else - $parts[0] | gsub("(?[0-9])(?([0-9]{3})+$)"; "\(.x),\(.y)") + def add_commas: + tostring | + if length <= 3 then . + else (.[:-3] | add_commas) + "," + .[-3:] end; + def format_hz: floor | add_commas; + .files[].groups[].benchmarks[] | - "| \(.name) | \(.hz | floor | format_number) | \((.mean * 1000) | (. * 100 | round / 100)) | \((.min * 1000) | (. * 100 | round / 100)) | \((.max * 1000) | (. * 100 | round / 100)) | \((.p99 * 1000) | (. * 100 | round / 100)) |" + "| \(.name) | \(.hz | format_hz) | \(.min | (. * 100 | round / 100)) | \(.max | (. * 100 | round / 100)) | \(.mean | (. * 100 | round / 100)) | \(.p75 | (. * 100 | round / 100)) | \(.p99 | (. * 100 | round / 100)) | \(.p995 | (. * 100 | round / 100)) | \(.p999 | (. * 100 | round / 100)) |" ' bench-results.json >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY From 631dc24b104db49188263ac22de667a405e06525 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 6 Oct 2025 19:45:55 +0000 Subject: [PATCH 4/5] Replace jq/shell logic with Node.js script for benchmark formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Created scripts/format-benchmarks.mjs to parse JSON and generate markdown - Simplified GitHub Actions workflow to call the script - Script is easier to test locally and maintain - Maintains same output format: table with Hz, Min, Max, Mean, P75, P99, P995, P999 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/performance.yml | 24 ++---------- scripts/format-benchmarks.mjs | 64 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 20 deletions(-) create mode 100755 scripts/format-benchmarks.mjs diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 90e0b3c4..2987224a 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -34,29 +34,13 @@ jobs: - 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 - echo "| Benchmark | Hz | Min | Max | Mean | P75 | P99 | P995 | P999 |" >> $GITHUB_STEP_SUMMARY - echo "|-----------|-------|------|------|------|------|------|------|------|" >> $GITHUB_STEP_SUMMARY - - jq -r ' - def add_commas: - tostring | - if length <= 3 then . - else (.[:-3] | add_commas) + "," + .[-3:] - end; - - def format_hz: floor | add_commas; - - .files[].groups[].benchmarks[] | - "| \(.name) | \(.hz | format_hz) | \(.min | (. * 100 | round / 100)) | \(.max | (. * 100 | round / 100)) | \(.mean | (. * 100 | round / 100)) | \(.p75 | (. * 100 | round / 100)) | \(.p99 | (. * 100 | round / 100)) | \(.p995 | (. * 100 | round / 100)) | \(.p999 | (. * 100 | round / 100)) |" - ' bench-results.json >> $GITHUB_STEP_SUMMARY - + node scripts/format-benchmarks.mjs bench-results.json >> $GITHUB_STEP_SUMMARY + else + echo "## 📊 Performance Benchmark Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "_Total benchmarks: $(jq '[.files[].groups[].benchmarks[]] | length' bench-results.json)_" >> $GITHUB_STEP_SUMMARY + echo "⚠️ No benchmark results found" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi diff --git a/scripts/format-benchmarks.mjs b/scripts/format-benchmarks.mjs new file mode 100755 index 00000000..b23bc07b --- /dev/null +++ b/scripts/format-benchmarks.mjs @@ -0,0 +1,64 @@ +#!/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 = 2) { + return (Math.round(num * 100) / 100).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); +} From 6f092f6a7f4cbbeed252f3bbc65c93dcb73cb897 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 6 Oct 2025 19:48:49 +0000 Subject: [PATCH 5/5] Increase precision to 4 decimal places for benchmark values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated formatNumber function to round to 4 decimal places instead of 2, providing more precise timing measurements for fast operations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- scripts/format-benchmarks.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/format-benchmarks.mjs b/scripts/format-benchmarks.mjs index b23bc07b..48645374 100755 --- a/scripts/format-benchmarks.mjs +++ b/scripts/format-benchmarks.mjs @@ -8,8 +8,9 @@ function addCommas(num) { return addCommas(str.slice(0, -3)) + ',' + str.slice(-3); } -function formatNumber(num, decimals = 2) { - return (Math.round(num * 100) / 100).toString(); +function formatNumber(num, decimals = 4) { + const multiplier = Math.pow(10, decimals); + return (Math.round(num * multiplier) / multiplier).toString(); } function formatBenchmarkResults(jsonFile) {