in resctl-bench/src/bench/iocost_tune.rs [1214:1327]
fn fit_lines(&mut self, gran: f64, dir: DataShape) -> Result<()> {
if self.points.len() == 0 {
return Ok(());
}
let start = self.points.iter().next().unwrap().x;
let end = self.points.iter().last().unwrap().x;
let intvs = ((end - start) / gran).ceil() as u32 + 1;
if intvs <= 1 {
return Ok(());
}
let gran = (end - start) / (intvs - 1) as f64;
// We want to prefer line fittings with fewer components. Discount
// error from the previous stage. Also, make sure each line segment
// is at least 10% of the vrate range.
const ERROR_DISCOUNT: f64 = 0.975;
const MIN_SEG_DIST: f64 = 10.0;
// Start with mean flat line which is acceptable for both dirs.
let mean = statistical::mean(&self.points.iter().map(|p| p.y).collect::<Vec<f64>>());
let range = Self::vrange(&self.points);
let mut best_lines = DataLines {
range,
left: DataPoint::new(range.0, mean),
right: DataPoint::new(range.1, mean),
};
let best_error =
RefCell::new(Self::calc_error(self.points.iter(), &best_lines) * ERROR_DISCOUNT);
let mut try_and_pick = |fit: &(dyn Fn() -> Option<DataLines>)| -> Result<bool> {
if prog_exiting() {
bail!("Program exiting");
}
if let Some(lines) = fit() {
if lines.left.y <= 0.0 || lines.right.y <= 0.0 {
return Ok(false);
}
match dir {
DataShape::Any => {}
DataShape::Inc => {
if lines.left.y > lines.right.y {
return Ok(false);
}
}
DataShape::Dec => {
if lines.left.y < lines.right.y {
return Ok(false);
}
}
}
let error = Self::calc_error(self.points.iter(), &lines);
if error < *best_error.borrow() {
trace!(
"fit-best: ({:.3}, {:.3}) - ({:.3}, {:.3}) \
start={:.3} end={:.3} MIN_SEG_DIST={:.3}",
lines.left.x,
lines.left.y,
lines.right.x,
lines.right.y,
start,
end,
MIN_SEG_DIST
);
best_lines = lines;
best_error.replace(error);
return Ok(true);
}
}
Ok(false)
};
// Try simple linear regression.
if self.points.len() > 3 && try_and_pick(&|| Some(Self::fit_line(&self.points)))? {
let be = *best_error.borrow();
best_error.replace(be * ERROR_DISCOUNT);
}
// Try one flat line and one slope.
let mut updated = false;
for i in 0..intvs {
let infl = start + i as f64 * gran;
if infl < start + MIN_SEG_DIST || infl > end - MIN_SEG_DIST {
continue;
}
updated |= try_and_pick(&|| Self::fit_slope_with_vleft(&self.points, infl))?;
updated |= try_and_pick(&|| Self::fit_slope_with_vright(&self.points, infl))?;
}
if updated {
let be = *best_error.borrow();
best_error.replace(be * ERROR_DISCOUNT);
}
// Try two flat lines connected with a slope.
for i in 0..intvs - 1 {
let vleft = start + i as f64 * gran;
if vleft < start + MIN_SEG_DIST {
continue;
}
for j in i..intvs {
let vright = start + j as f64 * gran;
if vright - vleft < MIN_SEG_DIST || vright > end - MIN_SEG_DIST {
continue;
}
try_and_pick(&|| {
Self::fit_slope_with_vleft_and_vright(&self.points, vleft, vright)
})?;
}
}
self.lines = best_lines;
Ok(())
}