diff --git a/crates/ruvector-core/Cargo.toml b/crates/ruvector-core/Cargo.toml index 52bb4f33..a20467c3 100644 --- a/crates/ruvector-core/Cargo.toml +++ b/crates/ruvector-core/Cargo.toml @@ -95,8 +95,13 @@ name = "bench_memory" harness = false [features] -default = ["simd", "storage", "hnsw", "api-embeddings", "parallel"] +default = ["simd", "simd-avx512", "storage", "hnsw", "api-embeddings", "parallel"] simd = ["simsimd"] # SIMD acceleration (not available in WASM) +# AVX-512 intrinsics. Requires Rust >= 1.89 (where avx512f stabilized). +# Downstream consumers on older stable (1.77–1.88) can opt out: +# --no-default-features --features simd,storage,hnsw,api-embeddings,parallel +# See issue #438. +simd-avx512 = [] parallel = ["rayon", "crossbeam"] # Parallel processing (not available in WASM) storage = ["redb", "memmap2"] # File-based storage (not available in WASM) hnsw = ["hnsw_rs"] # HNSW indexing (not available in WASM due to mmap dependency) diff --git a/crates/ruvector-core/src/simd_intrinsics.rs b/crates/ruvector-core/src/simd_intrinsics.rs index fcb7f8a7..74c61e10 100644 --- a/crates/ruvector-core/src/simd_intrinsics.rs +++ b/crates/ruvector-core/src/simd_intrinsics.rs @@ -42,9 +42,13 @@ const PREFETCH_DISTANCE: usize = 64; pub fn euclidean_distance_simd(a: &[f32], b: &[f32]) -> f32 { #[cfg(target_arch = "x86_64")] { - if is_x86_feature_detected!("avx512f") { - unsafe { euclidean_distance_avx512_impl(a, b) } - } else if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") { + #[cfg(feature = "simd-avx512")] + { + if is_x86_feature_detected!("avx512f") { + return unsafe { euclidean_distance_avx512_impl(a, b) }; + } + } + if is_x86_feature_detected!("avx2") && is_x86_feature_detected!("fma") { unsafe { euclidean_distance_avx2_fma_impl(a, b) } } else if is_x86_feature_detected!("avx2") { unsafe { euclidean_distance_avx2_impl(a, b) } @@ -192,7 +196,7 @@ unsafe fn euclidean_distance_avx2_fma_impl(a: &[f32], b: &[f32]) -> f32 { // ============================================================================ /// AVX-512 euclidean distance - processes 16 floats per iteration -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", feature = "simd-avx512"))] #[target_feature(enable = "avx512f")] unsafe fn euclidean_distance_avx512_impl(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len(), "Input arrays must have the same length"); @@ -223,7 +227,7 @@ unsafe fn euclidean_distance_avx512_impl(a: &[f32], b: &[f32]) -> f32 { } /// AVX-512 dot product - processes 16 floats per iteration -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", feature = "simd-avx512"))] #[target_feature(enable = "avx512f")] unsafe fn dot_product_avx512_impl(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len(), "Input arrays must have the same length"); @@ -249,7 +253,7 @@ unsafe fn dot_product_avx512_impl(a: &[f32], b: &[f32]) -> f32 { } /// AVX-512 cosine similarity - processes 16 floats per iteration -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", feature = "simd-avx512"))] #[target_feature(enable = "avx512f")] unsafe fn cosine_similarity_avx512_impl(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len(), "Input arrays must have the same length"); @@ -284,7 +288,7 @@ unsafe fn cosine_similarity_avx512_impl(a: &[f32], b: &[f32]) -> f32 { } /// AVX-512 Manhattan distance - processes 16 floats per iteration -#[cfg(target_arch = "x86_64")] +#[cfg(all(target_arch = "x86_64", feature = "simd-avx512"))] #[target_feature(enable = "avx512f")] unsafe fn manhattan_distance_avx512_impl(a: &[f32], b: &[f32]) -> f32 { assert_eq!(a.len(), b.len(), "Input arrays must have the same length"); @@ -783,9 +787,13 @@ unsafe fn manhattan_distance_neon_unrolled_impl(a: &[f32], b: &[f32]) -> f32 { pub fn dot_product_simd(a: &[f32], b: &[f32]) -> f32 { #[cfg(target_arch = "x86_64")] { - if is_x86_feature_detected!("avx512f") { - unsafe { dot_product_avx512_impl(a, b) } - } else if is_x86_feature_detected!("avx2") { + #[cfg(feature = "simd-avx512")] + { + if is_x86_feature_detected!("avx512f") { + return unsafe { dot_product_avx512_impl(a, b) }; + } + } + if is_x86_feature_detected!("avx2") { unsafe { dot_product_avx2_impl(a, b) } } else { dot_product_scalar(a, b) @@ -847,9 +855,13 @@ unsafe fn dot_product_avx2_impl(a: &[f32], b: &[f32]) -> f32 { pub fn cosine_similarity_simd(a: &[f32], b: &[f32]) -> f32 { #[cfg(target_arch = "x86_64")] { - if is_x86_feature_detected!("avx512f") { - unsafe { cosine_similarity_avx512_impl(a, b) } - } else if is_x86_feature_detected!("avx2") { + #[cfg(feature = "simd-avx512")] + { + if is_x86_feature_detected!("avx512f") { + return unsafe { cosine_similarity_avx512_impl(a, b) }; + } + } + if is_x86_feature_detected!("avx2") { unsafe { cosine_similarity_avx2_impl(a, b) } } else { cosine_similarity_scalar(a, b) @@ -883,9 +895,13 @@ pub fn cosine_similarity_avx2(a: &[f32], b: &[f32]) -> f32 { pub fn manhattan_distance_simd(a: &[f32], b: &[f32]) -> f32 { #[cfg(target_arch = "x86_64")] { - if is_x86_feature_detected!("avx512f") { - unsafe { manhattan_distance_avx512_impl(a, b) } - } else if is_x86_feature_detected!("avx2") { + #[cfg(feature = "simd-avx512")] + { + if is_x86_feature_detected!("avx512f") { + return unsafe { manhattan_distance_avx512_impl(a, b) }; + } + } + if is_x86_feature_detected!("avx2") { unsafe { manhattan_distance_avx2_impl(a, b) } } else { manhattan_distance_scalar(a, b) diff --git a/crates/ruvector-router-core/src/vector_db.rs b/crates/ruvector-router-core/src/vector_db.rs index eacb8035..a0b38f09 100644 --- a/crates/ruvector-router-core/src/vector_db.rs +++ b/crates/ruvector-router-core/src/vector_db.rs @@ -150,7 +150,8 @@ impl VectorDB { if deleted { self.index.remove(id)?; - self.stats.write().total_vectors = self.stats.write().total_vectors.saturating_sub(1); + let mut stats = self.stats.write(); + stats.total_vectors = stats.total_vectors.saturating_sub(1); } Ok(deleted) diff --git a/docs/research/claude-code-rvsource/versions/v2.1.x/modules-manifest.json b/docs/research/claude-code-rvsource/versions/v2.1.x/modules-manifest.json index 639e90a1..696b14d6 100644 --- a/docs/research/claude-code-rvsource/versions/v2.1.x/modules-manifest.json +++ b/docs/research/claude-code-rvsource/versions/v2.1.x/modules-manifest.json @@ -1418,7 +1418,7 @@ "size": 387 }, { - "name": "type.js", + "name": "type_lc.js", "size": 387 }, { @@ -2330,7 +2330,7 @@ "size": 176 }, { - "name": "tmux.js", + "name": "tmux_lc.js", "size": 176 }, { diff --git a/docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/tmux.js b/docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/tmux_lc.js similarity index 100% rename from docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/tmux.js rename to docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/tmux_lc.js diff --git a/docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/type.js b/docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/type_lc.js similarity index 100% rename from docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/type.js rename to docs/research/claude-code-rvsource/versions/v2.1.x/tree/react_memo_cache_sentinel/react_memo_cache_sentinel/type_lc.js