|
1 | | -# 🧪 LEANN Benchmarks & Testing |
| 1 | +# LEANN Benchmarks |
2 | 2 |
|
3 | | -This directory contains performance benchmarks and comprehensive tests for the LEANN system, including backend comparisons and sanity checks across different configurations. |
| 3 | +This directory contains benchmark scripts and data-dependent evaluation suites for LEANN. The |
| 4 | +canonical benchmark inventory now lives in [docs/benchmarks.md](../docs/benchmarks.md). |
4 | 5 |
|
5 | | -## 📁 Test Files |
| 6 | +## Quick Starts |
6 | 7 |
|
7 | | -### `diskann_vs_hnsw_speed_comparison.py` |
8 | | -Performance comparison between DiskANN and HNSW backends: |
9 | | -- ✅ **Search latency** comparison with both backends using recompute |
10 | | -- ✅ **Index size** and **build time** measurements |
11 | | -- ✅ **Score validity** testing (ensures no -inf scores) |
12 | | -- ✅ **Configurable dataset sizes** for different scales |
| 8 | +Run a small backend comparison: |
13 | 9 |
|
14 | 10 | ```bash |
15 | | -# Quick comparison with 500 docs, 10 queries |
16 | | -python benchmarks/diskann_vs_hnsw_speed_comparison.py |
17 | | - |
18 | | -# Large-scale comparison with 2000 docs, 20 queries |
19 | | -python benchmarks/diskann_vs_hnsw_speed_comparison.py 2000 20 |
20 | | -``` |
21 | | - |
22 | | -### `test_distance_functions.py` |
23 | | -Tests all supported distance functions across DiskANN backend: |
24 | | -- ✅ **MIPS** (Maximum Inner Product Search) |
25 | | -- ✅ **L2** (Euclidean Distance) |
26 | | -- ✅ **Cosine** (Cosine Similarity) |
27 | | - |
28 | | -```bash |
29 | | -uv run python tests/sanity_checks/test_distance_functions.py |
| 11 | +uv run python benchmarks/diskann_vs_hnsw_speed_comparison.py |
30 | 12 | ``` |
31 | 13 |
|
32 | | -### `test_l2_verification.py` |
33 | | -Specifically verifies that L2 distance is correctly implemented by: |
34 | | -- Building indices with L2 vs Cosine metrics |
35 | | -- Comparing search results and score ranges |
36 | | -- Validating that different metrics produce expected score patterns |
| 14 | +Compare LEANN storage usage against a FAISS baseline: |
37 | 15 |
|
38 | 16 | ```bash |
39 | | -uv run python tests/sanity_checks/test_l2_verification.py |
| 17 | +uv run python benchmarks/compare_faiss_vs_leann.py |
40 | 18 | ``` |
41 | 19 |
|
42 | | -### `test_sanity_check.py` |
43 | | -Comprehensive end-to-end verification including: |
44 | | -- Distance function testing |
45 | | -- Embedding model compatibility |
46 | | -- Search result correctness validation |
47 | | -- Backend integration testing |
| 20 | +Run the synthetic, model-free code-context expansion benchmark: |
48 | 21 |
|
49 | 22 | ```bash |
50 | | -uv run python tests/sanity_checks/test_sanity_check.py |
| 23 | +uv run python benchmarks/benchmark_code_context.py \ |
| 24 | + --modules 1000 \ |
| 25 | + --warmups 1 \ |
| 26 | + --repeats 5 \ |
| 27 | + --data-source synthetic-code-context \ |
| 28 | + --data-revision 2026-06-03-fixture \ |
| 29 | + --format markdown \ |
| 30 | + --json-output benchmark-results/code-context.json \ |
| 31 | + --markdown-output benchmark-results/code-context.md |
51 | 32 | ``` |
52 | 33 |
|
53 | | -## 🎯 What These Tests Verify |
| 34 | +This benchmark fixture exercises direct related-code matches, direct immediate-base inherited |
| 35 | +calls, and bounded one-hop exact-call expansion. Its JSON and Markdown artifacts report data |
| 36 | +source/revision, local environment provenance, direct related counts, inherited related counts, |
| 37 | +one-hop related counts, expected inherited/one-hop coverage, unique related passages, |
| 38 | +cap/truncation accounting, command provenance, and timing summaries. |
54 | 39 |
|
55 | | -### ✅ Distance Function Support |
56 | | -- All three distance metrics (MIPS, L2, Cosine) work correctly |
57 | | -- Score ranges are appropriate for each metric type |
58 | | -- Different metrics can produce different rankings (as expected) |
| 40 | +The curated documentation report for this benchmark lives in |
| 41 | +[docs/code_context_benchmark.md](../docs/code_context_benchmark.md). |
59 | 42 |
|
60 | | -### ✅ Backend Integration |
61 | | -- DiskANN backend properly initializes and builds indices |
62 | | -- Graph construction completes without errors |
63 | | -- Search operations return valid results |
| 43 | +Run the main retrieval evaluation driver: |
64 | 44 |
|
65 | | -### ✅ Embedding Pipeline |
66 | | -- Real-time embedding computation works |
67 | | -- Multiple embedding models are supported |
68 | | -- ZMQ server communication functions correctly |
69 | | - |
70 | | -### ✅ End-to-End Functionality |
71 | | -- Index building → searching → result retrieval pipeline |
72 | | -- Metadata preservation through the entire flow |
73 | | -- Error handling and graceful degradation |
74 | | - |
75 | | -## 🔍 Expected Output |
76 | | - |
77 | | -When all tests pass, you should see: |
78 | | - |
79 | | -``` |
80 | | -📊 测试结果总结: |
81 | | - mips : ✅ 通过 |
82 | | - l2 : ✅ 通过 |
83 | | - cosine : ✅ 通过 |
84 | | -
|
85 | | -🎉 测试完成! |
| 45 | +```bash |
| 46 | +uv run benchmarks/run_evaluation.py |
86 | 47 | ``` |
87 | 48 |
|
88 | | -## 🐛 Troubleshooting |
| 49 | +This command treats an incomplete `benchmarks/data/` tree, including a README-only checkout or an |
| 50 | +`indices/` tree without any `.index` artifact, as missing benchmark data and downloads the public |
| 51 | +data pack. The repository-provided prebuilt indexes are large; check local disk capacity before |
| 52 | +relying on the automatic download path. |
89 | 53 |
|
90 | | -### Common Issues |
| 54 | +For larger retrieval runs after data has been downloaded: |
91 | 55 |
|
92 | | -**Import Errors**: Ensure you're running from the project root: |
93 | 56 | ```bash |
94 | | -cd /path/to/leann |
95 | | -uv run python tests/sanity_checks/test_distance_functions.py |
| 57 | +uv run benchmarks/run_evaluation.py benchmarks/data/indices/rpj_wiki/rpj_wiki \ |
| 58 | + --dataset rpj_wiki \ |
| 59 | + --data-source LEANN-RAG/leann-rag-evaluation-data \ |
| 60 | + --data-revision 2026-06-02-download \ |
| 61 | + --num-queries 2000 \ |
| 62 | + --top-k 3 \ |
| 63 | + --complexity 120 \ |
| 64 | + --format markdown \ |
| 65 | + --json-output benchmark-results/retrieval-rpj-wiki.json \ |
| 66 | + --markdown-output benchmark-results/retrieval-rpj-wiki.md |
96 | 67 | ``` |
97 | 68 |
|
98 | | -**Memory Issues**: Reduce graph complexity for resource-constrained systems: |
99 | | -```python |
100 | | -builder = LeannBuilder( |
101 | | - backend_name="diskann", |
102 | | - graph_degree=8, # Reduced from 16 |
103 | | - complexity=16 # Reduced from 32 |
104 | | -) |
105 | | -``` |
| 69 | +Retrieval evaluation is search-only by default. Use `--run-llm` only when generation should be |
| 70 | +included as opt-in metadata outside retrieval latency. Retrieval artifacts include per-query result |
| 71 | +IDs, golden IDs, and duplicate-text counters so reviewers can audit text-overlap recall when passage |
| 72 | +ID schemes differ across indexes. CLI-generated artifacts also record SHA256 hashes for the query |
| 73 | +and ground-truth files plus shell-quoted script command arguments. |
106 | 74 |
|
107 | | -**ZMQ Port Conflicts**: The tests use different ports to avoid conflicts, but you may need to kill existing processes: |
108 | | -```bash |
109 | | -pkill -f "embedding_server" |
110 | | -``` |
| 75 | +Retrieval, query-log, and code-context artifacts share the same timing-statistics helper. p95 is the |
| 76 | +lower nearest-rank observed sample from sorted timings, so it is deterministic and comparable across |
| 77 | +reviewable benchmark reports. The standalone BM25 and DiskANN baseline scripts use the same |
| 78 | +observed-sample percentile helpers for their latency report fields. |
111 | 79 |
|
112 | | -## 📊 Performance Expectations |
| 80 | +Run one retrieval manifest across multiple prebuilt backend indexes: |
113 | 81 |
|
114 | | -### Typical Timing (3 documents, consumer hardware): |
115 | | -- **Index Building**: 2-5 seconds per distance function |
116 | | -- **Search Query**: 50-200ms |
117 | | -- **Recompute Mode**: 5-15 seconds (higher accuracy) |
118 | | - |
119 | | -### Memory Usage: |
120 | | -- **Index Storage**: ~1-2 MB per distance function |
121 | | -- **Runtime Memory**: ~500MB (including model loading) |
| 82 | +```bash |
| 83 | +uv run python benchmarks/compare_retrieval_backends.py benchmark-results/retrieval-comparison.json \ |
| 84 | + --format markdown \ |
| 85 | + --json-output benchmark-results/retrieval-comparison-summary.json \ |
| 86 | + --markdown-output benchmark-results/retrieval-comparison-summary.md |
| 87 | +``` |
122 | 88 |
|
123 | | -## 🔗 Integration with CI/CD |
| 89 | +The comparison manifest keeps dataset, query file, ground truth, `top_k`, complexity, and batch |
| 90 | +size identical across runs. The combined JSON/Markdown artifacts report per-run backend, |
| 91 | +passage-ID scheme, embedding model/mode, recall@k, hit rate@k, latency, storage bytes, query file |
| 92 | +hash, ground-truth file hash, shell-quoted script command arguments, missing result-ID counts, and |
| 93 | +duplicate result/golden text counters. |
| 94 | +See [docs/benchmarks.md](../docs/benchmarks.md) for the manifest fields and a complete example. |
124 | 95 |
|
125 | | -These tests are designed to be run in automated environments: |
| 96 | +Summarize query logs with optional ground truth and storage accounting: |
126 | 97 |
|
127 | | -```yaml |
128 | | -# GitHub Actions example |
129 | | -- name: Run Sanity Checks |
130 | | - run: | |
131 | | - uv run python tests/sanity_checks/test_distance_functions.py |
132 | | - uv run python tests/sanity_checks/test_l2_verification.py |
| 98 | +```bash |
| 99 | +uv run python benchmarks/summarize_query_log.py queries.jsonl \ |
| 100 | + --ground-truth ground_truth.json \ |
| 101 | + --index-path .leann/indexes/my-index/documents.leann \ |
| 102 | + --data-source my-dataset \ |
| 103 | + --data-revision 2026-06-02-download \ |
| 104 | + --format markdown \ |
| 105 | + --json-output benchmark-results/my-index-summary.json \ |
| 106 | + --markdown-output benchmark-results/my-index-summary.md |
133 | 107 | ``` |
134 | 108 |
|
135 | | -The tests are deterministic and should produce consistent results across different platforms. |
| 109 | +`--format` controls stdout. Use `--json-output` and `--markdown-output` to write durable review |
| 110 | +artifacts in the same run. Query-log summaries include latency mean/median/p95/min/max when |
| 111 | +available plus counters for records with missing result IDs, total missing result IDs, missing |
| 112 | +latency, missing search mode, missing backend metadata, and shell-quoted script command arguments. |
| 113 | + |
| 114 | +The `benchmark-results/` directory is ignored by git and is the default scratch location for local |
| 115 | +summary artifacts. Commit only curated reports with full dataset, hardware, and command context. |
| 116 | + |
| 117 | +## Suites |
| 118 | + |
| 119 | +- `bm25_diskann_baselines/`: Natural Questions BM25 and DiskANN search-only baselines that require |
| 120 | + externally synced artifacts, report latency with the shared observed-sample percentile helpers, |
| 121 | + and can write JSON reports with query hashes, timing scope, recursive storage bytes, settings, |
| 122 | + command arguments, and environment provenance. |
| 123 | +- `contextbench/`: trace-driven code-assistant benchmark tooling. |
| 124 | +- `enron_emails/`: retrieval and generation evaluation on the Enron email corpus. |
| 125 | +- `financebench/`: financial document question-answering benchmark. |
| 126 | +- `laion/`: multimodal image/text retrieval benchmark. |
| 127 | +- `update/`: update-latency and sequential-vs-offline update strategy benchmarks. |
| 128 | + |
| 129 | +Benchmark result files committed under subdirectories are reference outputs from their documented |
| 130 | +settings and hardware. Do not treat them as automatically refreshed results for the current branch |
| 131 | +unless the relevant command has been rerun. |
0 commit comments