Files
wifi-densepose/examples/wasm/ios/benches/performance.rs
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

250 lines
6.5 KiB
Rust

//! Performance Benchmarks for iOS WASM
//!
//! Run with: cargo bench
use std::time::Instant;
// Import the library
use ruvector_ios_wasm::*;
fn main() {
println!("=== iOS WASM Vector Database Benchmarks ===\n");
bench_simd_operations();
bench_hnsw_operations();
bench_quantization();
bench_distance_metrics();
bench_recommendation_engine();
println!("\n=== All benchmarks completed ===");
}
fn bench_simd_operations() {
println!("--- SIMD Operations ---");
let dim = 128;
let iterations = 10000;
let a: Vec<f32> = (0..dim).map(|i| i as f32 / dim as f32).collect();
let b: Vec<f32> = (0..dim).map(|i| (dim - i) as f32 / dim as f32).collect();
// Dot product benchmark
let start = Instant::now();
for _ in 0..iterations {
let _ = dot_product(&a, &b);
}
let elapsed = start.elapsed();
println!(
" dot_product({} dims, {} iter): {:?} ({:.0} ops/sec)",
dim,
iterations,
elapsed,
iterations as f64 / elapsed.as_secs_f64()
);
// L2 distance benchmark
let start = Instant::now();
for _ in 0..iterations {
let _ = l2_distance(&a, &b);
}
let elapsed = start.elapsed();
println!(
" l2_distance({} dims, {} iter): {:?} ({:.0} ops/sec)",
dim,
iterations,
elapsed,
iterations as f64 / elapsed.as_secs_f64()
);
// Cosine similarity benchmark
let start = Instant::now();
for _ in 0..iterations {
let _ = cosine_similarity(&a, &b);
}
let elapsed = start.elapsed();
println!(
" cosine_similarity({} dims, {} iter): {:?} ({:.0} ops/sec)",
dim,
iterations,
elapsed,
iterations as f64 / elapsed.as_secs_f64()
);
}
fn bench_hnsw_operations() {
println!("\n--- HNSW Index ---");
let dim = 64;
let num_vectors = 1000;
// Generate random vectors
let vectors: Vec<Vec<f32>> = (0..num_vectors)
.map(|i| {
(0..dim)
.map(|j| ((i * 17 + j * 31) % 100) as f32 / 100.0)
.collect()
})
.collect();
// Insert benchmark
let mut index = HnswIndex::with_defaults(dim, DistanceMetric::Cosine);
let start = Instant::now();
for (i, v) in vectors.iter().enumerate() {
index.insert(i as u64, v.clone());
}
let insert_elapsed = start.elapsed();
println!(
" insert {} vectors: {:?} ({:.0} vec/sec)",
num_vectors,
insert_elapsed,
num_vectors as f64 / insert_elapsed.as_secs_f64()
);
// Search benchmark
let query = &vectors[500];
let k = 10;
let iterations = 1000;
let start = Instant::now();
for _ in 0..iterations {
let _ = index.search(query, k);
}
let search_elapsed = start.elapsed();
println!(
" search top-{} ({} iter): {:?} ({:.0} qps)",
k,
iterations,
search_elapsed,
iterations as f64 / search_elapsed.as_secs_f64()
);
// Verify search quality
let results = index.search(query, k);
println!(
" search quality: found {} results, best dist={:.4}",
results.len(),
results.first().map(|(_, d)| *d).unwrap_or(f32::MAX)
);
}
fn bench_quantization() {
println!("\n--- Quantization ---");
let dim = 128;
let iterations = 10000;
let vector: Vec<f32> = (0..dim).map(|i| i as f32 / dim as f32).collect();
// Scalar quantization
let start = Instant::now();
for _ in 0..iterations {
let _ = ScalarQuantized::quantize(&vector);
}
let elapsed = start.elapsed();
println!(
" scalar_quantize({} dims, {} iter): {:?} ({:.0} ops/sec)",
dim,
iterations,
elapsed,
iterations as f64 / elapsed.as_secs_f64()
);
// Binary quantization
let start = Instant::now();
for _ in 0..iterations {
let _ = BinaryQuantized::quantize(&vector);
}
let elapsed = start.elapsed();
println!(
" binary_quantize({} dims, {} iter): {:?} ({:.0} ops/sec)",
dim,
iterations,
elapsed,
iterations as f64 / elapsed.as_secs_f64()
);
// Memory savings
let sq = ScalarQuantized::quantize(&vector);
let bq = BinaryQuantized::quantize(&vector);
let original_size = dim * 4; // f32 = 4 bytes
println!(
" memory: original={}B, scalar={}B ({}x), binary={}B ({}x)",
original_size,
sq.memory_size(),
original_size / sq.memory_size(),
bq.memory_size(),
original_size / bq.memory_size()
);
}
fn bench_distance_metrics() {
println!("\n--- Distance Metrics ---");
let dim = 128;
let iterations = 10000;
let a: Vec<f32> = (0..dim).map(|i| i as f32 / dim as f32).collect();
let b: Vec<f32> = (0..dim).map(|i| (dim - i) as f32 / dim as f32).collect();
let metrics = [
("Euclidean", DistanceMetric::Euclidean),
("Cosine", DistanceMetric::Cosine),
("Manhattan", DistanceMetric::Manhattan),
("DotProduct", DistanceMetric::DotProduct),
];
for (name, metric) in metrics {
let start = Instant::now();
for _ in 0..iterations {
let _ = distance::distance(&a, &b, metric);
}
let elapsed = start.elapsed();
println!(
" {}: {:?} ({:.0} ops/sec)",
name,
elapsed,
iterations as f64 / elapsed.as_secs_f64()
);
}
}
fn bench_recommendation_engine() {
println!("\n--- Recommendation Engine ---");
// Create VectorDatabase
let dim = 64;
let num_vectors = 500;
let mut db = VectorDatabase::new(dim, DistanceMetric::Cosine, QuantizationMode::None);
// Insert vectors
let start = Instant::now();
for i in 0..num_vectors {
let v: Vec<f32> = (0..dim)
.map(|j| ((i * 17 + j * 31) % 100) as f32 / 100.0)
.collect();
db.insert(i as u64, v);
}
let insert_elapsed = start.elapsed();
println!(
" VectorDB insert {} vectors: {:?}",
num_vectors, insert_elapsed
);
// Search
let query: Vec<f32> = (0..dim).map(|i| i as f32 / dim as f32).collect();
let iterations = 1000;
let start = Instant::now();
for _ in 0..iterations {
let _ = db.search(&query, 10);
}
let search_elapsed = start.elapsed();
println!(
" VectorDB search ({} iter): {:?} ({:.0} qps)",
iterations,
search_elapsed,
iterations as f64 / search_elapsed.as_secs_f64()
);
// Memory usage
println!(" VectorDB memory: {} bytes", db.memory_usage());
}