# Benchmark CI Workflow # 分层策略: # - PR 趋势监控: 宽松阈值,不阻塞合并 # - 定期完整检测: 严格阈值,生成报告 # # 作者: xfy name: Benchmark on: push: branches: [master] pull_request: branches: [master] schedule: # 每周一凌晨 2 点运行完整检测 - cron: '0 2 * * 1' workflow_dispatch: inputs: full: description: 'Run full benchmark suite' required: false default: 'false' env: GO_VERSION: '1.23' BENCH_COUNT: 10 jobs: # PR 趋势监控 - 宽松阈值,仅警告 benchmark-pr: name: PR Benchmark if: github.event_name == 'pull_request' runs-on: ubuntu-latest timeout-minutes: 15 steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run core benchmarks id: bench run: | # 运行核心模块基准测试 go test -bench='Benchmark(Variable|Compression|RateLimiter|SlidingWindow|AccessLog|Static|Cache|Proxy|LoadBalance)' \ -benchmem -count=${{ env.BENCH_COUNT }} -timeout=10m ./... 2>&1 | tee benchmark-pr.txt # 统计测试数量 echo "test_count=$(grep -c 'ns/op' benchmark-pr.txt || echo 0)" >> $GITHUB_OUTPUT - name: Check regression (warning only) run: | # 宽松阈值 ±20%,仅作警告 python3 scripts/check_regression.py \ --warning-threshold 20 \ --block-threshold 30 \ benchmark-pr.txt || \ echo "::warning::Potential performance change detected (±20% threshold)" - name: Comment on PR uses: actions/github-script@v7 with: script: | const fs = require('fs'); const output = fs.readFileSync('benchmark-pr.txt', 'utf8'); const lines = output.split('\n').filter(l => l.includes('ns/op')).slice(0, 25); const body = `## 📊 Benchmark Results \`\`\` ${lines.join('\n')} \`\`\` - Tests run: ${{ steps.bench.outputs.test_count }} - Threshold: ±20% (warning only) `; github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: body }); - name: Upload results uses: actions/upload-artifact@v4 with: name: benchmark-pr-results path: benchmark-pr.txt retention-days: 7 # 定期完整检测 - 严格阈值 benchmark-weekly: name: Weekly Full Benchmark if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Install benchstat run: go install golang.org/x/perf/cmd/benchstat@latest - name: Run full benchmarks id: bench run: | echo "Running full benchmark suite..." go test -bench=. -benchmem -count=20 -timeout=25m ./... 2>&1 | tee benchmark-full.txt # 生成统计报告 benchstat benchmark-full.txt > benchmark-stat.txt || true echo "test_count=$(grep -c 'ns/op' benchmark-full.txt || echo 0)" >> $GITHUB_OUTPUT - name: Check regression with config run: | if [ -f .benchmark-thresholds.yaml ]; then python3 scripts/check_regression.py \ --config .benchmark-thresholds.yaml \ --environment ci \ benchmark-full.txt || true else python3 scripts/check_regression.py \ --warning-threshold 15 \ --block-threshold 25 \ benchmark-full.txt || true fi - name: Upload baseline uses: actions/upload-artifact@v4 with: name: benchmark-baseline path: benchmark-full.txt retention-days: 30 - name: Upload report uses: actions/upload-artifact@v4 with: name: benchmark-report path: | benchmark-stat.txt retention-days: 90 - name: Create issue on regression if: failure() uses: actions/github-script@v7 with: script: | github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: `🚨 Performance Regression Detected - ${new Date().toISOString().split('T')[0]}`, body: `Weekly benchmark detected performance regression.\n\nSee [workflow run](${process.env.GITHUB_SERVER_URL}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`, labels: ['performance', 'regression'] }); # 保存基准线 benchmark-save: name: Save Benchmark Baseline if: github.ref == 'refs/heads/master' runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} - name: Run benchmarks run: | go test -bench=. -benchmem -count=${{ env.BENCH_COUNT }} ./... > benchmark-main.txt - name: Upload baseline uses: actions/upload-artifact@v4 with: name: benchmark-baseline-main path: benchmark-main.txt retention-days: 90