Skip to content

perf(symqg): filter neighbors with batch threshold masks - #97

Merged
gouyt13 merged 1 commit into
mainfrom
perf/symqg-threshold-mask
Sep 10, 2026
Merged

perf(symqg): filter neighbors with batch threshold masks#97
gouyt13 merged 1 commit into
mainfrom
perf/symqg-threshold-mask

Conversation

@gouyt13

@gouyt13 gouyt13 commented Sep 10, 2026

Copy link
Copy Markdown
Member

Problem and change

SymphonyQG currently performs a scalar threshold check for every scored neighbor. Build a 32-lane threshold mask after FastScan and iterate only eligible lanes, reducing scalar handling of rejected candidates. Preserve lane order, equal-distance handling, visited checks, and the live threshold recheck as insertions tighten the beam.

Construction can supply partially filled neighborhoods even though finalized rows have a multiple-of-32 degree. Clear mask bits beyond the logical degree so stale IDs in unused physical lanes cannot enter the beam. Keep the fixed-length mask-generation loop for vectorization and avoid shifting a 32-bit value by 32.

This PR changes only qg.hpp; it does not include the local experiment or test files.

Validation

  • Portable C++ build (RABITQ_ENABLE_NATIVE_OPTIMIZATION=OFF) and ctest: 62/62 passed. Runtime dispatch used AVX-512 on this machine; AVX2 execution was not separately tested.
  • Full current Python suite: 102 passed, using the rebuilt fixed extension installed in the existing project environment. Built/installed extension code hashes were verified during the fix.
  • Standalone probe of the actual scan implementation: logical degrees 1/17/31/32 insert exactly 1/17/31/32 neighbors and no stale IDs. The unguarded mask inserted 32 neighbors for each case. These focused regression artifacts were run locally and are not part of this header-only PR.
  • ./scripts/check-format.sh, ./scripts/check-python.sh, git diff --check, and focused clang-tidy for the QG test translation unit passed. Full pre-merge clang-tidy has not been run.
  • Native GCC 14.3 disassembly retains four 256-bit comparisons and tzcnt/blsr enumeration; the tail guard clears high mask bits with bzhi.

Earlier measurements of the threshold-mask optimization on GIST1M (960 dimensions, degree 32, squared L2, k=10, one thread pinned to CPU 0 on Xeon Gold 6418H, GCC 14.3, -O3 -march=native, AVX-512 dispatch) showed raw QPS improvements of 3.9%/5.1%/4.2% at ef 155/180/290 and 8-bit improvements of 3.2%/3.0% at ef 180/340, with identical ordered result and distance hashes on fixed indexes. Those measurements preceded the tail guard; the final guard was correctness- and assembly-checked, without a new end-to-end performance claim.

Compatibility

No public API, persisted index-format, or dependency changes. Existing finalized indexes remain compatible. Construction now excludes unused lanes from partially filled neighborhoods.

@gouyt13
gouyt13 merged commit c2ff92e into main Sep 10, 2026
17 checks passed
@gouyt13
gouyt13 deleted the perf/symqg-threshold-mask branch September 11, 2026 20:15
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