la-stack 0.4.1

Fast, stack-allocated linear algebra for fixed dimensions
Documentation
name: Benchmarks

# Detect performance regressions in exact-arithmetic benchmarks.
# - Push to main: run benchmarks, save Criterion baseline, upload as artifact.
# - PRs: find latest main baseline artifact, download, compare, report.
# Regressions are warning-only — this workflow never fails on regression.

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 # v6.0.2

      - name: Install Rust toolchain
        uses: actions-rust-lang/setup-rust-toolchain@2b1f5e9b395427c92ee4e3331786ca3c37afe2d7 # v1.16.0
        with:
          cache: true

      # ── PR: find and download the latest main baseline ──────────────
      - name: Find latest main baseline
        if: github.event_name == 'pull_request'
        id: find-baseline
        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
        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 # v8.0.1
        with:
          name: bench-baseline-main
          path: target/criterion
          run-id: ${{ steps.find-baseline.outputs.run_id }}
          github-token: ${{ secrets.GITHUB_TOKEN }}

      # ── PR: run benchmarks and compare ──────────────────────────────
      - 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

      # ── Main push: run benchmarks and save baseline ─────────────────
      - 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 # v7.0.1
        with:
          name: bench-baseline-main
          path: target/criterion
          retention-days: 30
          if-no-files-found: error

      # ── PR: report results ──────────────────────────────────────────
      - 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 }}