Skip to content

fix(deps): update rust crate toml to v1 #27

fix(deps): update rust crate toml to v1

fix(deps): update rust crate toml to v1 #27

Workflow file for this run

name: Performance Benchmarks
on:
pull_request:
branches: [main]
paths:
- 'crates/**'
- 'benchmarks/**'
- 'Cargo.toml'
- 'Cargo.lock'
- '.github/workflows/benchmarks.yml'
push:
branches: [main]
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
# Criterion bench targets to run (real_corpus is excluded -- requires QNDX_BENCH_CORPUS)
BENCH_TARGETS: "serializer_choice postings_choice ngram_extract query_planner end_to_end_search git_overlay"
jobs:
benchmark:
name: Run Benchmarks
runs-on: [self-hosted, freebsd]
timeout-minutes: 60
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
- name: Install gnuplot (for Criterion HTML reports)
run: pkg install -y gnuplot
- name: Restore baseline from main branch
if: github.event_name == 'pull_request'
id: restore-baseline
uses: actions/cache/restore@v5
with:
path: target/criterion
key: benchmark-baseline-${{ github.base_ref }}-${{ hashFiles('benchmarks/budgets.toml') }}
restore-keys: |
benchmark-baseline-${{ github.base_ref }}-
benchmark-baseline-main-
# ---------------------------------------------------------------
# PR with baseline: compare against saved main baseline
# ---------------------------------------------------------------
- name: Run benchmarks (PR - with baseline comparison)
if: github.event_name == 'pull_request' && steps.restore-baseline.outputs.cache-hit == 'true'
run: |
echo "::group::Running benchmarks against main baseline"
for bench in $BENCH_TARGETS; do
echo "--- $bench ---"
cargo bench -p qndx-bench --bench "$bench" -- --baseline main 2>&1 | tee -a bench-output.txt
done
echo "::endgroup::"
# ---------------------------------------------------------------
# PR without baseline: just run and save as PR baseline
# ---------------------------------------------------------------
- name: Run benchmarks (PR - no baseline)
if: github.event_name == 'pull_request' && steps.restore-baseline.outputs.cache-hit != 'true'
run: |
echo "::warning::No baseline found, running benchmarks without comparison"
for bench in $BENCH_TARGETS; do
echo "--- $bench ---"
cargo bench -p qndx-bench --bench "$bench" -- --save-baseline "pr-${{ github.event.pull_request.number }}"
done
# ---------------------------------------------------------------
# Main branch push: save as the canonical baseline
# ---------------------------------------------------------------
- name: Run benchmarks (main branch - save as baseline)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
run: |
echo "::group::Running benchmarks and saving as baseline"
for bench in $BENCH_TARGETS; do
echo "--- $bench ---"
cargo bench -p qndx-bench --bench "$bench" -- --save-baseline main
done
echo "::endgroup::"
# ---------------------------------------------------------------
# Check for regressions in Criterion output
# ---------------------------------------------------------------
- name: Check performance budgets
if: github.event_name == 'pull_request' && steps.restore-baseline.outputs.cache-hit == 'true'
run: |
echo "::group::Checking performance budgets"
# Criterion prints "Performance has regressed." to stdout when
# a benchmark regresses beyond its noise threshold.
REGRESSIONS=$(grep -c "Performance has regressed" bench-output.txt || true)
if [ "$REGRESSIONS" -gt 0 ]; then
echo "::warning::Criterion detected $REGRESSIONS benchmark regression(s)"
echo ""
echo "Regressed benchmarks:"
grep -B2 "Performance has regressed" bench-output.txt || true
echo ""
fi
# Check for large regressions (>20% change)
# Criterion format: "change: [-1.2345% +23.4567% +45.6789%]"
# The middle value is the point estimate.
LARGE=$(awk '/change:/{
s=$0; n=0
while(match(s,/\+[0-9]+\.[0-9]+%/)){
n++; val=substr(s,RSTART+1,RLENGTH-2)+0
s=substr(s,RSTART+RLENGTH)
if(n==2 && val>=20) print val
}
}' bench-output.txt || true)
if [ -n "$LARGE" ]; then
echo "::error::Significant performance regression (>20%) detected"
grep -EB5 'change:.*\+[0-9]{2,}\.[0-9]' bench-output.txt || true
exit 1
fi
echo "::notice::Performance budgets check passed ($REGRESSIONS minor regression(s))"
echo "::endgroup::"
- name: Upload benchmark results
if: always()
uses: actions/upload-artifact@v7
with:
name: benchmark-results-${{ github.sha }}
path: |
target/criterion/
bench-output.txt
retention-days: 90
- name: Save baseline cache (main branch)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/cache/save@v5
with:
path: target/criterion
key: benchmark-baseline-${{ github.ref_name }}-${{ hashFiles('benchmarks/budgets.toml') }}
- name: Comment PR with benchmark summary
if: github.event_name == 'pull_request' && steps.restore-baseline.outputs.cache-hit == 'true'
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
let output = '';
try {
output = fs.readFileSync('bench-output.txt', 'utf8');
} catch (e) {
output = '(benchmark output not available)';
}
// Count regressions and improvements
const regressions = (output.match(/Performance has regressed/g) || []).length;
const improvements = (output.match(/Performance has improved/g) || []).length;
const noChange = (output.match(/No change in performance/g) || []).length;
let summary = '## Benchmark Results\n\n';
summary += `| Status | Count |\n|--------|-------|\n`;
summary += `| Regressions | ${regressions} |\n`;
summary += `| Improvements | ${improvements} |\n`;
summary += `| No change | ${noChange} |\n\n`;
if (regressions > 0) {
summary += '### Regressions\n\n```\n';
const lines = output.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].includes('Performance has regressed')) {
// Include benchmark name (2 lines before) and the change line
const start = Math.max(0, i - 3);
summary += lines.slice(start, i + 1).join('\n') + '\n\n';
}
}
summary += '```\n\n';
}
summary += 'Download full results from the workflow artifacts.\n';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
# ================================================================
# Nightly comprehensive benchmark run for trend tracking
# ================================================================
nightly-benchmark:
name: Nightly Comprehensive Benchmarks
runs-on: [self-hosted, freebsd]
if: github.event_name == 'workflow_dispatch'
timeout-minutes: 120
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Set date
run: echo "BENCH_DATE=$(date +%Y%m%d)" >> $GITHUB_ENV
- name: Run all benchmarks
run: |
for bench in $BENCH_TARGETS; do
echo "--- $bench ---"
cargo bench -p qndx-bench --bench "$bench" -- --save-baseline "nightly-$BENCH_DATE"
done
- name: Upload nightly results
uses: actions/upload-artifact@v7
with:
name: nightly-benchmark-${{ env.BENCH_DATE }}
path: target/criterion/
retention-days: 365