diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..b465d51 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,104 @@ +name: Benchmark + +on: + push: + branches: + - master + paths: + - 'internal/**/*.go' + - 'go.mod' + - 'go.sum' + pull_request: + branches: + - master + paths: + - 'internal/**/*.go' + - 'go.mod' + - 'go.sum' + workflow_dispatch: + +permissions: + contents: write + +jobs: + benchmark: + name: Run Benchmarks + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: 'go.mod' + cache: true + + - name: Install benchstat + run: go install golang.org/x/perf/cmd/benchstat@latest + + - name: Download dependencies + run: go mod download + + - name: Fetch baseline benchmark + run: | + if git show origin/master:benchmark-baseline.txt >/dev/null 2>&1; then + git show origin/master:benchmark-baseline.txt > benchmark-baseline.txt + echo "baseline_found=true" >> $GITHUB_ENV + else + echo "baseline_found=false" >> $GITHUB_ENV + fi + + - name: Run benchmarks + run: | + go test -bench=. -benchmem -count=10 ./... 2>&1 | tee benchmark-current.txt + + - name: Compare benchmarks + if: env.baseline_found == 'true' + run: | + benchstat benchmark-baseline.txt benchmark-current.txt > benchmark-comparison.txt + cat benchmark-comparison.txt + + - name: Check for regressions + if: env.baseline_found == 'true' + run: | + if command -v python3 >/dev/null 2>&1; then + benchstat benchmark-baseline.txt benchmark-current.txt | \ + python3 scripts/check_regression.py - \ + --config .benchmark-thresholds.yaml \ + --environment ci \ + || echo "regression_detected=$?" >> $GITHUB_OUTPUT + else + echo "Python3 not available, skipping regression check" + fi + id: regression_check + + - name: Save current benchmark as baseline + if: github.ref == 'refs/heads/master' + run: | + cp benchmark-current.txt benchmark-baseline.txt + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add benchmark-baseline.txt || true + git commit -m "chore(bench): update benchmark baseline" || true + git push || true + + - name: Upload benchmark results + uses: actions/upload-artifact@v4 + with: + name: benchmark-results + path: | + benchmark-current.txt + benchmark-baseline.txt + benchmark-comparison.txt + retention-days: 30 + + - name: Fail on regression + if: steps.regression_check.outputs.regression_detected == '2' + run: | + echo "::error::BLOCK level performance regression detected" + exit 2 \ No newline at end of file