resctl-bench/src/bench/iocost_params.rs (103 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. use super::*; use rd_agent_intf::IoCostKnobs; use rd_agent_intf::{IOCOST_BENCH_SVC_NAME, ROOT_SLICE}; struct IoCostParamsJob { apply: bool, commit: bool, } impl Default for IoCostParamsJob { fn default() -> Self { Self { apply: true, commit: true, } } } pub struct IoCostParamsBench {} impl Bench for IoCostParamsBench { fn desc(&self) -> BenchDesc { BenchDesc::new("iocost-params", "Benchmark io.cost model parameters").takes_run_props() } fn parse(&self, spec: &JobSpec, _prev_data: Option<&JobData>) -> Result<Box<dyn Job>> { let mut job = IoCostParamsJob::default(); for (k, v) in spec.props[0].iter() { match k.as_str() { "apply" => job.apply = v.len() == 0 || v.parse::<bool>()?, "commit" => job.commit = v.len() == 0 || v.parse::<bool>()?, k => bail!("unknown property key {:?}", k), } } if job.commit { job.apply = true; } Ok(Box::new(job)) } fn doc<'a>(&self, out: &mut Box<dyn Write + 'a>) -> Result<()> { const DOC: &[u8] = include_bytes!("../../doc/iocost-params.md"); write!(out, "{}", String::from_utf8_lossy(DOC))?; Ok(()) } } impl Job for IoCostParamsJob { fn sysreqs(&self) -> BTreeSet<SysReq> { MIN_SYSREQS.clone() } fn run(&mut self, rctx: &mut RunCtx) -> Result<serde_json::Value> { rctx.skip_mem_profile().start_agent(vec![])?; info!("iocost-params: Estimating iocost parameters"); rctx.start_iocost_bench()?; rctx.wait_cond( |af, progress| { let cmd = &af.cmd.data; let bench = &af.bench.data; let rep = &af.report.data; progress.set_status(&format!( "rw:{:>5}/{:>5}", format_size_dashed(rep.usages[ROOT_SLICE].io_rbps), format_size_dashed(rep.usages[ROOT_SLICE].io_wbps), )); bench.iocost_seq >= cmd.bench_iocost_seq }, None, Some(BenchProgress::new().monitor_systemd_unit(IOCOST_BENCH_SVC_NAME)), )?; let result = rctx.access_agent_files(|af| af.bench.data.iocost.clone()); Ok(serde_json::to_value(&result).unwrap()) } fn study(&self, rctx: &mut RunCtx, rec_json: serde_json::Value) -> Result<serde_json::Value> { if self.apply { rctx.apply_iocost_knobs(parse_json_value_or_dump(rec_json)?, self.commit)?; } Ok(serde_json::Value::Bool(true)) } fn format<'a>( &self, out: &mut Box<dyn Write + 'a>, data: &JobData, _full: &FormatOpts, _props: &JobProps, ) -> Result<()> { let result: IoCostKnobs = data.parse_record()?; let model = &result.model; let qos = &result.qos; writeln!( out, "iocost model: rbps={} rseqiops={} rrandiops={}", model.rbps, model.rseqiops, model.rrandiops ) .unwrap(); writeln!( out, " wbps={} wseqiops={} wrandiops={}", model.wbps, model.wseqiops, model.wrandiops ) .unwrap(); writeln!( out, "iocost QoS: rpct={:.2} rlat={} wpct={:.2} wlat={} min={:.2} max={:.2}", qos.rpct, qos.rlat, qos.wpct, qos.wlat, qos.min, qos.max ) .unwrap(); Ok(()) } }