pub(crate) mod handshake;
pub(crate) mod percpu_lock;
pub(crate) mod plat;
pub(crate) mod run;
pub use run::SchbenchConfig;
pub use run::{PipeTransferReport, pipe_transfer_report};
pub const SCHBENCH_PERCENTILES: [f64; 5] = plat::PLIST;
#[derive(Debug, Clone, Copy)]
pub struct StandaloneReport {
pub wakeup_pcts_us: [u32; 5],
pub wakeup_counts: [u64; 5],
pub wakeup_min_us: u32,
pub wakeup_max_us: u32,
pub nr_wakeup_samples: u64,
pub request_pcts_us: [u32; 5],
pub request_counts: [u64; 5],
pub request_min_us: u32,
pub request_max_us: u32,
pub nr_request_samples: u64,
pub rps_pcts: [u32; 5],
pub rps_counts: [u64; 5],
pub rps_min: u32,
pub rps_max: u32,
pub nr_rps_samples: u64,
pub final_rps_goal: usize,
pub achieved_rps: f64,
pub sched_delay_msg_ns: u64,
pub sched_delay_worker_ns: u64,
pub loop_count: u64,
pub nr_workers: usize,
}
pub fn run_standalone(config: &SchbenchConfig, run_secs: u64) -> StandaloneReport {
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
let stop = AtomicBool::new(false);
let progress = AtomicU64::new(0);
let outcome = std::thread::scope(|s| {
let runner = s.spawn(|| run::run(config, &stop, &progress, None));
std::thread::sleep(std::time::Duration::from_secs(run_secs));
stop.store(true, Ordering::Release);
runner.join().expect("schbench standalone runner panicked")
});
let w = &outcome.whole_run;
StandaloneReport {
wakeup_pcts_us: w.wakeup.values,
wakeup_counts: w.wakeup.counts,
wakeup_min_us: w.wakeup.min,
wakeup_max_us: w.wakeup.max,
nr_wakeup_samples: w.wakeup.nr_samples,
request_pcts_us: w.request.values,
request_counts: w.request.counts,
request_min_us: w.request.min,
request_max_us: w.request.max,
nr_request_samples: w.request.nr_samples,
rps_pcts: w.rps.values,
rps_counts: w.rps.counts,
rps_min: w.rps.min,
rps_max: w.rps.max,
nr_rps_samples: w.rps.nr_samples,
final_rps_goal: w.final_rps_goal,
achieved_rps: w.achieved_rps,
sched_delay_msg_ns: w.sched_delay_msg_ns,
sched_delay_worker_ns: w.sched_delay_worker_ns,
loop_count: w.loop_count,
nr_workers: w.nr_workers,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn run_standalone_fills_report_from_a_real_run() {
let config = SchbenchConfig::default()
.message_threads(1)
.worker_threads(1)
.sleep_usec(0);
let report = run_standalone(&config, 2);
assert!(report.loop_count > 0, "loop_count: {}", report.loop_count);
assert!(
report.achieved_rps > 0.0,
"achieved_rps: {}",
report.achieved_rps
);
assert!(report.nr_wakeup_samples > 0, "wakeup samples");
assert!(report.nr_request_samples > 0, "request samples");
assert!(
report.nr_rps_samples > 0,
"rps samples: {}",
report.nr_rps_samples
);
for w in report.wakeup_pcts_us.windows(2) {
assert!(
w[0] <= w[1],
"wakeup percentiles monotonic: {:?}",
report.wakeup_pcts_us
);
}
for w in report.request_pcts_us.windows(2) {
assert!(
w[0] <= w[1],
"request percentiles monotonic: {:?}",
report.request_pcts_us
);
}
for w in report.rps_pcts.windows(2) {
assert!(
w[0] <= w[1],
"rps percentiles monotonic: {:?}",
report.rps_pcts
);
}
let wc: u64 = report.wakeup_counts.iter().sum();
assert!(
wc > 0 && wc <= report.nr_wakeup_samples,
"wakeup counts {wc} in (0, {}]",
report.nr_wakeup_samples
);
let rc: u64 = report.request_counts.iter().sum();
assert!(
rc > 0 && rc <= report.nr_request_samples,
"request counts {rc} in (0, {}]",
report.nr_request_samples
);
let rpsc: u64 = report.rps_counts.iter().sum();
assert!(
rpsc > 0 && rpsc <= report.nr_rps_samples,
"rps counts {rpsc} in (0, {}]",
report.nr_rps_samples
);
assert!(report.wakeup_min_us <= report.wakeup_max_us);
assert!(report.request_min_us <= report.request_max_us);
assert!(report.rps_min <= report.rps_max);
}
}