use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use hashtree::{HashTree, HashTreeConfig, MemoryStore, BEP52_CHUNK_SIZE, DEFAULT_CHUNK_SIZE};
use std::sync::Arc;
fn random_data(size: usize) -> Vec<u8> {
use rand::Rng;
let mut rng = rand::thread_rng();
(0..size).map(|_| rng.gen()).collect()
}
fn bench_tree_builder(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("tree_builder");
let sizes = [(1, "1MB"), (10, "10MB"), (50, "50MB")];
let chunk_sizes = [("256KB", DEFAULT_CHUNK_SIZE), ("16KB", BEP52_CHUNK_SIZE)];
for (size_mb, size_name) in sizes {
let size = size_mb * 1024 * 1024;
let data = random_data(size);
group.throughput(Throughput::Bytes(size as u64));
for (chunk_name, chunk_size) in &chunk_sizes {
group.bench_with_input(
BenchmarkId::new(*chunk_name, size_name),
&data,
|b, data| {
b.iter(|| {
rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store)
.with_chunk_size(*chunk_size)
.public();
let tree = HashTree::new(config);
tree.put(black_box(data)).await.unwrap()
})
})
},
);
}
}
group.finish();
}
fn bench_tree_reader(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("tree_reader");
let sizes = [(1, "1MB"), (10, "10MB")];
let chunk_sizes = [("256KB", DEFAULT_CHUNK_SIZE), ("16KB", BEP52_CHUNK_SIZE)];
for (size_mb, size_name) in sizes {
let size = size_mb * 1024 * 1024;
let data = random_data(size);
group.throughput(Throughput::Bytes(size as u64));
for (chunk_name, chunk_size) in &chunk_sizes {
let (tree, cid) = rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store)
.with_chunk_size(*chunk_size)
.public();
let tree = HashTree::new(config);
let cid = tree.put(&data).await.unwrap();
(tree, cid)
});
group.bench_with_input(
BenchmarkId::new(*chunk_name, size_name),
&(tree, cid),
|b, (tree, cid)| {
b.iter(|| rt.block_on(async { tree.get(black_box(cid), None).await.unwrap() }))
},
);
}
}
group.finish();
}
fn bench_roundtrip(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("roundtrip");
let size = 10 * 1024 * 1024; let data = random_data(size);
group.throughput(Throughput::Bytes(size as u64));
for (name, chunk_size) in [("256KB", DEFAULT_CHUNK_SIZE), ("16KB", BEP52_CHUNK_SIZE)] {
group.bench_with_input(BenchmarkId::new(name, "10MB"), &data, |b, data| {
b.iter(|| {
rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store)
.with_chunk_size(chunk_size)
.public();
let tree = HashTree::new(config);
let cid = tree.put(black_box(data)).await.unwrap();
tree.get(&cid, None).await.unwrap()
})
})
});
}
group.finish();
}
#[cfg(feature = "encryption")]
fn bench_encrypted_write(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("encrypted_write");
let sizes = [(1, "1MB"), (10, "10MB")];
for (size_mb, size_name) in sizes {
let size = size_mb * 1024 * 1024;
let data = random_data(size);
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(BenchmarkId::new("plain", size_name), &data, |b, data| {
b.iter(|| {
rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store).public();
let tree = HashTree::new(config);
tree.put(black_box(data)).await.unwrap()
})
})
});
group.bench_with_input(
BenchmarkId::new("encrypted", size_name),
&data,
|b, data| {
b.iter(|| {
rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store); let tree = HashTree::new(config);
tree.put(black_box(data)).await.unwrap()
})
})
},
);
}
group.finish();
}
#[cfg(feature = "encryption")]
fn bench_encrypted_read(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("encrypted_read");
let sizes = [(1, "1MB"), (10, "10MB")];
for (size_mb, size_name) in sizes {
let size = size_mb * 1024 * 1024;
let data = random_data(size);
group.throughput(Throughput::Bytes(size as u64));
let (plain_tree, plain_cid) = rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store).public();
let tree = HashTree::new(config);
let cid = tree.put(&data).await.unwrap();
(tree, cid)
});
group.bench_with_input(
BenchmarkId::new("plain", size_name),
&(plain_tree, plain_cid),
|b, (tree, cid)| {
b.iter(|| rt.block_on(async { tree.get(black_box(cid), None).await.unwrap() }))
},
);
let (enc_tree, enc_cid) = rt.block_on(async {
let store = Arc::new(MemoryStore::new());
let config = HashTreeConfig::new(store); let tree = HashTree::new(config);
let cid = tree.put(&data).await.unwrap();
(tree, cid)
});
group.bench_with_input(
BenchmarkId::new("encrypted", size_name),
&(enc_tree, enc_cid),
|b, (tree, cid)| {
b.iter(|| rt.block_on(async { tree.get(black_box(cid), None).await.unwrap() }))
},
);
}
group.finish();
}
#[cfg(feature = "encryption")]
criterion_group!(
benches,
bench_tree_builder,
bench_tree_reader,
bench_roundtrip,
bench_encrypted_write,
bench_encrypted_read,
);
#[cfg(not(feature = "encryption"))]
criterion_group!(
benches,
bench_tree_builder,
bench_tree_reader,
bench_roundtrip,
);
criterion_main!(benches);