#![allow(clippy::cast_precision_loss)]
use mappy_core::{Engine, EngineConfig, PersistenceMode};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng};
use std::collections::{BTreeMap, HashMap};
use std::time::Instant;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("🚀 Mappy Performance Comparison");
println!("===============================\n");
let sizes = vec![1000, 10000, 100000];
for size in sizes {
println!("📊 Testing with {} items", size);
println!("{}", "=".repeat(50));
let test_data = generate_test_data(size);
test_hashmap(&test_data, size).await;
test_btreemap(&test_data, size).await;
test_mappy(&test_data, size, PersistenceMode::Memory).await;
test_mappy(&test_data, size, PersistenceMode::Disk).await;
println!();
}
test_memory_efficiency().await?;
test_concurrent_performance().await?;
println!("✅ Performance comparison completed!");
Ok(())
}
fn generate_test_data(size: usize) -> Vec<(String, String)> {
let mut rng = StdRng::seed_from_u64(42);
(0..size)
.map(|i| {
let key = format!("key_{:08x}", i);
let value = format!("value_{}", rng.gen_range(1..=1000));
(key, value)
})
.collect()
}
async fn test_hashmap(test_data: &[(String, String)], size: usize) {
let start = Instant::now();
let mut map = HashMap::new();
for (key, value) in test_data {
map.insert(key.clone(), value.clone());
}
let insert_time = start.elapsed();
let start = Instant::now();
for (key, _) in test_data.iter().take(1000) {
let _ = map.get(key);
}
let read_time = start.elapsed();
let estimated_memory = size * (32 + 32);
println!(" HashMap:");
println!(" Insert time: {:?}", insert_time);
println!(" Read time (1000 items): {:?}", read_time);
println!(" Estimated memory: {} bytes", estimated_memory);
println!(
" Load factor: {:.2}",
map.len() as f64 / map.capacity() as f64
);
}
async fn test_btreemap(test_data: &[(String, String)], size: usize) {
let start = Instant::now();
let mut map = BTreeMap::new();
for (key, value) in test_data {
map.insert(key.clone(), value.clone());
}
let insert_time = start.elapsed();
let start = Instant::now();
for (key, _) in test_data.iter().take(1000) {
let _ = map.get(key);
}
let read_time = start.elapsed();
let estimated_memory = size * (32 + 32);
println!(" BTreeMap:");
println!(" Insert time: {:?}", insert_time);
println!(" Read time (1000 items): {:?}", read_time);
println!(" Estimated memory: {} bytes", estimated_memory);
}
async fn test_mappy(
test_data: &[(String, String)],
_size: usize,
persistence_mode: PersistenceMode,
) {
let config = EngineConfig {
persistence_mode,
data_dir: if persistence_mode == PersistenceMode::Memory {
None
} else {
Some(
std::env::temp_dir()
.join("mappy_perf")
.to_string_lossy()
.to_string(),
)
},
..Default::default()
};
let engine = Engine::new(config).await.unwrap();
let start = Instant::now();
for (key, value) in test_data {
engine
.set(key.clone(), value.as_bytes().to_vec())
.await
.unwrap();
}
let insert_time = start.elapsed();
let start = Instant::now();
for (key, _) in test_data.iter().take(1000) {
let _ = engine.get(key).await.unwrap();
}
let read_time = start.elapsed();
let stats = engine.stats().await.unwrap();
let memory_usage = engine.memory_usage().await.unwrap();
println!(" Mappy ({:?}):", persistence_mode);
println!(" Insert time: {:?}", insert_time);
println!(" Read time (1000 items): {:?}", read_time);
println!(" Memory usage: {} bytes", memory_usage);
println!(" Maplet stats: {:?}", stats.maplet_stats);
engine.close().await.unwrap();
}
async fn test_memory_efficiency() -> Result<(), Box<dyn std::error::Error>> {
println!("💾 Memory Efficiency Test");
println!("{}", "=".repeat(50));
let test_data = generate_test_data(10000);
let false_positive_rates = vec![0.001, 0.01, 0.1, 0.5];
for fpr in false_positive_rates {
let config = EngineConfig {
persistence_mode: PersistenceMode::Memory,
maplet: mappy_core::types::MapletConfig {
capacity: 10000,
false_positive_rate: fpr,
max_load_factor: 0.8,
auto_resize: false,
enable_deletion: true,
enable_merging: true,
},
..Default::default()
};
let engine = Engine::new(config).await?;
for (key, value) in &test_data {
engine.set(key.clone(), value.as_bytes().to_vec()).await?;
}
let memory_usage = engine.memory_usage().await?;
let stats = engine.stats().await?;
println!(" False Positive Rate: {:.1}%", fpr * 100.0);
println!(" Memory usage: {} bytes", memory_usage);
println!(" Maplet stats: {:?}", stats.maplet_stats);
engine.close().await?;
}
Ok(())
}
async fn test_concurrent_performance() -> Result<(), Box<dyn std::error::Error>> {
println!("🔄 Concurrent Performance Test");
println!("{}", "=".repeat(50));
let config = EngineConfig::default();
let engine = Engine::new(config).await?;
let start = Instant::now();
let handles: Vec<_> = (0..10)
.map(|i| {
let engine = engine.clone();
tokio::spawn(async move {
for j in 0..1000 {
let key = format!("concurrent_{}_{}", i, j);
let value = format!("value_{}_{}", i, j);
engine.set(key, value.into_bytes()).await.unwrap();
}
})
})
.collect();
for handle in handles {
handle.await?;
}
let concurrent_write_time = start.elapsed();
let start = Instant::now();
let read_handles: Vec<_> = (0..5)
.map(|i| {
let engine = engine.clone();
tokio::spawn(async move {
for j in 0..2000 {
let key = format!("concurrent_{}_{}", i % 10, j % 1000);
let _ = engine.get(&key).await.unwrap();
}
})
})
.collect();
for handle in read_handles {
handle.await?;
}
let concurrent_read_time = start.elapsed();
println!(
" Concurrent writes (10 tasks, 1000 items each): {:?}",
concurrent_write_time
);
println!(
" Concurrent reads (5 tasks, 2000 items each): {:?}",
concurrent_read_time
);
let stats = engine.stats().await?;
println!(" Final stats: {:?}", stats);
engine.close().await?;
Ok(())
}
trait EngineClone {
fn clone(&self) -> Self;
}
impl EngineClone for Engine {
fn clone(&self) -> Self {
unimplemented!("Engine cloning not implemented in this demo")
}
}