Skip to content

chore(deps): update rust crate serde_json to v1.0.151 (#85) #136

chore(deps): update rust crate serde_json to v1.0.151 (#85)

chore(deps): update rust crate serde_json to v1.0.151 (#85) #136

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@v7
with:
fetch-depth: 0
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Record Rust toolchain version
id: rustc-version
run: echo "version=$(rustc --version | sha256 -q)" >> "$GITHUB_OUTPUT"
- 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@v6
with:
path: target/criterion
key: benchmark-baseline-${{ github.base_ref }}-rust-${{ steps.rustc-version.outputs.version }}-${{ hashFiles('benchmarks/budgets.toml') }}
restore-keys: |
benchmark-baseline-${{ github.base_ref }}-rust-${{ steps.rustc-version.outputs.version }}-
benchmark-baseline-main-rust-${{ steps.rustc-version.outputs.version }}-
# ---------------------------------------------------------------
# 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 against budgets.toml
# ---------------------------------------------------------------
- name: Check performance budgets
if: github.event_name == 'pull_request' && steps.restore-baseline.outputs.cache-hit == 'true'
run: |
cargo run -p qndx-cli --features bench-tools -- bench check-budgets \
--comparison bench-output.txt \
--budgets benchmarks/budgets.toml
- 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@v6
with:
path: target/criterion
key: benchmark-baseline-${{ github.ref_name }}-rust-${{ steps.rustc-version.outputs.version }}-${{ 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@v9
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
});
# ================================================================
# Real-corpus benchmark run (on-demand)
# ================================================================
real-corpus-benchmark:
name: Real Corpus Benchmarks
runs-on: [self-hosted, freebsd]
if: github.event_name == 'workflow_dispatch'
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
corpus: [rust, linux, kubernetes]
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
- name: Cache corpus (${{ matrix.corpus }})
id: cache-corpus
uses: actions/cache@v6
with:
path: benchmarks/corpora/${{ matrix.corpus }}
key: corpus-${{ matrix.corpus }}-v1
- name: Download corpus (${{ matrix.corpus }})
if: steps.cache-corpus.outputs.cache-hit != 'true'
run: ./benchmarks/fetch_corpora.sh ${{ matrix.corpus }}
- name: Set date
run: echo "BENCH_DATE=$(date +%Y%m%d)" >> $GITHUB_ENV
- name: Run real_corpus benchmark (${{ matrix.corpus }})
env:
QNDX_BENCH_CORPUS: benchmarks/corpora/${{ matrix.corpus }}
QNDX_BENCH_NAME: ${{ matrix.corpus }}
QNDX_BENCH_PATTERNS: benchmarks/patterns/${{ matrix.corpus }}.txt
run: |
cargo bench -p qndx-bench --bench real_corpus -- \
--save-baseline "real-${{ matrix.corpus }}-$BENCH_DATE"
- name: Upload results (${{ matrix.corpus }})
if: always()
uses: actions/upload-artifact@v7
with:
name: real-corpus-${{ matrix.corpus }}-${{ env.BENCH_DATE }}
path: target/criterion/
retention-days: 365
# ================================================================
# 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@v7
- 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