use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use fsys::builder::Builder;
use fsys::method::Method;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
static C: AtomicU64 = AtomicU64::new(0);
const PAYLOADS: &[(usize, &str)] = &[
(4 * 1024, "4KiB"),
(64 * 1024, "64KiB"),
(1024 * 1024, "1MiB"),
(16 * 1024 * 1024, "16MiB"),
];
const METHODS: &[(Method, &str)] = &[
(Method::Sync, "sync"),
(Method::Data, "data"),
(Method::Direct, "direct"),
(Method::Mmap, "mmap"),
];
const BATCH_N: usize = 8;
fn tmp_path(tag: &str) -> PathBuf {
let n = C.fetch_add(1, Ordering::Relaxed);
std::env::temp_dir().join(format!(
"fsys_bench_matrix_{}_{}_{}.dat",
std::process::id(),
n,
tag
))
}
fn tmp_dir(tag: &str) -> PathBuf {
let n = C.fetch_add(1, Ordering::Relaxed);
let dir = std::env::temp_dir().join(format!(
"fsys_bench_matrix_{}_{}_{}",
std::process::id(),
n,
tag
));
std::fs::create_dir_all(&dir).expect("mkdir");
dir
}
fn bench_write(c: &mut Criterion) {
let mut group = c.benchmark_group("matrix_write");
for &(method, m_tag) in METHODS {
let handle = Builder::new().method(method).build().expect("build handle");
for &(size, sz_tag) in PAYLOADS {
let data = vec![0xA5u8; size];
let path = tmp_path(&format!("{m_tag}_{sz_tag}_w"));
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(BenchmarkId::new(m_tag, sz_tag), &path, |b, p: &PathBuf| {
b.iter(|| handle.write(p, &data).expect("write"));
});
let _ = std::fs::remove_file(&path);
}
}
group.finish();
}
fn bench_read(c: &mut Criterion) {
let mut group = c.benchmark_group("matrix_read");
for &(method, m_tag) in METHODS {
let handle = Builder::new().method(method).build().expect("build handle");
for &(size, sz_tag) in PAYLOADS {
let data = vec![0x5Au8; size];
let path = tmp_path(&format!("{m_tag}_{sz_tag}_r"));
handle.write(&path, &data).expect("priming write");
group.throughput(Throughput::Bytes(size as u64));
group.bench_with_input(BenchmarkId::new(m_tag, sz_tag), &path, |b, p: &PathBuf| {
b.iter(|| {
let _ = handle.read(p).expect("read");
});
});
let _ = std::fs::remove_file(&path);
}
}
group.finish();
}
fn bench_write_batch(c: &mut Criterion) {
let mut group = c.benchmark_group("matrix_write_batch_8");
for &(method, m_tag) in METHODS {
let handle = Builder::new().method(method).build().expect("build handle");
for &(size, sz_tag) in PAYLOADS {
if size >= 16 * 1024 * 1024 {
continue;
}
let data = vec![0x33u8; size];
let dir = tmp_dir(&format!("{m_tag}_{sz_tag}_b"));
let paths: Vec<PathBuf> = (0..BATCH_N).map(|i| dir.join(format!("op_{i}"))).collect();
group.throughput(Throughput::Bytes((size * BATCH_N) as u64));
group.bench_with_input(
BenchmarkId::new(m_tag, sz_tag),
&paths,
|b, ps: &Vec<PathBuf>| {
b.iter(|| {
let batch: Vec<(&Path, &[u8])> =
ps.iter().map(|p| (p.as_path(), data.as_slice())).collect();
handle.write_batch(&batch).expect("write_batch");
});
},
);
let _ = std::fs::remove_dir_all(&dir);
}
}
group.finish();
}
fn bench_read_after_write(c: &mut Criterion) {
let mut group = c.benchmark_group("matrix_read_after_write");
for &(method, m_tag) in METHODS {
let handle = Builder::new().method(method).build().expect("build handle");
for &(size, sz_tag) in PAYLOADS {
let data = vec![0xC3u8; size];
let path = tmp_path(&format!("{m_tag}_{sz_tag}_rw"));
group.throughput(Throughput::Bytes((size * 2) as u64));
group.bench_with_input(BenchmarkId::new(m_tag, sz_tag), &path, |b, p: &PathBuf| {
b.iter(|| {
handle.write(p, &data).expect("write");
let _ = handle.read(p).expect("read");
});
});
let _ = std::fs::remove_file(&path);
}
}
group.finish();
}
criterion_group!(
matrix,
bench_write,
bench_read,
bench_write_batch,
bench_read_after_write
);
criterion_main!(matrix);