311 lines
11 KiB
YAML
311 lines
11 KiB
YAML
name: Weekly Benchmarks
|
|
|
|
on:
|
|
schedule:
|
|
- cron: '0 7 * * 0' # 07:00 UTC every Sunday
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
check-commits:
|
|
name: Check for new commits
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
has_new_commits: ${{ steps.check.outputs.has_new_commits }}
|
|
steps:
|
|
- name: Check if there are new commits in last 7 days
|
|
id: check
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const weekMs = 7 * 24 * 60 * 60 * 1000;
|
|
const since = new Date(Date.now() - weekMs).toISOString();
|
|
const { data } = await github.rest.repos.listCommits({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
sha: 'main',
|
|
since,
|
|
per_page: 1,
|
|
});
|
|
const has = data.length > 0;
|
|
core.setOutput('has_new_commits', has ? 'true' : 'false');
|
|
core.info(
|
|
has
|
|
? `Found ${data.length} new commit(s) since ${since}`
|
|
: 'No new commits in last 7 days, skipping benchmarks'
|
|
);
|
|
|
|
nightly-linux:
|
|
needs: check-commits
|
|
if: needs.check-commits.outputs.has_new_commits == 'true' || github.event_name == 'workflow_dispatch'
|
|
name: Benchmarks (Linux x86_64)
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 135
|
|
env:
|
|
BUILD_DIR: builddir
|
|
YAMS_DISABLE_FAISS: 1
|
|
# Opt-in switch to run the daemon warm-latency bench (off by default)
|
|
RUN_DAEMON_WARM_BENCH: 'false'
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v5
|
|
with:
|
|
fetch-depth: 0
|
|
submodules: false
|
|
|
|
- name: Initialize required submodules
|
|
shell: bash
|
|
run: |
|
|
# Force HTTPS for GitHub to handle SSH submodule URLs in CI
|
|
git config --global url."https://github.com/".insteadOf "git@github.com:"
|
|
git submodule update --init --depth 1 third_party/sqlite-vec-cpp
|
|
git submodule update --init --depth 1 third_party/simeon
|
|
git submodule update --init --depth 1 third_party/symspell
|
|
|
|
- name: Install system dependencies
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends pkg-config meson ninja-build cmake python3-pip libboost-all-dev libomp-18-dev ccache
|
|
|
|
- name: Install Conan
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
PYTOOLS_DIR="${RUNNER_TEMP}/yams-python-tools"
|
|
python3 -m venv "$PYTOOLS_DIR"
|
|
"$PYTOOLS_DIR/bin/python" -m pip install --upgrade pip
|
|
"$PYTOOLS_DIR/bin/python" -m pip install --upgrade conan
|
|
echo "$PYTOOLS_DIR/bin" >> "$GITHUB_PATH"
|
|
export PATH="$PYTOOLS_DIR/bin:$PATH"
|
|
conan --version
|
|
|
|
# Detect Conan profile (required for setup.sh)
|
|
conan profile detect --force || true
|
|
|
|
- name: Cache Conan
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.conan2/p
|
|
~/.conan2/r
|
|
~/.conan2/recipes
|
|
~/.conan2/metadata
|
|
~/.conan2/s
|
|
key: nightly-conan2-linux-${{ hashFiles('conanfile.py', 'meson.build', 'meson_options.txt') }}
|
|
restore-keys: |
|
|
nightly-conan2-linux-
|
|
|
|
- name: Cache ccache
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ~/.cache/ccache
|
|
key: nightly-ccache-linux-${{ hashFiles('conanfile.py', 'meson.build', 'meson_options.txt') }}
|
|
restore-keys: |
|
|
nightly-ccache-linux-
|
|
|
|
- name: Setup ccache env
|
|
shell: bash
|
|
run: |
|
|
{
|
|
echo "CCACHE_DIR=$HOME/.cache/ccache"
|
|
echo "CCACHE_BASEDIR=$GITHUB_WORKSPACE"
|
|
echo "CCACHE_COMPRESS=1"
|
|
echo "CCACHE_MAXSIZE=5G"
|
|
echo "CCACHE_SLOPPINESS=time_macros,include_file_mtime,include_file_ctime,file_macro"
|
|
} >> "$GITHUB_ENV"
|
|
ccache -z >/dev/null 2>&1 || true
|
|
|
|
- name: Configure (Release) and Build
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
rm -rf "$BUILD_DIR"
|
|
|
|
# Keep AF_UNIX socket path short
|
|
XDG_RUNTIME_DIR="/run/user/$(id -u)"
|
|
export XDG_RUNTIME_DIR
|
|
mkdir -p "$XDG_RUNTIME_DIR" || true
|
|
|
|
# Use setup.sh with CI environment variables for consistent configuration
|
|
export YAMS_CONAN_HOST_PROFILE="./conan/profiles/host-linux-clang"
|
|
export YAMS_CONAN_ARCH="x86_64"
|
|
# Ensure Conan and Meson both opt into benchmark targets.
|
|
export YAMS_CONAN_EXTRA_OPTIONS="-o build_tests=True -o build_benchmarks=True"
|
|
export YAMS_EXTRA_MESON_FLAGS="-Dbuild-tests=true -Dbuild-benchmarks=true -Denable-onnx=disabled"
|
|
export YAMS_ENABLE_MOBILE_BINDINGS=false
|
|
|
|
./setup.sh Debug
|
|
CONAN_BUILD_ENV=""
|
|
for candidate in \
|
|
"$BUILD_DIR/build-debug/conan/conanbuild.sh" \
|
|
"$BUILD_DIR/conan/conanbuild.sh"
|
|
do
|
|
if [ -f "$candidate" ]; then
|
|
CONAN_BUILD_ENV="$candidate"
|
|
break
|
|
fi
|
|
done
|
|
if [ -n "$CONAN_BUILD_ENV" ]; then
|
|
set +u
|
|
# shellcheck disable=SC1090
|
|
source "$CONAN_BUILD_ENV"
|
|
set -u
|
|
fi
|
|
meson compile -C "$BUILD_DIR"
|
|
|
|
- name: Run Bench Test Suite
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
meson test -C "$BUILD_DIR" --suite bench -t 7 --no-rebuild
|
|
|
|
- name: Capture failing test diagnostics
|
|
if: failure()
|
|
shell: bash
|
|
run: |
|
|
echo "### Failing Bench Diagnostics" >> "$GITHUB_STEP_SUMMARY"
|
|
LOG="$BUILD_DIR/meson-logs/testlog.txt"
|
|
if [ -f "$LOG" ]; then
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
grep -E 'FAIL|killed|SIGABRT|Signal|abort|Error|error:' "$LOG" | head -80 >> "$GITHUB_STEP_SUMMARY" || true
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
fi
|
|
echo "### ccache stats" >> "$GITHUB_STEP_SUMMARY"
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
ccache -s 2>/dev/null | head -10 >> "$GITHUB_STEP_SUMMARY" || true
|
|
echo '```' >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
- name: Run Daemon Warm-Latency Bench (opt-in)
|
|
if: env.RUN_DAEMON_WARM_BENCH == 'true'
|
|
shell: bash
|
|
env:
|
|
YAMS_ENABLE_DAEMON_BENCH: '1'
|
|
run: |
|
|
set -euo pipefail
|
|
echo "Running bench_daemon_warm_latency (opt-in)..."
|
|
meson test -C "$BUILD_DIR" bench_daemon_warm_latency --suite bench --no-rebuild -t 5
|
|
|
|
- name: Run Bus Micro-benchmark
|
|
id: bench
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p "$BUILD_DIR/bench_results"
|
|
echo "Running yams_bus_bench (SPSC default)..."
|
|
RAW=$("$BUILD_DIR"/src/benchmarks/yams_bus_bench)
|
|
echo "$RAW"
|
|
# Convert key=value pairs to JSON using bash
|
|
ts=$(date -Is)
|
|
json='{"timestamp":"'"$ts"'","bench":{'
|
|
first=1
|
|
for kv in $RAW; do
|
|
case "$kv" in
|
|
*=*)
|
|
key="${kv%%=*}"
|
|
val="${kv#*=}"
|
|
if [ $first -eq 0 ]; then json="$json,"; else first=0; fi
|
|
json="$json\"$key\":\"$val\""
|
|
;;
|
|
esac
|
|
done
|
|
json="$json}}"
|
|
printf '%s\n' "$json" > "$BUILD_DIR/bench_results/bus_bench.json"
|
|
echo "Wrote bench_results/bus_bench.json"
|
|
|
|
- name: Run API Benchmarks
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
echo "Running yams_api_benchmarks..."
|
|
( cd "$BUILD_DIR" && ./tests/benchmarks/yams_api_benchmarks ) || exit 1
|
|
|
|
- name: Run Search Benchmarks
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
echo "Running yams_search_benchmarks..."
|
|
( cd "$BUILD_DIR" && ./tests/benchmarks/yams_search_benchmarks ) || exit 1
|
|
|
|
- name: Run Tree Diff Benchmarks (PBI-043)
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
echo "Running tree_diff_benchmarks..."
|
|
( cd "$BUILD_DIR" && ./tests/benchmarks/tree_diff_benchmarks ) || exit 1
|
|
|
|
- name: Regression Check (API)
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 tests/scripts/check_regression.py \
|
|
"$BUILD_DIR/bench_results/api_benchmarks.json" \
|
|
tests/benchmarks/baseline/api_benchmarks.baseline.json \
|
|
--threshold 0.5 \
|
|
--output "$BUILD_DIR/bench_results/api_benchmarks_regression.json" \
|
|
--fail-on-regression
|
|
|
|
- name: Regression Check (Search)
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 tests/scripts/check_regression.py \
|
|
"$BUILD_DIR/bench_results/search_benchmarks.json" \
|
|
tests/benchmarks/baseline/search_benchmarks.baseline.json \
|
|
--threshold 0.5 \
|
|
--output "$BUILD_DIR/bench_results/search_benchmarks_regression.json" \
|
|
--fail-on-regression
|
|
|
|
- name: Regression Check (Tree Diff - PBI-043)
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 tests/scripts/check_regression.py \
|
|
"$BUILD_DIR/bench_results/tree_diff_benchmark_results.json" \
|
|
tests/benchmarks/baseline/tree_diff_benchmarks.baseline.json \
|
|
--threshold 0.5 \
|
|
--output "$BUILD_DIR/bench_results/tree_diff_benchmarks_regression.json" \
|
|
--fail-on-regression
|
|
|
|
- name: Summarize Benchmarks in Job Summary
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
SUMMARY_FILE="$GITHUB_STEP_SUMMARY"
|
|
{
|
|
echo "### Bench Results"
|
|
if [ -d "$BUILD_DIR/bench_results" ] && ls "$BUILD_DIR/bench_results"/*.json >/dev/null 2>&1; then
|
|
for json in "$BUILD_DIR/bench_results"/*.json; do
|
|
echo
|
|
echo "#### $(basename "$json")"
|
|
echo '```json'
|
|
sed -e 's/[[:cntrl:]]//g' "$json" | head -c 120000 || true
|
|
echo
|
|
echo '```'
|
|
done
|
|
else
|
|
echo "_No bench_results found._"
|
|
fi
|
|
} >> "$SUMMARY_FILE"
|
|
|
|
- name: Upload Benchmark Artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: nightly-benchmarks-${{ github.run_number }}
|
|
path: |
|
|
${{ env.BUILD_DIR }}/bench_results/bus_bench.json
|
|
${{ env.BUILD_DIR }}/bench_results/api_benchmarks.json
|
|
${{ env.BUILD_DIR }}/bench_results/api_benchmark_report.json
|
|
${{ env.BUILD_DIR }}/bench_results/api_benchmark_report.md
|
|
${{ env.BUILD_DIR }}/bench_results/search_benchmarks.json
|
|
${{ env.BUILD_DIR }}/bench_results/search_benchmark_report.json
|
|
${{ env.BUILD_DIR }}/bench_results/search_benchmark_report.md
|
|
${{ env.BUILD_DIR }}/bench_results/api_benchmarks_regression.json
|
|
${{ env.BUILD_DIR }}/bench_results/search_benchmarks_regression.json
|
|
${{ env.BUILD_DIR }}/bench_results/tree_diff_benchmark_results.json
|
|
${{ env.BUILD_DIR }}/bench_results/tree_diff_benchmarks_regression.json
|
|
retention-days: 7
|