text editor inspired vim and yi
#!/bin/bash

set -euo pipefail

# Usage:
#   scripts/perf_bench_lake.sh [iterations]
#
# Environment:
#   BENCH_ARGS         Extra args for benchmark (default: --no-render)
#   PERF_RESULTS_ROOT  Results root dir (default: perf)
#   PERF_RUN_LABEL     Label for run (default: HHMMSS)
#
# Example:
#   BENCH_ARGS="--case search-bloom --lines 800 --line-len 120 --no-render" scripts/perf_bench_lake.sh 2000

ITERATIONS="10000"
BENCH_ARGS="${BENCH_ARGS:---no-render}"
PERF_CASES="${PERF_CASES:-}"

usage() {
  cat <<'USAGE'
Usage:
  scripts/perf_bench_lake.sh [iterations]
  scripts/perf_bench_lake.sh --iterations N
  scripts/perf_bench_lake.sh --case NAME [--case NAME...]
  scripts/perf_bench_lake.sh --cases "case1,case2"

Notes:
  - Cases are passed through to: bench --case <name>
  - Aliases: linear -> search-linear, bloom -> search-bloom
  - Extra bench args via BENCH_ARGS env (default: --no-render)
USAGE
}

case_list=""
iter_set="0"
while [ "$#" -gt 0 ]; do
  case "$1" in
    -n|--iterations)
      ITERATIONS="${2:-}"
      iter_set="1"
      shift 2
      ;;
    --case)
      case_list="${case_list}${2:-},"
      shift 2
      ;;
    --cases)
      PERF_CASES="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      if [[ "$1" =~ ^[0-9]+$ ]] && [ "$iter_set" = "0" ]; then
        ITERATIONS="$1"
        iter_set="1"
        shift
      else
        echo "Error: unknown argument '$1'"
        usage
        exit 1
      fi
      ;;
  esac
done

if [ -n "$case_list" ]; then
  case_list="${case_list%,}"
  if [ -n "$PERF_CASES" ]; then
    PERF_CASES="${PERF_CASES},${case_list}"
  else
    PERF_CASES="${case_list}"
  fi
fi

RESULTS_ROOT="${PERF_RESULTS_ROOT:-perf}"
RUN_LABEL="${PERF_RUN_LABEL:-$(date +%H%M%S)}"
DATE_DIR="${RESULTS_ROOT}/$(date +%Y-%m-%d)"
REPORT_DIR="${DATE_DIR}/report"
PERF_DATA="${DATE_DIR}/perf-bench-${RUN_LABEL}.data"
PERF_REPORT="${REPORT_DIR}/perf-bench-${RUN_LABEL}.log"
FLAME_DIR="${DATE_DIR}/flamegraph"
PERF_FOLDED="${FLAME_DIR}/perf-bench-${RUN_LABEL}.folded"
FLAMEGRAPH_SVG="${FLAME_DIR}/flamegraph-bench-${RUN_LABEL}.svg"
FLAMEGRAPH_DIR="${FLAMEGRAPH_DIR:-$HOME/.local/bin/FlameGraph}"
STACKCOLLAPSE_BIN="${STACKCOLLAPSE_BIN:-${FLAMEGRAPH_DIR}/stackcollapse-perf.pl}"
FLAMEGRAPH_BIN="${FLAMEGRAPH_BIN:-${FLAMEGRAPH_DIR}/flamegraph.pl}"

echo "=== ViE perf (lake exe bench) ==="
echo "Iterations: ${ITERATIONS}"
echo "Bench args: ${BENCH_ARGS}"
if [ -n "${PERF_CASES}" ]; then
  echo "Perf cases: ${PERF_CASES}"
fi
echo "Results: ${DATE_DIR}"

# 1. Build bench
echo "Building benchmark..."
lake build bench

# 2. Check for perf
if ! command -v perf &> /dev/null; then
  echo "Error: 'perf' command not found. Please install perf."
  exit 1
fi

# 3. Prepare output directories
mkdir -p "${REPORT_DIR}" "${FLAME_DIR}"

# 4. Run perf record using lake exe bench -- <iterations> <args>
run_one () {
  local label="$1"
  shift
  local -a extra_args=("$@")
  local data="${DATE_DIR}/perf-bench-${label}.data"
  local report="${REPORT_DIR}/perf-bench-${label}.log"
  local folded="${FLAME_DIR}/perf-bench-${label}.folded"
  local svg="${FLAME_DIR}/flamegraph-bench-${label}.svg"

  echo "Running perf record (${label})..."
  perf record -g --call-graph dwarf -o "${data}" -- \
    lake exe bench -- "${ITERATIONS}" "${BENCH_ARGS_ARR[@]}" "${extra_args[@]}"

  echo "Writing report to ${report}"
  perf report -i "${data}" --stdio > "${report}"

  if { [ -x "${STACKCOLLAPSE_BIN}" ] && [ -x "${FLAMEGRAPH_BIN}" ]; } || \
     { command -v stackcollapse-perf.pl &> /dev/null && command -v flamegraph.pl &> /dev/null; }; then
    echo "Generating flamegraph (${label})..."
    if [ -x "${STACKCOLLAPSE_BIN}" ] && [ -x "${FLAMEGRAPH_BIN}" ]; then
      perf script -i "${data}" | "${STACKCOLLAPSE_BIN}" > "${folded}"
      "${FLAMEGRAPH_BIN}" "${folded}" > "${svg}"
    else
      perf script -i "${data}" | stackcollapse-perf.pl > "${folded}"
      flamegraph.pl "${folded}" > "${svg}"
    fi
  else
    echo "Flamegraph tools not found. Skipping flamegraph generation."
    echo "Expected in \$FLAMEGRAPH_DIR (default: ${FLAMEGRAPH_DIR})"
  fi
}

read -r -a BENCH_ARGS_ARR <<< "${BENCH_ARGS}"

if [ -n "${PERF_CASES}" ]; then
  IFS=',' read -r -a CASES_ARR <<< "${PERF_CASES}"
  for c in "${CASES_ARR[@]}"; do
    c_trim="$(echo "${c}" | xargs)"
    if [ -z "${c_trim}" ]; then
      continue
    fi
    case "${c_trim}" in
      linear) norm="search-linear" ;;
      bloom) norm="search-bloom" ;;
      *) norm="${c_trim}" ;;
    esac
    run_one "${RUN_LABEL}-${norm}" --case "${norm}"
  done
else
  run_one "${RUN_LABEL}"
fi

echo "Done."