#[cfg(feature = "async-std")] use async_std::fs as afs; #[cfg(feature = "link_to")] use std::path::PathBuf; #[cfg(all(test, feature = "tokio"))] use tokio::fs as afs; #[cfg(all(test, feature = "async-std"))] pub use async_std::task::block_on; #[cfg(all(test, feature = "tokio"))] lazy_static::lazy_static! { static ref TOKIO_RUNTIME: tokio::runtime::Runtime = tokio::runtime::Runtime::new().unwrap(); } #[cfg(all(test, feature = "tokio"))] #[inline] pub fn block_on(future: F) -> T where F: std::future::Future, { TOKIO_RUNTIME.block_on(future) } use std::fs::{self, File}; use std::io::prelude::*; use criterion::{black_box, criterion_group, criterion_main, Criterion}; const NUM_REPEATS: usize = 10; fn baseline_read_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let path = tmp.path().join("test_file"); let data = b"hello world"; let mut fd = File::create(&path).unwrap(); fd.write_all(data).unwrap(); drop(fd); c.bench_function("baseline_read_sync", move |b| { b.iter(|| fs::read(&path).unwrap()) }); } fn baseline_read_many_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let paths: Vec<_> = (0..) .take(NUM_REPEATS) .map(|i| tmp.path().join(format!("test_file_{i}"))) .collect(); let data = b"hello world"; for path in paths.iter() { let mut fd = File::create(path).unwrap(); fd.write_all(data).unwrap(); drop(fd); } c.bench_function("baseline_read_many_sync", move |b| { b.iter(|| { for path in paths.iter() { fs::read(black_box(&path)).unwrap(); } }) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn baseline_read_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let path = tmp.path().join("test_file"); let data = b"hello world"; let mut fd = File::create(&path).unwrap(); fd.write_all(data).unwrap(); drop(fd); c.bench_function("baseline_read_async", move |b| { b.iter(|| block_on(afs::read(&path))) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn baseline_read_many_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let paths: Vec<_> = (0..) .take(NUM_REPEATS) .map(|i| tmp.path().join(format!("test_file_{i}"))) .collect(); let data = b"hello world"; for path in paths.iter() { let mut fd = File::create(path).unwrap(); fd.write_all(data).unwrap(); drop(fd); } c.bench_function("baseline_read_many_async", move |b| { b.iter(|| { let tasks = paths.iter().map(|path| afs::read(black_box(path))); block_on(futures::future::join_all(tasks)); }) }); } fn read_hash_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = b"hello world".to_vec(); let sri = cacache::write_sync(&cache, "hello", data).unwrap(); c.bench_function("get::data_hash_sync", move |b| { b.iter(|| cacache::read_hash_sync(black_box(&cache), black_box(&sri)).unwrap()) }); } fn read_hash_sync_xxh3(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = b"hello world".to_vec(); let sri = cacache::write_sync_with_algo(cacache::Algorithm::Xxh3, &cache, "hello", data).unwrap(); c.bench_function("get::data_hash_sync::xxh3", move |b| { b.iter(|| cacache::read_hash_sync(black_box(&cache), black_box(&sri)).unwrap()) }); } fn read_hash_many_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data: Vec<_> = (0..) .take(NUM_REPEATS) .map(|i| format!("test_file_{i}")) .collect(); let sris: Vec<_> = data .iter() .map(|datum| cacache::write_sync(&cache, "hello", datum).unwrap()) .collect(); c.bench_function("get::data_hash_many_sync", move |b| { b.iter(|| { for sri in sris.iter() { cacache::read_hash_sync(black_box(&cache), black_box(sri)).unwrap(); } }) }); } fn read_hash_many_sync_xxh3(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data: Vec<_> = (0..) .take(NUM_REPEATS) .map(|i| format!("test_file_{i}")) .collect(); let sris: Vec<_> = data .iter() .map(|datum| { cacache::write_sync_with_algo(cacache::Algorithm::Xxh3, &cache, "hello", datum).unwrap() }) .collect(); c.bench_function("get::data_hash_many_sync::xxh3", move |b| { b.iter(|| { for sri in sris.iter() { cacache::read_hash_sync(black_box(&cache), black_box(sri)).unwrap(); } }) }); } fn read_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = b"hello world".to_vec(); cacache::write_sync(&cache, "hello", data).unwrap(); c.bench_function("get::data_sync", move |b| { b.iter(|| cacache::read_sync(black_box(&cache), black_box(String::from("hello"))).unwrap()) }); } fn read_hash_sync_big_data(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = vec![1; 1024 * 1024 * 5]; let sri = cacache::write_sync(&cache, "hello", data).unwrap(); c.bench_function("get_hash_big_data", move |b| { b.iter(|| cacache::read_hash_sync(black_box(&cache), black_box(&sri)).unwrap()) }); } fn read_hash_sync_big_data_xxh3(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = vec![1; 1024 * 1024 * 5]; let sri = cacache::write_sync_with_algo(cacache::Algorithm::Xxh3, &cache, "hello", data).unwrap(); c.bench_function("get_hash_big_data::xxh3", move |b| { b.iter(|| cacache::read_hash_sync(black_box(&cache), black_box(&sri)).unwrap()) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn read_hash_many_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data: Vec<_> = (0..) .take(NUM_REPEATS) .map(|i| format!("test_file_{i}")) .collect(); let sris: Vec<_> = data .iter() .map(|datum| cacache::write_sync(&cache, "hello", datum).unwrap()) .collect(); c.bench_function("get::data_hash_many", move |b| { b.iter(|| { let tasks = sris .iter() .map(|sri| cacache::read_hash(black_box(&cache), black_box(sri))); block_on(futures::future::join_all(tasks)); }) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn read_hash_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = b"hello world".to_vec(); let sri = cacache::write_sync(&cache, "hello", data).unwrap(); c.bench_function("get::data_hash", move |b| { b.iter(|| block_on(cacache::read_hash(black_box(&cache), black_box(&sri))).unwrap()) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn read_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = b"hello world".to_vec(); cacache::write_sync(&cache, "hello", data).unwrap(); c.bench_function("get::data", move |b| { b.iter(|| block_on(cacache::read(black_box(&cache), black_box("hello"))).unwrap()) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn read_hash_async_big_data(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); let data = vec![1; 1024 * 1024 * 5]; let sri = cacache::write_sync(&cache, "hello", data).unwrap(); c.bench_function("get::data_big_data", move |b| { b.iter(|| block_on(cacache::read_hash(black_box(&cache), black_box(&sri))).unwrap()) }); } fn write_hash(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("put::data::sync", move |b| { b.iter_custom(|iters| { let start = std::time::Instant::now(); for i in 0..iters { cacache::write_hash_sync(&cache, format!("hello world{i}")).unwrap(); } start.elapsed() }) }); } fn write_hash_xxh3(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("put::data::sync::xxh3", move |b| { b.iter_custom(|iters| { let start = std::time::Instant::now(); for i in 0..iters { cacache::write_hash_sync_with_algo( cacache::Algorithm::Xxh3, &cache, format!("hello world{i}"), ) .unwrap(); } start.elapsed() }) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn write_hash_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("put::data", move |b| { b.iter_custom(|iters| { let start = std::time::Instant::now(); for i in 0..iters { block_on(cacache::write_hash(&cache, format!("hello world{i}"))).unwrap(); } start.elapsed() }) }); } #[cfg(any(feature = "async-std", feature = "tokio"))] fn write_hash_async_xxh3(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("put::data::xxh3", move |b| { b.iter_custom(|iters| { let start = std::time::Instant::now(); for i in 0..iters { block_on(cacache::write_hash_with_algo( cacache::Algorithm::Xxh3, &cache, format!("hello world{i}"), )) .unwrap(); } start.elapsed() }) }); } #[cfg(feature = "link_to")] fn create_tmpfile(tmp: &tempfile::TempDir, buf: &[u8]) -> PathBuf { let dir = tmp.path().to_owned(); let target = dir.join("target-file"); std::fs::create_dir_all(&target.parent().unwrap()).unwrap(); let mut file = File::create(target.clone()).unwrap(); file.write_all(buf).unwrap(); file.flush().unwrap(); target } #[cfg(feature = "link_to")] #[cfg(any(feature = "async-std", feature = "tokio"))] fn link_to_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let target = create_tmpfile(&tmp, b"hello world"); let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("link_to::file", move |b| { b.iter_custom(|iters| { let start = std::time::Instant::now(); for i in 0..iters { block_on(cacache::link_to( &cache, format!("key{}", i), target.clone(), )) .unwrap(); } start.elapsed() }) }); } #[cfg(all(feature = "link_to", any(feature = "async-std", feature = "tokio")))] fn link_to_hash_async(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let target = create_tmpfile(&tmp, b"hello world"); let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("link_to::file_hash", move |b| { b.iter(|| block_on(cacache::link_to_hash(&cache, target.clone())).unwrap()) }); } #[cfg(feature = "link_to")] fn link_to_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let target = create_tmpfile(&tmp, b"hello world"); let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("link_to::file_sync", move |b| { b.iter_custom(|iters| { let start = std::time::Instant::now(); for i in 0..iters { cacache::link_to_sync(&cache, format!("key{}", i), target.clone()).unwrap(); } start.elapsed() }) }); } #[cfg(feature = "link_to")] fn link_to_hash_sync(c: &mut Criterion) { let tmp = tempfile::tempdir().unwrap(); let target = create_tmpfile(&tmp, b"hello world"); let tmp = tempfile::tempdir().unwrap(); let cache = tmp.path().to_owned(); c.bench_function("link_to::file_hash_sync", move |b| { b.iter(|| cacache::link_to_hash_sync(&cache, target.clone()).unwrap()) }); } criterion_group!( benches, baseline_read_sync, baseline_read_many_sync, write_hash, write_hash_xxh3, read_hash_sync, read_hash_sync_xxh3, read_hash_many_sync, read_hash_many_sync_xxh3, read_sync, read_hash_sync_big_data, read_hash_sync_big_data_xxh3, ); #[cfg(any(feature = "async-std", feature = "tokio"))] criterion_group!( benches_async, baseline_read_async, baseline_read_many_async, read_hash_async, read_hash_many_async, read_async, write_hash_async, write_hash_async_xxh3, read_hash_async_big_data, ); #[cfg(all(feature = "link_to", any(feature = "async-std", feature = "tokio")))] criterion_group!(link_to_benches_async, link_to_async, link_to_hash_async,); #[cfg(feature = "link_to")] criterion_group!(link_to_benches, link_to_sync, link_to_hash_sync); #[cfg(all( feature = "link_to", not(any(feature = "async-std", feature = "tokio")) ))] criterion_main!(benches, link_to_benches); #[cfg(all( not(feature = "link_to"), any(feature = "async-std", feature = "tokio") ))] criterion_main!(benches, benches_async); #[cfg(all(feature = "link_to", any(feature = "async-std", feature = "tokio")))] criterion_main!( benches, benches_async, link_to_benches, link_to_benches_async ); #[cfg(all( not(feature = "link_to"), not(any(feature = "async-std", feature = "tokio")) ))] criterion_main!(benches);