use std::collections::HashMap;
use std::path::PathBuf;
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use modde_core::resolver::{ModId, ResolvedLoadOrder};
use modde_core::vfs::SymlinkFarm;
fn make_fixture(
store_root: &std::path::Path,
n_mods: usize,
files_per_mod: usize,
) -> (ResolvedLoadOrder, HashMap<ModId, Vec<(String, PathBuf)>>) {
let mut order = Vec::with_capacity(n_mods);
let mut mod_files: HashMap<ModId, Vec<(String, PathBuf)>> = HashMap::with_capacity(n_mods);
for m in 0..n_mods {
let mod_id_str = format!("mod_{m:05}");
let mod_id = ModId::from(mod_id_str.as_str());
let mod_dir = store_root.join(&mod_id_str);
std::fs::create_dir_all(&mod_dir).expect("create mod dir");
let mut files = Vec::with_capacity(files_per_mod);
for f in 0..files_per_mod {
let rel = format!("data/{mod_id_str}/file_{f:05}.dat");
let src = mod_dir.join(format!("file_{f:05}.dat"));
std::fs::write(&src, b"x").expect("write source");
files.push((rel, src));
}
mod_files.insert(mod_id.clone(), files);
order.push(mod_id);
}
(ResolvedLoadOrder { order }, mod_files)
}
fn bench_build(c: &mut Criterion) {
let mut group = c.benchmark_group("symlink_farm_build");
let store = tempfile::TempDir::new().unwrap();
for &(n_mods, files_per_mod) in &[(100, 10), (100, 100), (500, 100)] {
let total = n_mods * files_per_mod;
let (resolved, mod_files) = make_fixture(store.path(), n_mods, files_per_mod);
group.throughput(Throughput::Elements(total as u64));
group.bench_with_input(
BenchmarkId::from_parameter(format!("{n_mods}m_x_{files_per_mod}f")),
&(resolved, mod_files),
|b, (resolved, mod_files)| {
b.iter(|| {
let _farm =
SymlinkFarm::build("bench", resolved, mod_files, None, None).unwrap();
});
},
);
}
group.finish();
}
fn bench_materialize_and_deploy(c: &mut Criterion) {
let mut group = c.benchmark_group("symlink_farm_materialize_deploy");
group.sample_size(10);
for &(n_mods, files_per_mod) in &[(50, 20), (100, 100)] {
let total = n_mods * files_per_mod;
group.throughput(Throughput::Elements(total as u64));
group.bench_with_input(
BenchmarkId::from_parameter(format!("{n_mods}m_x_{files_per_mod}f")),
&(n_mods, files_per_mod),
|b, &(n_mods, files_per_mod)| {
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap();
b.iter_with_setup(
|| {
let store = tempfile::TempDir::new().unwrap();
let target = tempfile::TempDir::new().unwrap();
let staging = tempfile::TempDir::new().unwrap();
let (resolved, mod_files) =
make_fixture(store.path(), n_mods, files_per_mod);
let built =
SymlinkFarm::build("bench", &resolved, &mod_files, None, None).unwrap();
let farm = SymlinkFarm::from_links(
staging.path().to_path_buf(),
built.links.clone(),
);
(farm, target, store, staging)
},
|(farm, target, _store, _staging)| {
rt.block_on(async {
let materialized = farm.materialize().await.unwrap();
materialized.deploy_to(target.path()).await.unwrap();
});
},
);
},
);
}
group.finish();
}
criterion_group!(benches, bench_build, bench_materialize_and_deploy);
criterion_main!(benches);