use std::time::Instant;
fn main() {
println!("=== Multi-Position Parallel Benchmark ===\n");
#[cfg(target_arch = "aarch64")]
println!("Architecture: ARM64 (NEON)\n");
#[cfg(target_arch = "x86_64")]
println!("Architecture: x86_64 (AVX2)\n");
let text = "The quick brown fox jumps over the lazy dog. ".repeat(100);
let text_bytes = text.as_bytes();
let positions: Vec<usize> = (0..text_bytes.len())
.filter(|&i| i % 10 == 0) .collect();
println!("Text size: {} bytes", text_bytes.len());
println!("Candidate positions: {}\n", positions.len());
let iterations = 10_000u32;
println!("--- Test 1: k=0 Exact Match ---");
bench_pattern("fox", 0, &text, &positions, iterations);
println!("\n--- Test 2: k=1 Fuzzy Match ---");
bench_pattern("fox", 1, &text, &positions, iterations);
println!("\n--- Test 3: Longer Pattern k=0 ---");
bench_pattern("quick brown", 0, &text, &positions, iterations);
println!("\n--- Test 4: Pattern Near End ---");
bench_pattern("dog", 0, &text, &positions, iterations);
println!("\n--- Test 5: Non-Matching Pattern ---");
bench_pattern("xyz", 0, &text, &positions, iterations);
println!("\n=== Direct Bitap Comparison ===");
compare_sequential_vs_parallel(&text, &positions);
}
fn bench_pattern(pattern: &str, edits: u8, text: &str, _positions: &[usize], iterations: u32) {
use fuzzy_regex::FuzzyRegexBuilder;
let regex = FuzzyRegexBuilder::new(&format!("(?:{pattern})"))
.edits(edits)
.similarity(0.5)
.build()
.unwrap();
for _ in 0..100 {
std::hint::black_box(regex.find(text));
}
let start = Instant::now();
for _ in 0..iterations {
std::hint::black_box(regex.find(text));
}
let elapsed = start.elapsed();
let per_iter_ns = elapsed.as_secs_f64() * 1_000_000_000.0 / f64::from(iterations);
println!("Pattern: '{pattern}' (k={edits})");
println!("Time per find: {per_iter_ns:.0} ns");
let text_len = u32::try_from(text.len()).unwrap_or(u32::MAX);
let throughput = f64::from(text_len) * f64::from(iterations) / elapsed.as_secs_f64() / 1_000_000.0;
println!("Throughput: {throughput:.1} MB/s");
}
fn compare_sequential_vs_parallel(text: &str, positions: &[usize]) {
use fuzzy_regex::engine::bitap::BitapMatcher;
use fuzzy_regex::engine::levenshtein::EditLimits;
let pattern = "fox";
let text_bytes = text.as_bytes();
let bitap = BitapMatcher::new(pattern, EditLimits::new(0), false).unwrap();
let iterations = 10_000u32;
let threshold = 1.0;
for _ in 0..100 {
for &pos in positions.iter().take(10) {
std::hint::black_box(bitap.find_at_byte_position(text_bytes, pos, threshold));
}
}
println!("\n--- Sequential (find_at_byte_position) ---");
let start = Instant::now();
for _ in 0..iterations {
for &pos in positions {
if let Some(_m) = bitap.find_at_byte_position(text_bytes, pos, threshold) {
break;
}
}
}
let seq_elapsed = start.elapsed();
let seq_per_iter_ns = seq_elapsed.as_secs_f64() * 1_000_000_000.0 / f64::from(iterations);
println!("Time per search: {seq_per_iter_ns:.0} ns");
println!("\n--- Parallel (find_at_positions_parallel) ---");
let start = Instant::now();
for _ in 0..iterations {
std::hint::black_box(bitap.find_at_positions_parallel(text_bytes, positions, threshold));
}
let par_elapsed = start.elapsed();
let par_per_iter_ns = par_elapsed.as_secs_f64() * 1_000_000_000.0 / f64::from(iterations);
println!("Time per search: {par_per_iter_ns:.0} ns");
let speedup = seq_per_iter_ns / par_per_iter_ns;
println!("\nSpeedup: {speedup:.2}x");
}