name: Benchmarks
permissions:
contents: read
actions: read
on:
push:
branches:
- main
paths:
- "src/**"
- "benches/**"
- "Cargo.toml"
- "Cargo.lock"
pull_request:
branches:
- main
paths:
- "src/**"
- "benches/**"
- "Cargo.toml"
- "Cargo.lock"
workflow_dispatch:
concurrency:
group: >
bench-${{ github.workflow }}-${{
github.event_name == 'pull_request' &&
github.event.pull_request.number ||
github.ref
}}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
bench:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 with:
cache: true
- name: Find latest main baseline
if: github.event_name == 'pull_request'
id: find-baseline
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 with:
script: |
// Find the most recent successful run of this workflow on main.
const runs = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'benchmarks.yml',
branch: 'main',
status: 'completed',
conclusion: 'success',
per_page: 5,
});
for (const run of runs.data.workflow_runs) {
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: run.id,
});
const baseline = artifacts.data.artifacts.find(
a => a.name === 'bench-baseline-main' && !a.expired
);
if (baseline) {
console.log(`Found baseline from run ${run.id} (${run.created_at})`);
core.setOutput('found', 'true');
core.setOutput('run_id', run.id.toString());
return;
}
}
console.log('No baseline artifact found');
core.setOutput('found', 'false');
- name: Download baseline artifact
if: >
github.event_name == 'pull_request' &&
steps.find-baseline.outputs.found == 'true'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
name: bench-baseline-main
path: target/criterion
run-id: ${{ steps.find-baseline.outputs.run_id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Run benchmarks (compare against main)
if: github.event_name == 'pull_request'
id: bench-compare
run: |
set -euo pipefail
if [ -d target/criterion/exact_d2/det/main ]; then
echo "::notice::Baseline found — comparing against main"
# --baseline-lenient rather than --baseline: benches added on the
# PR branch that don't yet exist in the main baseline get a
# "no baseline data" notice instead of aborting the whole run.
cargo bench --features bench,exact --bench exact \
-- --baseline-lenient main 2>&1 | tee bench-output.txt
else
echo "::notice::No baseline found — running without comparison"
cargo bench --features bench,exact --bench exact \
2>&1 | tee bench-output.txt
fi
if grep -q "Performance has regressed" bench-output.txt; then
echo "regression=true" >> "$GITHUB_OUTPUT"
else
echo "regression=false" >> "$GITHUB_OUTPUT"
fi
- name: Run benchmarks (save baseline)
if: >
(github.event_name == 'push' || github.event_name == 'workflow_dispatch') &&
github.ref == 'refs/heads/main'
run: >
cargo bench --features bench,exact --bench exact
-- --save-baseline main
- name: Upload baseline artifact
if: >
(github.event_name == 'push' || github.event_name == 'workflow_dispatch') &&
github.ref == 'refs/heads/main'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a with:
name: bench-baseline-main
path: target/criterion
retention-days: 30
if-no-files-found: error
- name: Benchmark summary
if: github.event_name == 'pull_request' && always()
run: |
set -euo pipefail
regression="${BENCH_REGRESSION:-}"
if [ -z "$regression" ]; then
{
echo "### ❓ Benchmark Comparison Unavailable"
echo ""
echo "The benchmark step did not produce a result."
echo "This may indicate a build failure or missing baseline."
} >> "$GITHUB_STEP_SUMMARY"
echo "::warning::Benchmark comparison produced no output"
elif [ "$regression" = "true" ]; then
{
echo "### ⚠️ Performance Regression Detected"
echo ""
echo "Exact-arithmetic benchmarks show regression vs main baseline."
echo "This is a **warning only** — the workflow will not fail."
echo ""
echo '```'
grep -B1 "Performance has regressed" bench-output.txt || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
echo "::warning::Performance regression detected in exact-arithmetic benchmarks"
else
{
echo "### ✅ No Performance Regression"
echo ""
echo "Exact-arithmetic benchmarks are within expected range vs main."
} >> "$GITHUB_STEP_SUMMARY"
fi
env:
BENCH_REGRESSION: ${{ steps.bench-compare.outputs.regression }}