use super::timed::timed_pass;
use super::types::{
BenchBinding, BenchCall, BenchInvocation, BenchOutcome, BenchReading, BenchReport,
BenchRunRefusal, BenchTable, BenchTargetMismatch, PrimaryWorkPhase, WorkCurve,
WorkQualificationRefusal,
};
use super::work::{curve, judge};
use crate::runner::{lens_verdict, run_one};
fn target_mismatch(
binding: &BenchBinding,
invocation: &BenchInvocation,
) -> Option<BenchTargetMismatch> {
let preflight = binding.preflight().invocation().target();
let run = invocation.target();
if preflight.target() != run.target() {
return Some(BenchTargetMismatch::Target {
benchmark: run.target().clone(),
preflight: preflight.target().clone(),
});
}
if preflight.toolchain() != run.toolchain() {
return Some(BenchTargetMismatch::Toolchain {
benchmark: run.toolchain().clone(),
preflight: preflight.toolchain().clone(),
});
}
None
}
fn admit(table: &BenchTable, invocation: &BenchInvocation) -> Result<(), BenchRunRefusal> {
for binding in table.bindings() {
if let Some(mismatch) = target_mismatch(binding, invocation) {
return Err(BenchRunRefusal::PreflightTargetMismatch {
row: binding.row().key(),
mismatch,
});
}
}
Ok(())
}
fn primary(
binding: &BenchBinding,
call: BenchCall,
phase: PrimaryWorkPhase,
) -> Result<WorkCurve, BenchRunRefusal> {
curve(call, binding.row(), binding.attachment()).map_err(|refusal| {
BenchRunRefusal::WorkNotRecorded {
row: binding.row().key(),
phase,
refusal,
}
})
}
fn run_row(
binding: &BenchBinding,
invocation: &BenchInvocation,
) -> Result<BenchReading, BenchRunRefusal> {
let row = binding.row();
let preflight = run_one(
binding.preflight().binding(),
binding.preflight().invocation(),
);
if lens_verdict(&preflight).is_err() {
return Ok(BenchReading::recorded(
row,
invocation.target().clone(),
preflight,
BenchOutcome::PreflightRefused,
));
}
let attachment = binding.attachment();
let measured = primary(binding, attachment.measured(), PrimaryWorkPhase::Measured)?;
let planted_worse = primary(
binding,
attachment.planted_worse(),
PrimaryWorkPhase::PlantedWorse,
)?;
let judgment = judge(row, attachment, &measured, &planted_worse);
let outcome = match judgment.qualification() {
Err(WorkQualificationRefusal::PlantedWorseNotDistinguished { .. }) => {
BenchOutcome::PlantedWorseNotDistinguished {
measured,
planted_worse,
judgment,
}
}
Err(WorkQualificationRefusal::MeasuredRefused(_)) => BenchOutcome::PrimaryWorkRefused {
measured,
planted_worse,
judgment,
},
Ok(()) => {
let secondary = timed_pass(binding, invocation, &planted_worse).map_err(|refusal| {
BenchRunRefusal::SecondaryWorkRefused {
row: row.key(),
refusal,
}
})?;
BenchOutcome::Qualified {
measured,
planted_worse,
judgment,
secondary,
}
}
};
Ok(BenchReading::recorded(
row,
invocation.target().clone(),
preflight,
outcome,
))
}
pub fn run_all(
table: &BenchTable,
invocation: &BenchInvocation,
) -> Result<BenchReport, BenchRunRefusal> {
admit(table, invocation)?;
let readings = table
.bindings()
.iter()
.map(|binding| run_row(binding, invocation))
.collect::<Result<Vec<_>, _>>()?;
Ok(BenchReport::recorded(
table.name(),
table.provenance(),
readings,
))
}