PY ?= python3
CACHE_DIR := .cache/ordvec-beir
RESULTS_DIR := results/beir
FIG_DIR := $(RESULTS_DIR)/figures
QUALITY_DATASETS := scifact
PERF_DATASET := trec-covid
SPLIT := test
SMOKE_QUALITY := scifact
SMOKE_PERF_DATASET := scifact
SMOKE_SCALE_SIZES := 500 1000 2000
TOPK := 100
K_VALUES := 10 100
BATCH := 32
CANDIDATES := 500
SEED := 1
NPROC := $(shell nproc 2>/dev/null || echo 8)
SCALE_BATCH := 1
MULTI_BATCH := 32
SCALE_SIZES := 1000 3000 10000 30000 100000 170000
BENCH_METHODS := flat,hnsw,rq2,rq4,bitmap-rq2,sign-rq2
HARRIER_GGUF_REPO := mradermacher/harrier-oss-v1-0.6b-GGUF
GGUF_FILE := *Q8_0.gguf
N_GPU_LAYERS := -1
N_CTX := 2048
ENCODE_BATCH := 16
LLAMA_CMAKE_ARGS := -DGGML_CUDA=on
.PHONY: benchmark-beir benchmark-beir-smoke bench-beir-setup bench-beir-build \
bench-beir-guardrail bench-beir-quality bench-beir-scaling \
bench-beir-plot bench-beir-clean bench-beir-clean-cache
.NOTPARALLEL:
benchmark-beir: bench-beir-guardrail bench-beir-quality bench-beir-scaling bench-beir-plot
benchmark-beir-smoke:
$(MAKE) bench-beir-guardrail
$(MAKE) bench-beir-quality QUALITY_DATASETS="$(SMOKE_QUALITY)"
$(MAKE) bench-beir-scaling PERF_DATASET=$(SMOKE_PERF_DATASET) SCALE_SIZES="$(SMOKE_SCALE_SIZES)"
$(MAKE) bench-beir-plot PERF_DATASET=$(SMOKE_PERF_DATASET)
bench-beir-setup:
$(PY) -m pip install -r benchmarks/beir/requirements.txt
CMAKE_ARGS="$(LLAMA_CMAKE_ARGS)" $(PY) -m pip install \
--upgrade --force-reinstall --no-cache-dir llama-cpp-python
bench-beir-build:
cargo build --release -p beir-bench
bench-beir-guardrail:
@if grep -rnE "^[[:space:]]*(import ordvec|from ordvec)\b" benchmarks/beir --include='*.py' 2>/dev/null; then \
echo "ERROR: a benchmarks/beir/*.py file imports the ordvec Python package."; \
exit 1; \
fi
@echo "guardrail OK: no 'import ordvec' in benchmarks/beir/*.py"
bench-beir-quality: bench-beir-build
@for d in $(QUALITY_DATASETS); do \
echo "=== quality: $$d ==="; \
$(PY) benchmarks/beir/beir_prepare.py --datasets $$d --split $(SPLIT) \
--provider llamacpp --model "$(HARRIER_GGUF_REPO)" --gguf-file "$(GGUF_FILE)" \
--n-gpu-layers $(N_GPU_LAYERS) --n-ctx $(N_CTX) --batch-size $(ENCODE_BATCH) \
--cache-dir "$(CACHE_DIR)" --seed $(SEED) || exit 1; \
$(CURDIR)/target/release/beir-bench --cache-dir "$(CACHE_DIR)" --dataset $$d \
--split $(SPLIT) --top-k $(TOPK) --batch $(BATCH) --candidates $(CANDIDATES) \
--threads 1 --methods $(BENCH_METHODS) --out-dir "$(RESULTS_DIR)" || exit 1; \
$(PY) benchmarks/beir/beir_eval.py --datasets $$d --split $(SPLIT) \
--cache-dir "$(CACHE_DIR)" --runs-dir "$(RESULTS_DIR)" --k-values $(K_VALUES) \
--baseline flat --bootstrap-iters 1000 --seed $(SEED) --out-dir "$(RESULTS_DIR)" || exit 1; \
done
bench-beir-scaling: bench-beir-build
@echo "=== scaling: $(PERF_DATASET) (sizes: $(SCALE_SIZES); threaded full = $(NPROC)t) ==="
$(PY) benchmarks/beir/beir_prepare.py --datasets $(PERF_DATASET) --split $(SPLIT) \
--provider llamacpp --model "$(HARRIER_GGUF_REPO)" --gguf-file "$(GGUF_FILE)" \
--n-gpu-layers $(N_GPU_LAYERS) --n-ctx $(N_CTX) --batch-size $(ENCODE_BATCH) \
--cache-dir "$(CACHE_DIR)" --seed $(SEED)
rm -f "$(RESULTS_DIR)/$(PERF_DATASET)/timing.jsonl"
@for n in $(SCALE_SIZES); do \
echo " -- n=$$n (1 thread, single-query batch=$(SCALE_BATCH)) --"; \
$(CURDIR)/target/release/beir-bench --cache-dir "$(CACHE_DIR)" --dataset $(PERF_DATASET) \
--split $(SPLIT) --top-k $(TOPK) --batch $(SCALE_BATCH) --candidates $(CANDIDATES) \
--threads 1 --max-docs $$n --methods $(BENCH_METHODS) --out-dir "$(RESULTS_DIR)" || exit 1; \
done
@echo " -- full corpus (1 thread, single-query batch=$(SCALE_BATCH); writes topk + nDCG inputs) --"
$(CURDIR)/target/release/beir-bench --cache-dir "$(CACHE_DIR)" --dataset $(PERF_DATASET) \
--split $(SPLIT) --top-k $(TOPK) --batch $(SCALE_BATCH) --candidates $(CANDIDATES) \
--threads 1 --methods $(BENCH_METHODS) --out-dir "$(RESULTS_DIR)"
@echo " -- full corpus ($(NPROC) threads, batched batch=$(MULTI_BATCH)) --"
$(CURDIR)/target/release/beir-bench --cache-dir "$(CACHE_DIR)" --dataset $(PERF_DATASET) \
--split $(SPLIT) --top-k $(TOPK) --batch $(MULTI_BATCH) --candidates $(CANDIDATES) \
--threads $(NPROC) --methods $(BENCH_METHODS) --out-dir "$(RESULTS_DIR)"
$(PY) benchmarks/beir/beir_eval.py --datasets $(PERF_DATASET) --split $(SPLIT) \
--cache-dir "$(CACHE_DIR)" --runs-dir "$(RESULTS_DIR)" --k-values $(K_VALUES) \
--baseline flat --bootstrap-iters 1000 --seed $(SEED) --out-dir "$(RESULTS_DIR)"
bench-beir-plot:
$(PY) benchmarks/beir/beir_plot.py --runs-dir "$(RESULTS_DIR)" \
--scaling-dataset $(PERF_DATASET) --bar-dataset $(PERF_DATASET) \
--scaling-threads 1 --scaling-batch $(SCALE_BATCH) \
--bar-single-threads 1 --bar-single-batch $(SCALE_BATCH) \
--bar-multi-threads $(NPROC) --bar-multi-batch $(MULTI_BATCH) \
--out-dir "$(FIG_DIR)"
bench-beir-clean:
find $(RESULTS_DIR) -name "*.topk.jsonl" -delete
find $(RESULTS_DIR) -name "*.summary.json" -delete
find $(RESULTS_DIR) -name "timing.jsonl" -delete
bench-beir-clean-cache:
rm -rf $(CACHE_DIR)