use criterion::{Criterion, Throughput, black_box};
use molframe::{
Cost, OperationMetadata, ReadOptions, Workflow, WorkflowInputs, read_bytes, write_mmcif,
};
use molframe_bench::{Sample, input, structure, structure_with_atoms};
fn bench_facade(c: &mut Criterion) {
let bytes = match Sample::Medium.cif() {
Some(bytes) => bytes.to_vec(),
None => panic!("facade benchmark requires the medium CIF fixture"),
};
let options = ReadOptions::new();
let input = input(&bytes);
let (structure, _) = match molframe_cif::read(&input, &options) {
Ok(result) => result,
Err(findings) => panic!("facade fixture failed: {findings:?}"),
};
let structure: molframe::Structure = structure.into();
let mut group = c.benchmark_group("facade_io");
group.throughput(Throughput::Bytes(bytes.len() as u64));
group.bench_function("read_bytes", |b| {
b.iter(|| black_box(read_bytes(bytes.clone(), Some("4hhb.cif"), &options)));
});
group.throughput(Throughput::Elements(u64::from(structure.atom_count())));
group.bench_function("write_mmcif", |b| {
b.iter(|| black_box(write_mmcif(&structure)));
});
group.finish();
let coordinates = structure.coordinates().to_vec();
let build = || {
let mut workflow = Workflow::new();
let input = match workflow.input::<Vec<[f32; 3]>>("coordinates", Cost::Borrow) {
Ok(input) => input,
Err(error) => panic!("workflow input failed: {error}"),
};
let centroid = match workflow.map(
input,
OperationMetadata::new("geometry.centroid", Cost::Materialize)
.with_cse_key("geometry.centroid"),
|positions, _| {
let mut sum = [0.0_f64; 3];
for position in positions {
for axis in 0..3 {
sum[axis] += f64::from(position[axis]);
}
}
let Ok(count) = u32::try_from(positions.len()) else {
return Err(molframe::WorkflowError::Operation {
operation: "geometry.centroid",
message: "coordinate count exceeds u32".into(),
});
};
let scale = 1.0 / f64::from(count);
Ok(sum.map(|value| value * scale))
},
) {
Ok(centroid) => centroid,
Err(error) => panic!("workflow operation failed: {error}"),
};
if let Err(error) = workflow.output("centroid", centroid) {
panic!("workflow output failed: {error}");
}
workflow
};
c.bench_function("workflow_compile", |b| {
b.iter(|| {
let workflow = build();
black_box(workflow.compile())
});
});
let compiled = match build().compile() {
Ok(compiled) => compiled,
Err(error) => panic!("workflow compilation failed: {error}"),
};
let mut inputs = WorkflowInputs::new();
inputs.insert("coordinates", coordinates);
let context = molframe::ExecutionContext::default();
c.bench_function("workflow_reuse", |b| {
b.iter(|| black_box(compiled.run(&inputs, &context)));
});
}
fn bench_handoff(c: &mut Criterion) {
let structure: molframe::Structure = (*structure_with_atoms(100_000)).clone().into();
assert!(std::ptr::eq(
structure.coordinates().as_ptr(),
structure.coordinates().as_ptr()
));
let mut group = c.benchmark_group("facade_handoff");
group.bench_function("positions_slice", |b| {
b.iter(|| black_box(black_box(&structure).coordinates()));
});
group.finish();
}
fn bench_enrich(c: &mut Criterion) {
let structure: molframe::Structure = structure(Sample::Large).into();
let mut group = c.benchmark_group("facade_enrich");
group.throughput(Throughput::Elements(u64::from(structure.atom_count())));
group.bench_function("1aon", |b| {
b.iter(|| black_box(molframe::perceive(black_box(&structure))));
});
group.finish();
}
fn main() {
let mut criterion = Criterion::default().configure_from_args();
bench_facade(&mut criterion);
bench_handoff(&mut criterion);
bench_enrich(&mut criterion);
criterion.final_summary();
}