batpak 0.1.0

Event sourcing with causal graphs and policy gates. Sync API, zero async.
Documentation
#!/usr/bin/env bash
# bench-report: run benchmarks, compare against baseline, report what needs
# improvement. Uses criterion's built-in baseline comparison.
#
# Usage:
#   ./scripts/bench-report              # run + compare against saved baseline
#   ./scripts/bench-report --save       # run + save as new baseline
#   ./scripts/bench-report --compare    # compare only (don't re-run)
#
# [SPEC:scripts/bench-report]

set -euo pipefail

MODE="run"

while [[ $# -gt 0 ]]; do
    case "$1" in
        --save)    MODE="save"; shift ;;
        --compare) MODE="compare"; shift ;;
        *)         echo "Unknown arg: $1"; exit 1 ;;
    esac
done

BASELINE_DIR="target/criterion"

if [[ "$MODE" == "save" ]]; then
    echo "Running benchmarks and saving baseline..."
    cargo bench --all-features -- --save-baseline known-good
    echo ""
    echo "Baseline saved. Future runs will compare against this."
    exit 0
fi

if [[ "$MODE" == "compare" ]]; then
    if [[ ! -d "$BASELINE_DIR" ]]; then
        echo "No baseline found. Run: ./scripts/bench-report --save"
        exit 1
    fi
    echo "Comparing against saved baseline..."
    cargo bench --all-features -- --baseline known-good 2>&1
    exit 0
fi

# Default: run and show results with improvement suggestions
echo "Running benchmarks..."
echo ""

# Run benchmarks, capture output
OUTPUT=$(cargo bench --all-features 2>&1)
echo "$OUTPUT"

echo ""
echo "================================================================"
echo "  BENCHMARK IMPROVEMENT REPORT"
echo "================================================================"
echo ""

# Parse criterion output for timing data and suggest improvements.
# Criterion output format: "group/param    time: [low est high]"
echo "$OUTPUT" | awk '
/time:/ {
    # Extract benchmark name and timing
    name = ""
    for (i = 1; i <= NF; i++) {
        if ($i == "time:") break
        if (name != "") name = name " "
        name = name $i
    }

    # Find the estimate (middle value in [low est high])
    for (i = 1; i <= NF; i++) {
        if ($i ~ /^[0-9]+\.[0-9]+$/ && $(i+1) ~ /^(ns|µs|ms|s)$/) {
            value = $i
            unit = $(i+1)

            # Normalize to ms
            ms = value
            if (unit == "ns") ms = value / 1000000
            else if (unit == "µs") ms = value / 1000
            else if (unit == "s") ms = value * 1000

            break
        }
    }

    gsub(/^[ \t]+/, "", name)
    gsub(/[ \t]+$/, "", name)
    if (name != "" && ms + 0 > 0) {
        printf "  %-45s %10.2f ms\n", name, ms
    }
}
'

echo ""
echo "  Investigate slow benchmarks:"
echo "    - write_throughput: src/store/writer.rs (10-step commit)"
echo "    - cold_start:      src/store/mod.rs Store::open + src/store/reader.rs"
echo "    - projection:      src/store/projection.rs + src/store/reader.rs"
echo ""
echo "  Save a baseline:      ./scripts/bench-report --save"
echo "  Compare to baseline:  ./scripts/bench-report --compare"
echo "================================================================"