Skip to content

fix(cli): velesdb simd info names the detected level; drop the unused simd_neon (#1965) - #2391

Merged
cyberlife-coder merged 14 commits into
developfrom
fix/1965-simd-info-detected-level
Sep 24, 2026
Merged

cyberlife-coder merged 14 commits into
developfrom
fix/1965-simd-info-detected-level

Conversation

@cyberlife-coder

@cyberlife-coder cyberlife-coder commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Refs #1965. Clears the two cost-S items that the 2026-09-05 update promoted to checkboxes. The registry stays open for its measured items.

velesdb simd info names the level it detects

It used to print a fixed summary of the design. The thresholds in that summary no longer match the code: it said AVX2 switches at 1024 dimensions, but the dispatcher switches at 256, and it listed AVX-512 with 4/2/1 accumulators where the code runs an 8-accumulator kernel from 1024 dimensions. It said nothing about the machine it ran on. It now prints simd_native::simd_level(), named through a new impl Display for SimdLevel:

SIMD
  Detected level: NEON (aarch64)
  Distance kernels (dot product, cosine, Euclidean, Hamming, Jaccard,
  and their batch forms) dispatch to this level at runtime.

Test: e2e_complete::simd_commands::test_simd_info_names_the_detected_level. It asserts that the output contains simd_level().to_string() and that 1024D is gone. I ran it against the old handler first and it failed (var.contains(NEON (aarch64))), then passed after the fix.

velesdb_core::simd_neon removed (BREAKING, aarch64 only)

This was a pub mod with no callers, a standalone copy of the NEON kernels that simd_native already dispatches to. Two guides said mobile computes distances through it. It doesn't: mobile goes through simd_native, like every aarch64 build. The guides, SOUNDNESS.md (section and inventory table), ARCHITECTURE.md, SIMD_PERFORMANCE.md ("Known gaps" and the simd info paragraph) and CLI_COMMAND_REFERENCE.md are corrected to match. That reference also claimed simd benchmark re-benchmarks every backend; it only points to cargo bench, and now says so. The dead Codacy and Semgrep exclusions for the deleted file are removed, and core-review.yml and QUALITY_BAR.md now use simd_neon_prefetch as their example of an aarch64-only public item. The CHANGELOG maps all nine removed functions to their simd_native replacements. The velesdb simd --help text makes the same corrections as the reference: info shows the detected level, and benchmark measures nothing itself. SOUNDNESS.md's simd_native/neon.rs section no longer names the removed *_neon_safe wrappers. It also no longer calls every kernel an unsafe fn with #[target_feature]: the kernels are pub(crate) unsafe fns with an a.len() == b.len() precondition, and NEON needs no feature gate on AArch64. simd_neon_prefetch is kept because simd_native::prefetch uses it.

[Unreleased] already carries breaking changes, so the next release is a major and this removal fits it. cargo semver-checks runs on x86_64 and cannot see a module that only exists on aarch64, so the CHANGELOG entry spells out the migration.

Gates (local, aarch64)

fmt, both strict clippy runs, the CLI e2e test, the core simd lib tests, rustdoc -D warnings, and the doc/claims/attribution/version/promise checks.

Also

e2e_complete.rs (touched for the new test) had the BFS and DFS traversal tests building the same one-edge graph twice, 23 identical lines. They now share graph_with_one_edge / traverse_from_10, with no change to what either test asserts.

NEON kernels are unsafe fn (found in review, round 3)

The six pub(crate) NEON kernels, and the two private *_4acc helpers they call, were safe fns that read b at every index of a with no length check. A debug-profile probe called dot_product_neon(&[1.0; 8], &backing[..4]) and got 8: four floats read past b, no assert, no unsafe at the call site. The public entry points (*_native, DistanceEngine::dispatch) already assert equal lengths in release, so no public call was exposed. The hole was crate-internal: any future caller could trigger UB from safe code.

They are now unsafe fn with an a.len() == b.len() # Safety precondition, the model the x86 dot-product kernels already follow. Each of the 11 call sites wraps the call in unsafe with a SAFETY comment naming the assert it relies on. The inner calls to the *_1acc/*_4acc and cosine helpers name the calling kernel's own precondition. Every unsafe fn in neon.rs now has a # Safety section; I checked this by listing them all, because the template checker only covers unsafe blocks. The two register-only helpers state that they need nothing beyond NEON. The cosine pointer helpers state the span of b they read. cosine_fused_neon_4acc takes its bounds from bounds_16wide too. Three comments that cited a 64-element "minimum" now give it as what it is: a dispatch threshold, not a safety condition. No behaviour changes: a safe call to these kernels no longer compiles. SOUNDNESS.md invariant 2 previously claimed a debug_assert_eq! that did not exist; it now describes the real check. velesdb simd benchmark printed "micro-benchmarks removed" although simd_benchmark exists; it now says the CLI does not benchmark and gives the cargo bench command. The three 16-wide kernels (dot_product_neon_4acc, squared_l2_neon_4acc, cosine_fused_neon_4acc) shared their loop-bound setup. It is now one safe helper, bounds_16wide, which returns the main-body length and both pointers. Both come from a's own as_ptr_range(), the tail start through wrapping_add(main). A first draft took the main-body end from the subslice a[..main]. The address was the same, but cosine's scalar tail dereferences from that pointer onward, past the subslice's borrow, and Miri (Stacked Borrows) reported it as UB. The review caught it, and pointers derived from the full slice remove it. Every change is under cfg(target_arch = "aarch64") and was built and gated on aarch64. The x86 code is untouched.

Round 7: the provenance fix, pinned

neon_bounds_tests feeds bounds_16wide's pointers to the cosine scalar tail at lengths 0, 1, 15, 16, 17 and 65 (empty, tail only, exact, 16+1, 64+1). Natively it passes whatever the pointers' provenance. Under Miri's Stacked Borrows, the review's reproduction shows the subslice-derived version fails and this one passes. The test calls no NEON intrinsic, so Miri can run it. CI's only Miri job runs on x86_64, weekly or on demand, so it never compiles neon.rs. Running this test there is a CI change, filed as #2397 rather than claimed here. SOUNDNESS.md now describes every NEON loop shape: the len / 4 single-accumulator loops, the three 16-wide kernels with pointer tails and where those pointers must come from, the two 16-wide kernels with indexed tails, and hamming_binary_neon's two-word loop.

Miri, run by the review with the documented command (cargo +nightly miri test --target aarch64-unknown-linux-gnu -p velesdb-core --lib -- neon_bounds, Stacked Borrows): the test passes at head. It fails on the round-6 regression, and also on a variant that keeps the subslice pointer only when main > 0.

Round 10: neon.rs split under the file budget

The # Safety sections took neon.rs to 1025 lines, past the 1000-line production budget, and CI's check-file-budgets.py failed on it. The budget is not raised. The Hamming and Jaccard kernels (hamming_neon, hamming_binary_neon, jaccard_neon and their 1acc/4acc helpers) share no helper with the dot, cosine and L2 ones, so they move unchanged to simd_native/neon_hamming_jaccard.rs, the same way x86_avx2_similarity.rs sits beside x86_avx2/. neon.rs is 591 lines (290 NLOC), the new file 455 (205 NLOC). QUALITY_BAR.md's stale neon.rs row (902 NLOC) is removed, since both files are now under the 500-NLOC line. SOUNDNESS.md names both files.

…ed `simd_neon` (#1965)

`simd info` printed a fixed design summary whose thresholds had drifted
from the dispatcher (AVX2 at 1024 dims, not 256) and said nothing about
the machine. It now prints `simd_native::simd_level()` through a new
`impl Display for SimdLevel`.

`velesdb_core::simd_neon` was a public aarch64-only module with no
caller, duplicating the NEON kernels `simd_native` dispatches to. Two
guides claimed mobile used it; they now name `simd_native`. Declared
BREAKING in the CHANGELOG, since semver-checks runs on x86_64 and cannot
see it.
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity

Metric Results
Complexity 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

…e removed functions (#1965)

SOUNDNESS's inventory table and SIMD_PERFORMANCE's `simd info` paragraph
still described the removed module and the old static output; the
CLI reference also claimed `simd benchmark` re-benchmarks every backend,
where it only points to `cargo bench`. Three dead lint exclusions named
the deleted file, and two docs used it as their aarch64-only example
(now `simd_neon_prefetch`). The CHANGELOG entry maps all nine removed
functions, the safe wrappers included, to their `simd_native` replacement.
…econdition stated (#1965)

`dot_product_neon`, `squared_l2_neon`, `cosine_neon`, `hamming_neon`,
`jaccard_neon`, `hamming_binary_neon` and the private `*_4acc` helpers
were safe functions that read `b` at every index of `a` unchecked: a
crate-internal call with a shorter `b` read past its end with no `unsafe`
in sight (probe: `dot_product_neon(&[1.0; 8], &backing[..4])` = 8). The
public entry points already assert equal lengths in release, so no public
call was affected. They now carry an `a.len() == b.len()` `# Safety`
contract, like the x86 kernels, and each call site names the assert it
relies on. The two `*_4acc` kernels share their loop bounds through a
safe helper instead of two copies of raw pointer arithmetic.
SOUNDNESS's invariant 2 claimed a `debug_assert_eq!` that did not exist;
`simd benchmark` said the benchmarks were removed.
)

The six `*_1acc`/`*_4acc` helpers of cosine, hamming and jaccard read `b`
at every index of `a` like the kernels, but had no `# Safety` section, and
the inner calls named only NEON and the minimum length. They now carry the
same `a.len() == b.len()` contract, and each inner call names it.
…1965)

Listed all of them this time: `squared_l2_neon_1acc` had no `# Safety`,
nor did the two cosine pointer helpers (now: the span of `b` they read)
or the two register-only helpers (now: nothing beyond NEON). Three
delegations cited a 64-element "minimum" the 4-accumulator kernels do
not have; it is a dispatch threshold, now said so. `cosine_fused_neon_4acc`
takes its bounds from `bounds_16wide` like the other two.
…1965)

`bounds_16wide` took the main-body end from `a[..main]`: the same
address, but cosine's scalar tail dereferences from that pointer on,
past the subslice's borrow, which Miri (Stacked Borrows) reports as UB.
Both pointers are now derived from `a` with `wrapping_add`, and the
helper returns the main-body length, which cosine recomputed. The calls
to `reduce_4acc_neon` get their SAFETY comment, and the loop bodies of
the pointer helpers cite their own `# Safety` contract.
…S states both loop shapes (#1965)

`neon_bounds_tests` feeds `bounds_16wide`'s pointers to the cosine scalar
tail at lengths 0-65. Natively it passes whatever their provenance; under
Miri's Stacked Borrows a tail pointer derived from `a[..main]` fails. It
calls no intrinsic, so Miri can run it; wiring an aarch64 Miri step is
#2397. SOUNDNESS's invariants 3 and 4 described only the `len / 4` loops;
they now cover the 16-wide kernels and where their tail pointers come from.
…n.rs

The # Safety sections took neon.rs to 1025 lines, past the 1000-line
production budget that check-file-budgets.py enforces. The Hamming and
Jaccard kernels share no helper with the dot, cosine and L2 ones, so they
move unchanged to neon_hamming_jaccard.rs, beside neon.rs the way
x86_avx2_similarity.rs sits beside x86_avx2/. The budget is not raised.
@cyberlife-coder
cyberlife-coder merged commit 3f2a7d9 into develop Sep 24, 2026
70 checks passed
@cyberlife-coder
cyberlife-coder deleted the fix/1965-simd-info-detected-level branch September 24, 2026 14:44
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