chunk_cache_bench/benches/cache_bench.rs (169 lines of code) (raw):

use std::time::Duration; use std::u64; use chunk_cache::{random_key, random_range, DiskCache, RandomEntryIterator}; use chunk_cache_bench::sccache::SCCache; use chunk_cache_bench::solid_cache::SolidCache; use chunk_cache_bench::ChunkCacheExt; use criterion::{criterion_group, BenchmarkId, Criterion}; use rand::rngs::StdRng; use rand::{thread_rng, SeedableRng}; use tempdir::TempDir; use tokio::task::JoinSet; const SEED: u64 = 42; const NUM_PUTS: u64 = 100; const RANGE_LEN: u32 = 1 << 20; // 1 MB const CAPACITY: u64 = 1 << 30; // 1 GB const NUM_CONCURRENT_TASKS: u8 = 8; fn benchmark_cache_get<T: ChunkCacheExt>(c: &mut Criterion) { let cache_root = TempDir::new(format!("benchmark_cache_get_{}", T::name()).as_str()).unwrap(); let cache = T::_initialize(cache_root.path().to_path_buf(), CAPACITY).unwrap(); let mut rng = StdRng::seed_from_u64(SEED); let mut it: RandomEntryIterator<StdRng> = RandomEntryIterator::from_seed(SEED).with_range_len(RANGE_LEN); for _ in 0..NUM_PUTS { let (key, range, offsets, data) = it.next().unwrap(); cache.put(&key, &range, &offsets, &data).unwrap(); } let name = format!("cache_get_{}", T::name()); c.bench_function(name.as_str(), |b| { b.iter(|| { let key = random_key(&mut rng); let range = random_range(&mut rng); cache.get(&key, &range).unwrap(); }) }); } fn benchmark_cache_get_mt<T: ChunkCacheExt + 'static>(c: &mut Criterion) { let cache_root = TempDir::new(format!("benchmark_cache_get_mt_{}", T::name()).as_str()).unwrap(); let cache = T::_initialize(cache_root.path().to_path_buf(), CAPACITY).unwrap(); let mut it: RandomEntryIterator<StdRng> = RandomEntryIterator::from_seed(SEED).with_range_len(RANGE_LEN); for _ in 0..NUM_PUTS { let (key, range, offsets, data) = it.next().unwrap(); cache.put(&key, &range, &offsets, &data).unwrap(); } let rt = tokio::runtime::Runtime::new().unwrap(); c.bench_with_input(BenchmarkId::new("cache_get_mt", T::name()), &0, |b, _| { b.to_async(&rt).iter(|| async { let mut handles = JoinSet::new(); for _ in 0..NUM_CONCURRENT_TASKS { let c = cache.clone(); handles.spawn(async move { let mut rng = thread_rng(); let key = random_key(&mut rng); let range = random_range(&mut rng); c.get(&key, &range).unwrap() }); } handles.join_all().await; }); }); } fn benchmark_cache_put_mt<T: ChunkCacheExt + 'static>(c: &mut Criterion) { let cache_root = TempDir::new(format!("benchmark_cache_put_mt_{}", T::name()).as_str()).unwrap(); let cache = T::_initialize(cache_root.path().to_path_buf(), CAPACITY).unwrap(); let mut it: RandomEntryIterator<StdRng> = RandomEntryIterator::from_seed(SEED); let mut total_bytes = 0; while total_bytes < CAPACITY { let (key, range, chunk_byte_indices, data) = it.next().unwrap(); cache.put(&key, &range, &chunk_byte_indices, &data).unwrap(); total_bytes += data.len() as u64; } let rt = tokio::runtime::Runtime::new().unwrap(); c.bench_with_input(BenchmarkId::new("cache_put_mt", T::name()), &0, |b, _| { b.to_async(&rt).iter(|| async { let mut handles = JoinSet::new(); for _ in 0..NUM_CONCURRENT_TASKS { let c = cache.clone(); handles.spawn(async move { let mut it = RandomEntryIterator::new(thread_rng()); let (key, range, offsets, data) = it.next().unwrap(); c.put(&key, &range, &offsets, &data).unwrap(); }); } handles.join_all().await; }); }); } fn benchmark_cache_put<T: ChunkCacheExt + 'static>(c: &mut Criterion) { let cache_root = TempDir::new(format!("benchmark_cache_put_{}", T::name()).as_str()).unwrap(); let cache = T::_initialize(cache_root.path().to_path_buf(), CAPACITY).unwrap(); let mut it: RandomEntryIterator<StdRng> = RandomEntryIterator::from_seed(SEED); let mut total_bytes = 0; while total_bytes < CAPACITY { let (key, range, chunk_byte_indices, data) = it.next().unwrap(); cache.put(&key, &range, &chunk_byte_indices, &data).unwrap(); total_bytes += data.len() as u64; } let name = format!("cache_put_{}", T::name()); c.bench_function(name.as_str(), |b| { b.iter(|| { let (key, range, offsets, data) = it.next().unwrap(); cache.put(&key, &range, &offsets, &data).unwrap(); }) }); } fn benchmark_cache_get_hits<T: ChunkCacheExt + 'static>(c: &mut Criterion) { let cache_root = TempDir::new(format!("benchmark_cache_get_hits_{}", T::name()).as_str()).unwrap(); let cache = T::_initialize(cache_root.path().to_path_buf(), CAPACITY).unwrap(); let mut it: RandomEntryIterator<StdRng> = RandomEntryIterator::from_seed(SEED).with_range_len(RANGE_LEN); let mut kr = Vec::with_capacity(NUM_PUTS as usize); for _ in 0..NUM_PUTS { let (key, range, offsets, data) = it.next().unwrap(); cache.put(&key, &range, &offsets, &data).unwrap(); kr.push((key, range)); } let mut i: usize = 0; let name = format!("cache_get_hit_{}", T::name()); c.bench_function(name.as_str(), |b| { b.iter(|| { let (key, range) = &kr[i]; cache.get(key, range).unwrap().unwrap(); i = (i + 1) % NUM_PUTS as usize; }) }); } criterion_group!( name = benches_get; config = Criterion::default(); targets = benchmark_cache_get::<DiskCache>, benchmark_cache_get::<SCCache>, benchmark_cache_get::<SolidCache>, ); criterion_group!( name = benches_get_hits; config = Criterion::default().measurement_time(Duration::from_secs(30)); targets = benchmark_cache_get_hits::<DiskCache>, benchmark_cache_get_hits::<SCCache>, benchmark_cache_get_hits::<SolidCache>, ); criterion_group!( name = benches_put; config = Criterion::default().measurement_time(Duration::from_secs(30)); targets = benchmark_cache_put::<DiskCache>, benchmark_cache_put::<SCCache>, benchmark_cache_put::<SolidCache>, ); criterion_group!( name = benches_get_multithreaded; config = Criterion::default(); targets = benchmark_cache_get_mt::<DiskCache>, benchmark_cache_get_mt::<SCCache>, ); criterion_group!( name = benches_put_multithreaded; config = Criterion::default().measurement_time(Duration::from_secs(30)); targets = benchmark_cache_put_mt::<DiskCache>, benchmark_cache_put_mt::<SCCache>, ); fn main() { benches_get(); benches_get_hits(); benches_put(); benches_get_multithreaded(); benches_put_multithreaded(); Criterion::default().configure_from_args().final_summary(); }