Skip to content

[muilt-vetor] Add standalone MinMax8 x MinMax4 MaxSim kernel - #1494

Open
juchen-ms (partychen) wants to merge 2 commits into
microsoft:mainfrom
partychen:minmax_kernel
Open

juchen-ms (partychen) wants to merge 2 commits into
microsoft:mainfrom
partychen:minmax_kernel

Conversation

@partychen

@partychen juchen-ms (partychen) commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor
  • Does this PR have a descriptive title that could go in our release notes?
  • Does this PR add any new dependencies?
  • Does this PR modify any existing APIs?
  • Is the change to the API backwards compatible?
  • Should this result in any changes to our documentation, either updating existing docs or adding new ones?

No new dependencies. Public additions are backward-compatible: dense BitSlice bulk decoding and supporting SIMD trait implementations. Existing distance APIs and canonical MinMax storage remain unchanged.

Reference Issues/PRs

Reworks the matrix-kernel portion of #1394 into a standalone implementation. Uses the SIMD reinterpretation and maddubs support from #1445 and #1479.

What does this implement/fix? Briefly explain your changes.

Adds an internal MaxSim matrix kernel for MinMax A/B inputs with 1-8 bits per code, supporting all 64 bit-width combinations through the available numeric layouts.

Execution

  • PackedA owns the prepacked query codes and compensation coefficients and can be reused across B comparisons.
  • The existing Drive -> PanelKernel -> MicroKernel structure decodes each B tile once and reuses it across A panels. Compensation precedes max reduction; no full pairwise score matrix is materialized.
  • B preparation uses shared dense BitSlice::decode_into, rather than MinMax-local 4/8-bit decoding branches. Output length is validated before writing or invoking the conversion callback.
  • B rows are zero-padded to PACK. Physical stride is separate from logical K, which controls compensation and accumulation limits. Broadcasts read complete packs without a valid argument or separate partial-K contraction.
  • ExtraWide exposes backend operations for loads, accumulation, score storage, and compensated reduction. Concrete array conversions replace the generic microkernel's lane-count const assertions. Construction-time checks for legal NR/backend bit widths remain.

Available layouts

All layouts support A_BITS=1-8. MR counts A rows per microkernel; NR is a separate parameter in 1-8. These are supported layouts, not a universal optimal configuration or automatic selection policy.

Backend/path MR PACK Prepared A / B B_BITS
Scalar byte 16 4 u8 / i8 1-7
Scalar general 8, 16 2 i16 / i16 1-8
V3 byte 8, 16 4 u8 / i8 1-6
V3 general 8, 16 2 i16 / i16 1-8
V4 byte 16 4 u8 / i8 1-7
V4 general 16 2 i16 / i16 1-8
Neon + dotprod 8, 16 4 u8 / u8 1-8

The byte limits prevent signed-byte misinterpretation and, on V3, saturation of the intermediate i16 sum. Full-range eight-bit B uses the i16 path on Scalar/x86 and unsigned byte dots on Neon.

Behavior

Each drive overwrites its output with unnegated maximum inner products. NaNs are ignored; empty B or all-NaN candidates leave negative infinity. The internal driver requires nonempty A, positive K, and matching dimensions. K is bounded by i32::MAX / ((2^A_BITS - 1) * (2^B_BITS - 1)); conversion to f32 may still round.

Tests separately cover decoding, packing, arithmetic limits, supported bit widths, partial panels, tile reuse, smaller MR layouts, compensation, and NaN reduction. Repeated whole-kernel combinations have been reduced in favor of focused cases.

Any other comments?

Scope: Factory/ISA selection policy, public prepared-query distance integration, FFI/externally owned query views, and benchmark integration remain follow-up work. PackedA stays pub(crate).

Performance: MR=16 is retained alongside narrower layouts, not claimed optimal for every architecture or query size. Earlier exploratory timings and assembly observations are not validation of this head; current-head native x86 performance and spill analysis still need confirmation.

Validation at 2538cc7 -- Windows ARM64 host:

Command Result
cargo fmt --all --check Passed
cargo test -p diskann-quantization --release --lib -- bits::slice::tests matrix_kernels::maxsim::packed_minmax_x_unpacked_minmax --test-threads=1 Passed: 36 tests; native Scalar/Neon paths
cargo clippy -p diskann-quantization -p diskann-wide --all-targets -- -D warnings Passed
cargo clippy -p diskann-quantization -p diskann-wide --all-targets --target x86_64-pc-windows-msvc -- -D warnings Passed; cross-compilation/lint only

Native V3/V4 execution, SDE/Miri, and coverage were not rerun as part of these checks. Cross-compilation is not runtime validation.

Copilot AI 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.

🔵 Needs a closer look

The new unsafe SIMD paths require cross-platform validation and final human review.

0 open findings

What changed in this PR

Adds a standalone quantized MaxSim kernel to DiskANN’s matrix kernels, leaving distance API integration for a follow-up.

Changes:

  • Implements packed-A, B-tiled computation for Scalar, V3, V4, and Neon.
  • Adds compensated inner products and NaN-aware maximum reduction.
  • Adds supporting SIMD conversions and regression coverage.
File Description
diskann-wide/​src/​reference.rs Adds reference u32-to-f32 conversion.
diskann-wide/​src/​emulated.rs Adds and tests 16-lane i32-to-f32 conversion.
diskann-wide/​src/​arch/​x86_64/​v4/​conversion.rs Adds and tests AVX-512 conversion.
diskann-wide/​src/​arch/​x86_64/​v3/​conversion.rs Adds and tests split-vector conversion.
diskann-wide/​src/​arch/​aarch64/​u32x4_.rs Adds and tests Neon conversion and reinterpretation.
diskann-quantization/​src/​matrix_kernels/​maxsim/​packed_minmax8_x_unpacked_minmax4.rs Implements the kernel, backends, and regression tests.
diskann-quantization/​src/​matrix_kernels/​maxsim/​mod.rs Registers the kernel pending integration.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov-commenter

Codecov Comments Bot (codecov-commenter) commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.24983% with 87 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.07%. Comparing base (18c9cce) to head (41710a5).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
..._kernels/maxsim/packed_minmax_x_unpacked_minmax.rs 94.21% 81 Missing ⚠️
diskann-quantization/src/bits/slice.rs 97.22% 3 Missing ⚠️
diskann-wide/src/reference.rs 0.00% 3 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1494      +/-   ##
==========================================
+ Coverage   90.94%   91.07%   +0.12%     
==========================================
  Files         586      587       +1     
  Lines      118391   121439    +3048     
==========================================
+ Hits       107675   110603    +2928     
- Misses      10716    10836     +120     
Flag Coverage Δ
miri 91.07% <94.24%> (+0.12%) ⬆️
unittests 90.77% <94.18%> (+0.13%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
diskann-wide/src/arch/x86_64/v3/conversion.rs 100.00% <100.00%> (ø)
diskann-wide/src/arch/x86_64/v4/conversion.rs 0.00% <ø> (ø)
diskann-wide/src/emulated.rs 100.00% <ø> (ø)
diskann-quantization/src/bits/slice.rs 97.31% <97.22%> (-0.02%) ⬇️
diskann-wide/src/reference.rs 91.81% <0.00%> (-2.58%) ⬇️
..._kernels/maxsim/packed_minmax_x_unpacked_minmax.rs 94.21% <94.21%> (ø)

... and 15 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Support all 1-8 bit A/B combinations through shared packing, tiled
execution, compensation and maximum-inner-product reduction.

Retain the tuned byte backends alongside full-range i16 paths, keep
quantization widths out of the numeric microkernels, and add the
required SIMD conversions and correctness coverage.

Leave factory, fallback and public distance integration to follow-up PRs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 74814a43-c576-493a-8783-585ef48c3f1c
@partychen juchen-ms (partychen) changed the title Add standalone MinMax8 x MinMax4 MaxSim kernel [muilt-vetor] Add standalone MinMax8 x MinMax4 MaxSim kernel Oct 16, 2026

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.

Thanks Junkui. This is a simplification over the earlier PR! There still is some coupling between the lower-level kernels and some of the higher data preparation stuff.

A few other things that stand out to me:

  • It makes heavy use of post-monomorphization errors via const { assert!(...) }. These aren't necessarily wrong, but they are kind of hard to debug when they trigger, don't compose with higher level code well, and to me often indicate that there is another way of structuring the code so they aren't needed. I'm not saying get rid of them, but that over reliance could indicate a missing abstraction.
  • Why are 16-wide accumulators used for all architectures? This seems like it could be problematic for Neon or Scalar. Have you checked that the generated code isn't spilling too much and is reasonable?

I know a few other folks are planning on reviewing this as well - let's see what they have to say.

Comment thread diskann-quantization/src/matrix_kernels/maxsim/packed_minmax_x_unpacked_minmax.rs Outdated
Comment thread diskann-quantization/src/matrix_kernels/maxsim/packed_minmax_x_unpacked_minmax.rs Outdated
Comment thread diskann-quantization/src/matrix_kernels/maxsim/packed_minmax_x_unpacked_minmax.rs Outdated
Comment thread diskann-quantization/src/matrix_kernels/maxsim/packed_minmax_x_unpacked_minmax.rs Outdated
Comment thread diskann-quantization/src/matrix_kernels/maxsim/packed_minmax_x_unpacked_minmax.rs Outdated
Comment thread diskann-quantization/src/matrix_kernels/maxsim/packed_minmax_x_unpacked_minmax.rs Outdated
@partychen
juchen-ms (partychen) force-pushed the minmax_kernel branch 3 times, most recently from e360602 to 2538cc7 Compare October 17, 2026 07:45
@partychen

Copy link
Copy Markdown
Contributor Author

Thanks Junkui. This is a simplification over the earlier PR! There still is some coupling between the lower-level kernels and some of the higher data preparation stuff.

A few other things that stand out to me:

  • It makes heavy use of post-monomorphization errors via const { assert!(...) }. These aren't necessarily wrong, but they are kind of hard to debug when they trigger, don't compose with higher level code well, and to me often indicate that there is another way of structuring the code so they aren't needed. I'm not saying get rid of them, but that over reliance could indicate a missing abstraction.
  • Why are 16-wide accumulators used for all architectures? This seems like it could be problematic for Neon or Scalar. Have you checked that the generated code isn't spilling too much and is reasonable?

I know a few other folks are planning on reviewing this as well - let's see what they have to say.

Thanks for the feedback. I’ve moved SIMD-specific operations behind ExtraWide, removing the lane-count const assertions from the generic microkernel. The arithmetic-safety checks remain.

I’ve also added MR=8 alternatives for Neon, V3, and Scalar’s i16 path rather than requiring 16-wide accumulators everywhere. Earlier V3 assembly inspection showed register-resident accumulators in the full contraction loop, but stack traffic around compensation and tails; I’m not claiming all configurations are spill-free.

PackedA remains pub(crate) for now. I’ll incorporate the other reviewers’ feedback as well.

Move bulk decoding into BitSlice and zero-pad prepared B rows for a unified pack loop. Decouple backend representations behind fixed-size operations, retain smaller row-panel choices, and replace redundant test sweeps with directed coverage.

Make B preparation independent of backend and row-panel types by accepting a code converter. Keep backend capability validation at the Driver construction boundary.

Give each backend the full microkernel compensation and reduction stage through max_into with borrowed coefficients. Keep MR16 contraction intact while V3 reduces native eight-row halves. Define backend operations explicitly and share the compensation formula; preserve floating-point order and NaN semantics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.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.

4 participants