Skip to content

runtime: expose batch_size_cap as an overridable LeanVec build parameter (SVS-164) - #393

Draft
yuejiaointel wants to merge 2 commits into
mainfrom
svs164-batch-size-cap-param
Draft

yuejiaointel wants to merge 2 commits into
mainfrom
svs164-batch-size-cap-param

Conversation

@yuejiaointel

@yuejiaointel yuejiaointel commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

SVS-164 found that Milvus's SVS LeanVec index build holds a batch_size_cap-sized combined transform buffer during reduce(). Lowering the default from 1,000,000 to 100,000 meaningfully reduces build-time peak memory (companion change in the innersource libraries.ai.vector-search.svs repo, not in this repo).

This PR adds additive, ABI-compatible overloads that take batch_size_cap as a caller-settable argument, for both the static and the dynamic build (training-data variants):

  • VamanaIndexLeanVec::build(..., training_data, params, default_search_params, batch_size_cap): static Vamana. This is the path current Milvus uses, since knowhere #1749 added svs_is_static (default true).
  • DynamicVamanaIndexLeanVec::build(..., training_data, params, default_search_params, dynamic_index_params, batch_size_cap): dynamic Vamana.

Both are threaded through the respective LeanVec impl into StorageFactory<LeanVecStorageType>. All existing overloads are untouched, and each new overload has a matching #else (no LVQ/LeanVec) stub. This follows the repo's append-only ABI convention (see #385, #388).

Evidence (from the companion default-value change)

Note: the e2e numbers below were measured on Milvus's old dynamic Vamana path (knowhere v3.0.1, which predates svs_is_static). Static-path e2e numbers on current Milvus master are pending. The bare-metal sweep builds a static index directly, so it is not affected.

  • Milvus/vdbbench e2e, Cohere-1M/768D, matched from-source build: optimize-phase peak RSS 11.6 GiB (cap=1,000,000) → 8.8 GiB (cap=100,000). That is parity with HNSW FP16 (8.9 GiB) and 1.21x HNSW SQ8 (down from 1.59x unpatched).
  • Generalizes to 2x the dimensionality: dbpedia 900K rows × 1536D, optimize peak 11.8 GiB at cap=100,000 vs 16.9 GiB at cap=1,000,000. No crash, no runaway memory.
  • Bare-metal svs_benchmark sweep (n=2/arm): peak memory reaches its floor at cap=100,000 and stays flat down to 10K. Build time reaches its floor at cap=500,000 and stays flat down to 10K. Only cap=1,000,000 is a slow outlier (+21%).

How to verify

cmake -B build -DSVS_BUILD_CPP_RUNTIME_BINDINGS=ON -DSVS_BUILD_RUNTIME_TESTS=ON -DSVS_EXPERIMENTAL_LEANVEC=ON ...
cmake --build build --target svs_runtime_test -j$(nproc)
./build/ScalableVectorSearch/bindings/cpp/tests/svs_runtime_test "[runtime]"   # full suite: 1456 assertions / 41 cases pass
./build/.../svs_runtime_test "StaticIndexLeanVecWithTrainingDataCustomBatchSizeCap"
./build/.../svs_runtime_test "LeanVecWithTrainingDataPointerCustomBatchSizeCap"

Both new tests use batch_size_cap=7 against test_n=100. That forces reduce() through multiple uneven-remainder batches, a path no existing LeanVec test exercises because their dataset is smaller than any previously used cap. The #else stubs were also checked with a -fsyntax-only compile without SVS_RUNTIME_HAVE_LVQ_LEANVEC.

Not in scope

Exposing this as a knowhere index-build param (svs_leanvec_batch_size_cap in SvsVamanaLeanVecConfig, passed to both static and dynamic IndexSVSVamanaLeanVec::create_impl branches) is a follow-up that depends on this PR.

🤖 Generated with Claude Code

yuejiaointel and others added 2 commits September 23, 2026 22:42
…ter (SVS-164)

Adds one new, additive overload of DynamicVamanaIndexLeanVec::build (the
training-data variant used for OOD LeanVec builds) that threads
batch_size_cap through as a caller-settable argument, instead of it only
being reachable by recompiling libsvs with a different default. All 4
existing overloads are untouched -- ABI-compatible, matching this repo's
append-only-virtuals convention (see #385, #388).

batch_size_cap itself (default 100'000, lowered from 1'000'000) was already
validated end-to-end this session; this change only adds a way to override
it without a rebuild. Milvus/knowhere config-schema exposure is a natural
follow-up, not included here.

New regression test (LeanVecWithTrainingDataPointerCustomBatchSizeCap) uses
batch_size_cap=7 against test_n=100 to force reduce() through multiple,
uneven-remainder batches -- the code path every other LeanVec test in this
file never exercises, since their built-in dataset size is smaller than any
cap value previously in use.

Verified locally: full [runtime] suite passes (1452 assertions, 40 cases,
zero regressions vs the unpatched build), new test passes (4 assertions).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…d (SVS-164)

Adds the same additive batch_size_cap overload to the static
VamanaIndexLeanVec::build (training-data variant) and threads it through
VamanaIndexLeanVecImpl into StorageFactory. Existing overloads are
unchanged. Current knowhere builds static Vamana by default
(svs_is_static), so this is the path Milvus uses.

Adds StaticIndexLeanVecWithTrainingDataCustomBatchSizeCap, mirroring the
dynamic test. Also clang-formats the dynamic #else stub.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant