Skip to content

perf(hgraph): optimize RaBitQ split construction#2460

Open
LightWant wants to merge 7 commits into
antgroup:mainfrom
LightWant:feat/rabitq-build-accelerationV2
Open

perf(hgraph): optimize RaBitQ split construction#2460
LightWant wants to merge 7 commits into
antgroup:mainfrom
LightWant:feat/rabitq-build-accelerationV2

Conversation

@LightWant

@LightWant LightWant commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Change Type

  • Bug fix
  • New feature
  • Improvement/Refactor
  • Documentation
  • CI/Build/Infra

Linked Issue

Not required for kind/improvement.

What Changed

  • Use transient per-dimension scalar RaBitQ codes during the first fast rabitq_split HGraph build, avoiding split x/y storage reads while constructing the graph.
  • Add scalar query-code and code-code compute paths plus SIMD packing/inner-product kernels for AVX2, AVX-512, NEON, SVE, and generic backends.
  • Finalize the build by packing the transient scalar codes directly into the existing x-bit and supplement datacells, then release all temporary storage.
  • Drain every accepted parallel build task on submission or task failure before optimized-build buffers are released; reserve future bookkeeping capacity before submission.
  • Preserve the public API, serialized index layout, unsupported non-empty Add behavior, and cleanup semantics on partial task submission failures.
  • Remove unrelated runtime stage timing, environment switches, and hot-path atomic counters from HGraph construction.
  • Document the optimized build lifecycle and temporary memory overhead in English and Chinese.

Test Evidence

  • make fmt
  • make lint
  • make test
  • make cov, run tests, and collect coverage
  • Other (described below)

Test details:

clang-format-15 --dry-run --Werror: passed
git diff --check: passed
ASan enqueue-failure regression: 1 test case, 3 assertions passed
ASan RaBitQ optimized-build unit tests: 6 test cases, 5,920 assertions passed
ASan HGraph RaBitQ Split functional tests: 7 test cases, 10,071 assertions passed
Release eval_performance rebuild: passed
GIST1M 32-thread split 3+5 build: 63.865 s, 15,658 TPS
GIST1M 32-thread RaBitQ3+SQ8 build: 148.818 s, 6,720 TPS
GIST1M split search Recall@10 / QPS: ef100 0.8275 / 14,848; ef200 0.9022 / 10,032; ef400 0.9465 / 6,305

Compatibility Impact

  • API/ABI compatibility: none
  • Behavior changes: only the internal first-build path for rabitq_split + fast_encode_rabitq=true; final storage and search behavior remain unchanged

Performance and Concurrency Impact

  • Performance impact: improved HGraph construction by using contiguous scalar codes and SIMD inner products before the final split packing pass
  • Concurrency/thread-safety impact: final datacells and future bookkeeping are fully preallocated; accepted tasks are drained if enqueue or task execution fails

Documentation Impact

  • No docs update needed
  • Updated docs:
    • README.md
    • DEVELOPMENT.md
    • CONTRIBUTING.md
    • Other: docs/docs/{en,zh}/src/quantization/rabitq.md

Risk and Rollback

  • Risk level: medium
  • Rollback plan: revert commit 3404d02 to restore the previous temporary-SQ8/split build flow

Checklist

  • Issue link is not required for kind/improvement
  • I have added/updated tests for new behavior and regressions
  • I have considered API compatibility impact
  • I have updated docs for the build behavior change
  • My commit message follows project conventions and includes DCO/Assisted-by trailers

@vsag-bot

vsag-bot commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

/label S-waiting-on-review
/waiting-on reviewer
/request-review @jiaweizone
/request-review @wxyucs
/request-review @inabao
/request-review @LHT129

@mergify

mergify Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 2 merge protections satisfied — ready to merge.

Show 2 satisfied protections

🟢 Require kind label

  • label~=^kind/

🟢 Require version label

  • label~=^version/

@LightWant LightWant added kind/improvement Optimizations, UX polish, or minor improvements 性能优化、体验打磨或细节改良 version/1.1 labels Jul 17, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an optimized scalar-code build path for HGraph with split RaBitQ (when fast_encode_rabitq=true). It first encodes vectors into temporary scalar codes and code sums to accelerate distance calculations during graph construction, then packs them into bit planes in parallel. The changes also add optimized SIMD kernels (AVX2, AVX512, NEON) for these operations and include comprehensive tests. The review feedback highlights a critical data race on optimized_build_code_sums_ during parallel insertions, a backward compatibility break caused by removing supplement_io_type_ serialization, and a recommendation to delete copy operations on OptimizedBuildGuard to prevent accidental copying.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/datacell/rabitq_split_datacell.h Outdated
Comment thread src/datacell/rabitq_split_datacell.h
Comment thread src/algorithm/hgraph/hgraph_build.cpp Outdated
@LightWant
LightWant force-pushed the feat/rabitq-build-accelerationV2 branch from 41c80c5 to ff26979 Compare July 18, 2026 09:20
@LightWant LightWant changed the title perf(hgraph): accelerate RaBitQ split construction perf(hgraph): optimize RaBitQ split construction Jul 18, 2026
@LightWant
LightWant force-pushed the feat/rabitq-build-accelerationV2 branch from ff26979 to f873ff8 Compare July 18, 2026 11:12
@vsag-bot
vsag-bot self-requested a review July 18, 2026 11:12
@vsag-bot

vsag-bot commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Automated pull request review completed.

Review effort: high (3022 changed lines across 36 files).

Submitted 2 inline comments.
Review: #2460 (review)

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (2662 changed lines across 34 files).
Submitted 1 inline comment.

Reviewed commit f873ff8.

Comment thread src/algorithm/hgraph/hgraph_build.cpp Outdated
@LightWant
LightWant force-pushed the feat/rabitq-build-accelerationV2 branch from f873ff8 to 82d11ba Compare July 19, 2026 09:01
@vsag-bot
vsag-bot self-requested a review July 19, 2026 09:01

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (2555 changed lines across 34 files).
Submitted 1 inline comment.

Reviewed commit 82d11ba.

Comment thread src/algorithm/hgraph/hgraph_build.cpp Outdated
@LightWant
LightWant force-pushed the feat/rabitq-build-accelerationV2 branch from 82d11ba to 3404d02 Compare July 20, 2026 03:10
@vsag-bot
vsag-bot self-requested a review July 20, 2026 03:10

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (2673 changed lines across 34 files).
Submitted 1 inline comment.

Reviewed commit 3404d02.

Comment thread src/datacell/rabitq_split_datacell.h
Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5
@LightWant
LightWant force-pushed the feat/rabitq-build-accelerationV2 branch from 3404d02 to b012ae5 Compare July 20, 2026 05:52
@vsag-bot
vsag-bot self-requested a review July 20, 2026 05:52

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (2737 changed lines across 34 files).
No actionable inline findings were found.

Reviewed commit b012ae5.

Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5
@vsag-bot
vsag-bot self-requested a review July 22, 2026 15:16
@LightWant

Copy link
Copy Markdown
Collaborator Author

Updated the fast-build integration in faaba7ad to minimize impact on shared interfaces while preserving the optimized construction path.

Interface isolation

  • Restored FlattenInterface and HGraph::search_one_graph to their pre-PR forms.
  • Added the internal optional FlattenOptimizedBuildInterface, implemented only by RaBitQSplitDataCell.
  • Moved optimized-build lifecycle, parallel scalar-code preparation, task draining, and preset-computer graph search into hgraph_fast_build.{h,cpp}; hgraph_build.cpp now contains only thin hooks.
  • Kept the existing virtual BasicSearcher::Search(...) signature unchanged and added a non-virtual build-only SearchWithPresetComputer(...) entry point.
  • Preserved one build-computer allocation per inserted point, parallel finalize, MMap serial finalize, and accepted-task draining on enqueue/task failures.

Validation

  • clang-format-15 --dry-run --Werror: passed
  • git diff --check: passed
  • Unit tests: 580 cases, 85,527,129 assertions passed
  • PR CI-equivalent non-daily functional tests: 261 cases, 1,773,211 assertions passed
  • Mock implementation tests: 1 case, 2 assertions passed
  • Optimized-build focused tests: 3 cases, 3,325 assertions passed
  • HGraph RaBitQ Split focused tests: 8 cases, 10,480 assertions passed
  • Release eval_performance rebuild: passed

GIST1M controlled A/B (3 runs, median)

Metric Before After Change
Build time 115.999 s 115.136 s -0.74%
QPS 4,308.9 4,346.7 +0.88%
Recall@10 0.9020 0.9012 -0.0008 absolute

The recall delta is within normal nondeterministic graph-build variation; scalar-code query equivalence and final packed-code behavior are covered by the focused tests. No systematic build or search performance regression was observed.

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (2968 changed lines across 36 files).
No actionable inline findings were found.

Reviewed commit faaba7a.

@LightWant

Copy link
Copy Markdown
Collaborator Author

/retest

Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5
@vsag-bot
vsag-bot self-requested a review July 23, 2026 10:01

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (2970 changed lines across 36 files).
No actionable inline findings were found.

Reviewed commit 2e49156.

Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5
@vsag-bot
vsag-bot self-requested a review July 23, 2026 11:33
@LHT129 LHT129 removed the in-review label Jul 23, 2026
Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (3044 changed lines across 36 files).
Submitted 3 inline comments.

Reviewed commit 3245b4f.

return std::nullopt;
}

this->Train(data);

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.

[P1] Validate dimensions before optimized training

Build now reaches Train(data) before Add calls validate_add_data. For an eligible split-RaBitQ index and a dataset whose dimension is smaller than the configured index dimension, RaBitQuantizer::TrainImpl strides and copies original_dim_ floats per row, reading beyond the supplied vectors; a larger wrong dimension can instead train on mis-strided data and leave the quantizer marked trained even though Add subsequently rejects the build. Validate the dataset before starting training so invalid input remains memory-safe and side-effect-free.

if (io_type == IO_TYPE_VALUE_READER_IO) {
return MakeHomogeneousRaBitQSplitDataCell<metric, ReaderIO>(param, common_param);
}
return nullptr;

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.

[P2] Preserve homogeneous uring_io dispatch

FlattenInterface::MakeInstance still dispatches uring_io to make_instance<UringIO>, but this new split factory has no corresponding homogeneous branch and returns null here. With HAVE_LIBURING=1, a split-RaBitQ configuration using uring_io therefore regresses from constructing RaBitQSplitDataCell<..., UringIO, UringIO> to index creation failure or a later null dereference. Add the guarded UringIO specialization.

`fast_encode_rabitq` and `fast_encode_rabitq_rounds` are available on HGraph,
IVF, and Pyramid and are propagated to both base and precise RaBitQ quantizers.

For a normal first HGraph build with split RaBitQ and `fast_encode_rabitq=true`,

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.

[P3] Document the build_by_base prerequisite

The implementation enables this path only when has_precise_reorder() ? build_by_base_ : raw_vector_ == nullptr. A normal split x+y configuration has precise reorder enabled while build_by_base defaults to false; the new functional configurations explicitly set it to true. Consequently, the scalar lifecycle described here does not apply to the normal/default build, so document the build_by_base=true prerequisite and other eligibility constraints or broaden the implementation.

Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5
@vsag-bot
vsag-bot self-requested a review July 24, 2026 10:14

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (3030 changed lines across 36 files).
Submitted 3 inline comments.

Reviewed commit e430b31.


std::vector<int64_t> result;
if (graph_type_ == GRAPH_TYPE_VALUE_NSW) {
this->Train(data);

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.

[P1] Validate the dataset before optimized training

This NSW path calls Train before Add reaches validate_add_data. If data->GetDim() differs from the configured dimension, RaBitQuantizer::TrainImpl strides original_dim_ floats per row, so a smaller row can be read out of bounds and a larger row is mis-strided before Add rejects it; validate the dataset before training or mutating the quantizer.

if (io_type == IO_TYPE_VALUE_READER_IO) {
return MakeHomogeneousRaBitQSplitDataCell<metric, ReaderIO>(param, common_param);
}
return nullptr;

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.

[P2] Restore homogeneous uring_io dispatch

FlattenInterface::MakeInstance still routes uring_io split configurations into this factory, but there is no IO_TYPE_VALUE_URING_IO branch, so it now returns null instead of constructing RaBitQSplitDataCell<..., UringIO, UringIO>. With HAVE_LIBURING=1, previously supported split-RaBitQ uring indexes therefore fail creation; add the guarded homogeneous specialization.

`fast_encode_rabitq` and `fast_encode_rabitq_rounds` are available on HGraph,
IVF, and Pyramid and are propagated to both base and precise RaBitQ quantizers.

For a normal first HGraph build with split RaBitQ and `fast_encode_rabitq=true`,

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.

[P3] Document the optimized-build eligibility constraints

This is not enabled for every normal split-RaBitQ first build: when precise reorder exists, the session requires build_by_base=true, while configurations using precise codes, deduplicated storage, raw-vector graph construction, or non-fast encoding fall back. State these prerequisites in both language versions so users do not plan memory or performance around a path that will not run.

Signed-off-by: LightWant <2510035537@qq.com>
Assisted-by: Codex:gpt-5
@vsag-bot
vsag-bot self-requested a review July 24, 2026 10:57

@vsag-bot vsag-bot 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.

Automated inline review completed.

Review effort: high (3022 changed lines across 36 files).
Submitted 2 inline comments.

Reviewed commit a25d8c6.

if (io_type == IO_TYPE_VALUE_READER_IO) {
return MakeHomogeneousRaBitQSplitDataCell<metric, ReaderIO>(param, common_param);
}
return nullptr;

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.

[P2] [P2] Restore homogeneous uring_io dispatch

FlattenInterface::MakeInstance still sends IO_TYPE_VALUE_URING_IO split configurations to this factory, but no branch handles that type. Under HAVE_LIBURING=1, a configuration that previously instantiated RaBitQSplitDataCell<..., UringIO, UringIO> reaches this return and produces a null cell, causing index creation to fail or later dereference the null pointer. Restore the homogeneous UringIO specialization.

`fast_encode_rabitq` and `fast_encode_rabitq_rounds` are available on HGraph,
IVF, and Pyramid and are propagated to both base and precise RaBitQ quantizers.

For a normal first HGraph build with split RaBitQ and `fast_encode_rabitq=true`,

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.

[P3] [P3] State the optimized-build eligibility constraints

The scalar lifecycle is not used by every normal split build described here: when precise reorder exists, it requires build_by_base=true even though that option defaults to false, and loaded-cache, deduplicated-storage, raw-vector, non-fast, and one-bit configurations also bypass it. This overstates the temporary-memory and performance behavior for common configurations; qualify the lifecycle in both language versions with the actual eligibility constraints.

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

Labels

kind/improvement Optimizations, UX polish, or minor improvements 性能优化、体验打磨或细节改良 module/docs module/simd module/testing size/XXL version/1.1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants