in resctl-bench/src/bench/iocost_tune.rs [666:830]
fn solve(
&self,
data: &BTreeMap<DataSel, DataSeries>,
(scale_min, scale_max): (f64, f64),
) -> Result<Option<(IoCostQoSParams, f64)>> {
let ds = |sel: &DataSel| -> Result<&DataSeries> {
data.get(sel)
.ok_or(anyhow!("Required data series {:?} unavailable", sel))
};
// When detecting inflection point for solutions, if the slope is
// steep and the error bar is wild, picking the exact inflection
// point can be dangerous as a small amount of error can lead to a
// large deviation from the target. Let's offset the result by some
// amount proportional to the slope * relative error. The scaling
// factor was determined empricially and the maximum offsetting is
// limited to 10%. We calculate infl_offset based on MOF and use it
// everywhere. There likely is a better way of determining the
// offset amount.
let mof_ds = ds(&DataSel::MOF)?;
let infl_offset = || {
let mof_max = mof_ds.lines.right.y;
if mof_max == 0.0 {
0.0
} else {
(mof_ds.lines.slope() * (mof_ds.error / mof_ds.lines.right.y) * 800.0).min(0.1)
}
};
// Helper to create fixed vrate result. {r|w}pct's are zero as the
// vrate won't be modulated but let's still fill in {r|w}lat's as
// iocost uses those values to determine the period.
let (rlat_99_dl, wlat_99_dl) = (
&ds(&DataSel::RLat("99".into(), "mean".into()))?.lines,
&ds(&DataSel::WLat("99".into(), "mean".into()))?.lines,
);
let params_at_vrate = |vrate| {
(
IoCostQoSParams {
min: vrate,
max: vrate,
rpct: 0.0,
wpct: 0.0,
rlat: (rlat_99_dl.eval(vrate) * 1_000_000.0).round() as u64,
wlat: (wlat_99_dl.eval(vrate) * 1_000_000.0).round() as u64,
},
vrate,
)
};
// Find min vrate at max val for @sel. If the line is flat, use the
// min vrate at max val for @no_sig_sel.
let solve_max = |sel, no_sig_sel| -> Result<Option<f64>> {
let no_sig_vrate = match no_sig_sel {
Some(nssel) => Self::find_max_vrate_at_min_val(
ds(nssel)?,
(scale_min, scale_max),
infl_offset(),
),
None => None,
};
Ok(Self::find_min_vrate_at_max_val(
ds(sel)?,
(scale_min, scale_max),
infl_offset(),
no_sig_vrate,
))
};
// Find the max vrate at min val.
let solve_min = |sel| -> Result<Option<f64>> {
Ok(Self::find_max_vrate_at_min_val(
ds(sel)?,
(scale_min, scale_max),
infl_offset(),
))
};
// Find the rightmost valid vrate.
let solve_max_vrate = |sel| -> Result<Option<f64>> {
Ok(ds(sel)?
.lines
.clamped(scale_min, scale_max)
.map(|dl| dl.range.1))
};
Ok(match self {
Self::VrateRange((scale_min, scale_max), (rpct, wpct)) => {
let (rpct, rlat) = Self::solve_vrate_range(*scale_max, READ, rpct.as_deref(), data);
let (wpct, wlat) =
Self::solve_vrate_range(*scale_max, WRITE, wpct.as_deref(), data);
Some((
IoCostQoSParams {
rpct,
rlat,
wpct,
wlat,
min: *scale_min,
max: *scale_max,
},
*scale_max,
))
}
// Min vrate still at max MOF. If MOF is flat, max vrate at min
// LatImp.
Self::MOFMax => solve_max(&DataSel::MOF, Some(&DataSel::LatImp))?.map(params_at_vrate),
// Min vrate still at max aMOF. If MOF is flat, max vrate at min
// LatImp.
Self::AMOFMax => {
solve_max(&DataSel::AMOF, Some(&DataSel::LatImp))?.map(params_at_vrate)
}
// Rightmost vrate with valid aMOF.
Self::AMOFMaxVrate => solve_max_vrate(&DataSel::AMOF)?.map(params_at_vrate),
// clamp(max vrate at min LatImp, isolation, bandwidth)
Self::IsolatedBandwidth => match (
solve_min(&DataSel::AMOFDelta)?,
solve_max_vrate(&DataSel::AMOF)?,
) {
(Some(min), Some(max)) => {
solve_min(&DataSel::LatImp)?.map(|v| params_at_vrate(v.clamp(min, max)))
}
_ => None,
},
Self::AMOFDeltaMin => solve_min(&DataSel::AMOFDelta)?.map(params_at_vrate),
Self::LatRange(sel, lat_rel_range) => {
if let Some((lat_target, vrate_range)) =
Self::solve_lat_range(ds(&sel)?, *lat_rel_range, (scale_min, scale_max))
{
Some(match sel {
DataSel::RLat(pct, _) => (
IoCostQoSParams {
rpct: pct.parse::<f64>().unwrap(),
rlat: lat_target,
wpct: 0.0,
wlat: 0,
min: vrate_range.0,
max: vrate_range.1,
},
vrate_range.1,
),
DataSel::WLat(pct, _) => (
IoCostQoSParams {
rpct: 0.0,
rlat: 0,
wpct: pct.parse::<f64>().unwrap(),
wlat: lat_target,
min: vrate_range.0,
max: vrate_range.1,
},
vrate_range.1,
),
_ => panic!(),
})
} else {
None
}
}
})
}