Skip to content

bench(lite): align reproducible acceptance tools with Lite feature baseline - #2926

Open
nw9663644-eng wants to merge 103 commits into
antgroup:mainfrom
nw9663644-eng:experiment/lite-baseline-v01
Open

nw9663644-eng wants to merge 103 commits into
antgroup:mainfrom
nw9663644-eng:experiment/lite-baseline-v01

Conversation

@nw9663644-eng

@nw9663644-eng nw9663644-eng commented Sep 10, 2026 •

Copy link
Copy Markdown

Purpose

Provide reproducible benchmarks and acceptance evidence for VSAG Lite.
Closes #2888. Depends on #2904, which owns the Lite implementation, API, architecture and functional tests.

Contents

  • Data preparation for SIFT, GIST and Cohere.
  • Lite/native Full benchmarks, real-change CRUD, CPU/memory, package-size and recall checks, with regression tests.
  • A comprehensive report linking configurations, measured commits and raw results. Positive and negative results are retained.

Historical exploration tools are archived at pinned commits rather than included in the current review tree. Until #2904 merges, the main-target diff also includes its feature dependency.

Validation

  • Lite Release: RaBitQ ON 5/5, OFF 4/4; benchmark targets compile.
  • Three native Full consumers compile against the recorded historical SDK.
  • Python guards: 26 passed, 2 skipped with optional dependencies, including four normal Cohere unittest cases. CI installs these dependencies and checks imports before discovery.
  • Latest SIFT/GIST resident run: 270,000 mutation calls and 270,000 interleaved queries; raw verification passed.

These are recorded local results, not a claim that hosted CI has passed. Restoring Cohere tools did not rerun Cohere performance.

Results and Limits

Defined package profiles and some load/memory comparisons show clear benefits. RaBitQ is not consistently faster than FP16; GIST dynamic quality, a unified same-quality/SIMD-aligned Full comparison and long-duration 100k/Cohere validation remain open. Historical and candidate results are explicitly separated from current production results.

Report

Read the comprehensive acceptance report.

Review follow-up: stream-position validation, consistent percentile bounds, compiled helper regressions and file-hash naming were addressed. Native Full was smoke-tested with dimension 16 and k=3 to confirm its result-layout contract; 13 representative inline threads received evidence-based replies. Existing historical measurements and Lite implementation are unchanged. Other historical/duplicate comments have not all been resolved.

Add an independent Lite shared-library target with FP32 squared-L2 CRUD,
versioned snapshots, Catch2 tests, an installed consumer, and bilingual docs.
Reuse the existing generic distance kernel and error contracts.
Graph search, quantization, mmap, and Full format compatibility remain out of scope.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Run focused formatting, expanded clang-tidy, Debug tests, the 100k-vector
workflow, Release dependency inspection, and an installed consumer in CI.
Address the additional public-header and test lint findings.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Harden the growth edge case, make dense-slot invariants explicit, use a stable heap comparator, and provide an installed static Lite archive with CI and documentation coverage.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Use a const reference when serializing IDs and simplify signed ID decoding with an object-representation copy.

Signed-off-by: Nannan Wang <1794949109@qq.com>

Assisted-by: Codex:GPT-5
@vsag-bot

vsag-bot commented Sep 10, 2026 •

Copy link
Copy Markdown
Collaborator

/label status/waiting-for-review
/waiting-on reviewer
/request-review @jiaweizone
/request-review @wxyucs
/request-review @inabao

@pull-request-size pull-request-size Bot added the size/XXL 1000+ changed lines label Sep 10, 2026
@mergify mergify Bot added area/ci CI/CD, build configuration, and automation CI/CD、构建配置与自动化 area/docs Website and repository documentation 网站与仓库文档 module/api Public C++ API and headers 公共 C++ API 与头文件 labels Sep 10, 2026
@mergify

mergify Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 1 of 2 protections blocking · waiting on 🙋 you

Protection Waiting on
🔴 Require kind label 🙋 you
🟢 Require version label —

🔴 Require kind label

Waiting for

  • label~=^kind/
This rule is failing.
  • label~=^kind/

Show 1 satisfied protection

🟢 Require version label

  • label~=^version/

Comment thread src/lite/index.cpp Outdated
Comment thread lite/benchmark/main.cpp Outdated
Comment thread lite/benchmark/main.cpp
Comment thread lite/benchmark/main.cpp
Comment thread lite/benchmark/main.cpp
Comment thread lite/benchmark/run_baseline.sh Outdated
@nw9663644-eng nw9663644-eng changed the title Experiment/li`bench(lite): add reproducible baseline and CRUD stability experimentste baseline v01 bench(lite): add reproducible baseline and CRUD stability experiments Sep 10, 2026

@LHT129 LHT129 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have completed a thorough review of all 16 changed files (2,040 additions). The code quality is high across the board.

Summary of findings:

The existing inline comments from @LHT129 already cover the notable points:

  • src/lite/index.cpp: float value copy vs const auto& consistency in Save loop
  • lite/benchmark/main.cpp: percentile() pass-by-value copies the vector on every call
  • lite/benchmark/main.cpp: peak_rss_kib() uses getrusage(RUSAGE_SELF) — ru_maxrss is in KiB on Linux but bytes on macOS (documented as Linux-only, so not a practical issue)
  • lite/benchmark/run_baseline.sh: lscpu is Linux-specific (consistent with the documented Linux x86_64 scope)

Additional observations (no new inline comments needed):

  1. The make_vector refactoring in this commit (from XOR-combined mix calls to chained mix calls) improves clarity and matches full_main.cpp. Good change.

  2. src/lite/index.cpp — The Index::Load function uses return std::move(*created); where the move is redundant (the compiler would move automatically from the dereferenced unique_ptr). This is harmless but unnecessary.

  3. lite/benchmark/main.cpp — run_stability calls peak_rss_kib() per round, which reports the cumulative process-wide ru_maxrss. For a stability experiment this is actually the desired behavior (it detects monotonic memory growth), so the semantics are correct for the use case.

  4. The snapshot format (VSAGLT01) is well-designed with explicit little-endian byte encoding, bounds validation before allocation, and rejection of truncation, trailing bytes, duplicate IDs, and non-finite values. The test coverage for malformed snapshots is thorough.

  5. The Add implementation correctly uses geometric capacity growth and publishes the slot map entry only after all potentially-throwing vector operations succeed — this is proper exception safety.

  6. The CI workflow (.github/workflows/lite.yml) correctly verifies that libvsag-lite.so does not link against libvsag.so, which is the key isolation guarantee.

No blocking issues found. The existing inline comments are all [note] or [suggestion] level and none should block merging.

Comment thread lite/benchmark/main.cpp
Comment thread lite/benchmark/run_comparison.sh Outdated
Comment thread lite/benchmark/full_main.cpp Outdated
Comment thread lite/benchmark/full_main.cpp
}
return neighbors;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] The loop below iterates k times unconditionally, reading GetIds()[i] and GetDistances()[i] without verifying that the result actually contains k elements. Combined with the GetDim() check on line 151 (which validates the vector dimension, not the result count), this can read out-of-bounds if KnnSearch returns fewer than k results.

While the benchmark currently operates on indices that always have enough vectors to satisfy k, a future change or an unexpected internal error could trigger undefined behavior here.

Consider either:

  • Fixing line 151 to use GetNumElements() (as noted in the critical comment above), which would make this loop safe by failing early, or
  • Adding an explicit bounds check before the loop:
require(static_cast<uint64_t>((*result)->GetNumElements()) >= k, "too few search results");

Current:

    for (uint64_t i = 0; i < k; ++i) {
        neighbors.push_back({(*result)->GetIds()[i], (*result)->GetDistances()[i]});
    }

run(const std::string& directory, const std::string& snapshot) {
const auto base_path = directory + "/base.fvecs";
const auto query_path = directory + "/queries.fvecs";
const auto truth_path = directory + "/groundtruth.ivecs";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[critical] The percentile function in dataset_main.cpp is missing the std::min guard present in the same function in main.cpp and full_main.cpp. When fraction=0 and values is non-empty, rank = ceil(0) - 1 = 0 - 1 underflows to UINT64_MAX, causing an out-of-bounds access on values[rank].

Compare with the safe version in main.cpp:

return values[std::min<uint64_t>(rank, values.size() - 1)];

Current (dataset_main.cpp):

double
percentile(std::vector<double> values, double fraction) {
    std::sort(values.begin(), values.end());
    const auto rank =
        static_cast<uint64_t>(std::ceil(fraction * static_cast<double>(values.size()))) - 1;
    return values[rank];
}

Suggested fix:

double
percentile(std::vector<double> values, double fraction) {
    std::sort(values.begin(), values.end());
    const auto rank =
        static_cast<uint64_t>(std::ceil(fraction * static_cast<double>(values.size()))) - 1;
    return values[std::min<uint64_t>(rank, values.size() - 1)];
}

Note: fraction=0 is a valid input for P0 percentile, and while the current callers always pass 0.50 or 0.99, this is a latent bug that could be triggered by future changes or refactoring.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in e37ea30. The current helpers already reject empty inputs/non-finite or out-of-range fractions and use max(1, ceil(f*n))-1, so P0 cannot underflow. Added the same upper clamp to all dataset variants for consistency. The new compiled-helper regression executes all five real implementations for P0/P50/P99/P100, singleton/empty input and invalid fractions; input samples remain unchanged. No historical measurements were recomputed.

Comment thread lite/benchmark/dataset_main.cpp Outdated
std::ifstream input(path, std::ios::binary | std::ios::ate);
require(static_cast<bool>(input), "input open failed");
const auto size = input.tellg();
require(size > 0 and size % (sizeof(int32_t) + sizeof(T) * expected_dim) == 0,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[suggestion] In read_records, const auto size = input.tellg() deduces size as std::streampos, which is a signed type. The subsequent size % (sizeof(int32_t) + sizeof(T) * expected_dim) performs a signed modulo with an unsigned operand, and size > 0 compares a signed value. While this works correctly on typical platforms for valid inputs, using an explicit static_cast<uint64_t> would make the intent clearer and avoid signed/unsigned comparison warnings.

Current:

const auto size = input.tellg();
require(size > 0 and size % (sizeof(int32_t) + sizeof(T) * expected_dim) == 0,
        "invalid input file length");
const auto count = static_cast<uint64_t>(size / (sizeof(int32_t) + sizeof(T) * expected_dim));

Suggested:

const auto size = static_cast<uint64_t>(input.tellg());
require(size > 0 and size % (sizeof(int32_t) + sizeof(T) * expected_dim) == 0,
        "invalid input file length");
const auto count = size / (sizeof(int32_t) + sizeof(T) * expected_dim);

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e37ea30: reject non-positive tellg() and invalid dimensions before converting to uint64_t, then use unsigned record-byte arithmetic. Applied to both dataset consumers. Compiled-reader regressions cover valid rows, empty/truncated files and invalid dimensions.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Document current cached incoming/safe-link policy and map required outputs
to public functionality, implementation, regressions and acceptance limits.
Separate current bilingual contracts from pinned historical experiments.
Exercise default-OFF, ON, sanitizer and coverage configurations in CI,
including installed consumers, all configured Lite units/private headers,
gcov line-union fixtures, a 90 percent gate and retained diagnostics.
Fix the private header's existing modernize-use-auto diagnostic without
changing the type or algorithm. No rejected graph policy is enabled.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Measure current PR2904 dbb2fe0 from the benchmark-only PR2926 branch. Record two datasets, three storages and three rotated fresh-process repeats, real-vector changes, interleaved deletion-aware queries, CPU/resource samples and per-round persistence checks. Preserve reproducible raw evidence and explicit final acceptance gaps.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Retain the measured PR2904 index across 20 rounds, pre-touch measurement storage, record before-persistence RSS and observed thread count. Add lifecycle parity and archive safety tests, preserve 18 fresh-process raw cohorts in a hash-verified archive, and report recall, latency and late-memory limitations without claiming hours-long acceptance.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Freshly compile consumers against current PR2904 and the hash-verified pinned native Full installation. Record two datasets, three storages, 36 builders and108 independent loaders at equal query ef512, plus raw archive, ELF footprint and independent audits. Preserve quality differences, incremental RSS and persistence costs; do not claim same-quality, fresh Full library or complete-package acceptance.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Package fresh native C++ consumers with recursive ELF dependencies, loader, launcher and license texts under a defined runtime profile. Verify relocation and package-local library maps for six storage smokes, record per-file accounting and real tar.gz bytes, and preserve exact native stdout. No production changes or certified-release/fresh-Full claims.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Build native Full core from an empty RAM build with ccache disabled, retain compilation and dependency boundaries, and audit a fresh equal-query-budget two-dataset matrix. Preserve negative results and distinguish this evidence from historical package and CRUD cohorts.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Calibrate fixed snapshots on 100 GIST queries, freeze budgets, and validate on 900 separate query rows. Preserve failed Lite quality gates, native Full comparisons, phase CPU/resource receipts, FP64 oracle agreement, and archived raw results. No production changes.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Trace the prior GIST snapshots without changing budgets or production code, reproduce all native neighbor IDs and distance bits, and retain disjoint routing/ranking loss evidence. Identify shared coverage gaps and distinguish the complete-code scan from a practical ANN quality result.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Preserve the source-backed nearest-selection candidate and paired SIFT/GIST results. Recall improves while build and query latency regress; no default adoption or complete acceptance claim.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>

Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Merge current upstream without rewriting published Lite commits. Compare coverage against the actual merge parent and validate the PR head.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
…e evidence

Merge current PR2904 feature baseline 8e82a2a without changing supported
production semantics. Keep optional acceptance tools default OFF, add audit
guard CI tests, and provide requirement-to-source/report/raw traceability.
Preserve all historical results at immutable 800a822 with per-file SHA256
manifest instead of including bulky raw output in the latest review tree.
Separate historical measurements and candidate policies from delivered code.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
@nw9663644-eng nw9663644-eng changed the title bench(lite): add baseline, CRUD and SQ8/FP16 experiments bench(lite): align reproducible acceptance tools with Lite feature baseline Oct 14, 2026
@mergify mergify Bot added the module/simd SIMD dispatch and optimized kernels SIMD 分派与优化内核 label Oct 14, 2026
…ance

Normally merge feature CI fixes and upstream ancestry. Preserve historical metric identities, publish fresh resident SIFT/GIST raw evidence, and retain unresolved quality/community gates.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
@mergify mergify Bot added the area/testing Tests, fixtures, and test infrastructure 测试、夹具与测试基础设施 label Oct 14, 2026
Retain the formal acceptance dependency closure and record immutable paths and hashes for 32 archived tools/documents. Validate Lite ON/OFF, native Full consumers, SIFT preparation and raw replay without changing production code or performance claims.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Separate current, historical and rejected-candidate results; report CRUD, CPU, native Full, package, 100k and quality limits. Restore pinned Cohere preparation and rejection fixtures with optional-dependency skip documentation.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Separate experiment conditions, before/after tables, conclusions and limits. Preserve values and distinguish historical resident records from current measurements. No production changes or new experiments.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Remove development timeline, source identifiers and audit details from the reader report while retaining evidence links. Recheck all 18 resource records, show three-trial ranges and separate query CPU from whole-test costs. Do not cherry-pick single best runs or claim failed candidates as accepted.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Require the pinned Full receipt before output creation, cover CLI failures, convert import-time assertions into four unittest cases, install optional benchmark dependencies in CI with an import gate, and clarify retained raw evidence.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Validate stream positions before unsigned conversion, make percentile bounds consistent, add compiled helper regression cases and clarify native Full result dimensions. Rename file hashes consistently across dataset preparation. No Lite implementation or historical metric changes.

Signed-off-by: Nannan Wang <1794949109@qq.com>
Assisted-by: Codex:GPT-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/ci CI/CD, build configuration, and automation CI/CD、构建配置与自动化 area/docs Website and repository documentation 网站与仓库文档 area/testing Tests, fixtures, and test infrastructure 测试、夹具与测试基础设施 module/api Public C++ API and headers 公共 C++ API 与头文件 module/simd SIMD dispatch and optimized kernels SIMD 分派与优化内核 size/XXL 1000+ changed lines version/1.1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[improve](lite): implement and optimize VSAG Lite for lightweight vector search

4 participants