difftreelog
fix only build benchmarker for x86_64-linux
in: master
3 files changed
xtask/Cargo.tomldiffbeforeafterboth--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -18,5 +18,5 @@
xshell.workspace = true
clap = { workspace = true, features = ["derive"] }
-[target.'cfg(target_os = "linux")'.dependencies]
+[target.'cfg(all(target_arch = "x86_64", target_os = "linux"))'.dependencies]
nix.workspace = true
xtask/src/bench.rsdiffbeforeafterboth1use std::{2 ffi::OsString,3 mem,4 process::{Command, Stdio},5 time::Instant,6};78use anyhow::{Result, bail};9use nix::{libc, sys::wait::WaitStatus, unistd::Pid};1011#[derive(Debug, Clone)]12pub struct Stats {13 pub min: f64,14 pub max: f64,15 pub mean: f64,16 pub stddev: f64,17}1819impl Stats {20 fn from_samples(samples: &[f64]) -> Self {21 let n = samples.len() as f64;22 let mean = samples.iter().sum::<f64>() / n;23 let var = if samples.len() > 1 {24 samples.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (n - 1.0)25 } else {26 0.027 };28 Self {29 min: samples.iter().copied().fold(f64::INFINITY, f64::min),30 max: samples.iter().copied().fold(f64::NEG_INFINITY, f64::max),31 mean,32 stddev: var.sqrt(),33 }34 }35}3637#[derive(Debug, Clone)]38pub struct BenchResult {39 pub runs: u32,40 /// Wall-clock time per run, seconds.41 pub wall_secs: Stats,42 /// Peak resident set per run, KiB (Linux `ru_maxrss`).43 pub max_rss_kib: Stats,44}4546pub struct BenchOpts<'a> {47 pub program: &'a OsString,48 pub args: &'a [OsString],49 pub runs: u32,50 pub warmup: u32,51 pub output: bool,52}5354pub fn bench(opts: BenchOpts<'_>) -> Result<BenchResult> {55 if opts.runs == 0 {56 bail!("runs must be >= 1");57 }5859 for _ in 0..opts.warmup {60 run_once(opts.program, opts.args, opts.output)?;61 }6263 let mut wall = Vec::with_capacity(opts.runs as usize);64 let mut rss = Vec::with_capacity(opts.runs as usize);65 for _ in 0..opts.runs {66 let s = run_once(opts.program, opts.args, opts.output)?;67 wall.push(s.wall_secs);68 rss.push(s.max_rss_kib as f64);69 }7071 Ok(BenchResult {72 runs: opts.runs,73 wall_secs: Stats::from_samples(&wall),74 max_rss_kib: Stats::from_samples(&rss),75 })76}7778struct Sample {79 wall_secs: f64,80 max_rss_kib: i64,81}8283fn run_once(program: &OsString, args: &[OsString], silent: bool) -> Result<Sample> {84 let mut cmd = Command::new(program);85 cmd.args(args);86 if silent {87 cmd.stdout(Stdio::null()).stderr(Stdio::null());88 }8990 let start = Instant::now();91 let child = cmd.spawn()?;92 let pid = child.id() as libc::pid_t;93 // We'll reap via wait4 ourselves; don't let std touch this handle again.94 mem::forget(child);9596 let mut status: libc::c_int = 0;97 let mut ru: libc::rusage = unsafe { mem::zeroed() };98 let waited = unsafe { libc::wait4(pid, &raw mut status, 0, &raw mut ru) };99 let elapsed = start.elapsed();100 if waited < 0 {101 return Err(std::io::Error::last_os_error().into());102 }103104 match WaitStatus::from_raw(Pid::from_raw(pid), status)? {105 WaitStatus::Exited(_, 0) => {}106 WaitStatus::Exited(_, code) => bail!("child exited with code {code}"),107 WaitStatus::Signaled(_, sig, _) => bail!("child killed by signal {sig:?}"),108 other => bail!("unexpected wait status: {other:?}"),109 }110111 Ok(Sample {112 wall_secs: elapsed.as_secs_f64(),113 max_rss_kib: ru.ru_maxrss,114 })115}116117#[cfg(target_os = "linux")]118pub fn bench_cmd(args: &[String], runs: u32, warmup: u32, output: bool) -> Result<()> {119 let program = std::ffi::OsString::from(&args[0]);120 let rest: Vec<std::ffi::OsString> = args[1..].iter().map(Into::into).collect();121 let r = bench(BenchOpts {122 program: &program,123 args: &rest,124 runs,125 warmup,126 output,127 })?;128 eprintln!(129 "runs: {} wall: {:.3}s ± {:.3}s [{:.3}..{:.3}]",130 r.runs, r.wall_secs.mean, r.wall_secs.stddev, r.wall_secs.min, r.wall_secs.max,131 );132 eprintln!(133 " max_rss: {} ± {} KiB [{}..{}]",134 r.max_rss_kib.mean as i64,135 r.max_rss_kib.stddev as i64,136 r.max_rss_kib.min as i64,137 r.max_rss_kib.max as i64,138 );139 Ok(())140}1#![allow(clippy::cast_precision_loss)]23use std::{4 ffi::OsString,5 mem,6 process::{Command, Stdio},7 time::Instant,8};910use anyhow::{Result, bail};11use nix::{libc, sys::wait::WaitStatus, unistd::Pid};1213#[derive(Debug, Clone)]14pub struct Stats {15 pub min: f64,16 pub max: f64,17 pub mean: f64,18 pub stddev: f64,19}2021impl Stats {22 fn from_samples(samples: &[f64]) -> Self {23 let n = samples.len() as f64;24 let mean = samples.iter().sum::<f64>() / n;25 let var = if samples.len() > 1 {26 samples.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (n - 1.0)27 } else {28 0.029 };30 Self {31 min: samples.iter().copied().fold(f64::INFINITY, f64::min),32 max: samples.iter().copied().fold(f64::NEG_INFINITY, f64::max),33 mean,34 stddev: var.sqrt(),35 }36 }37}3839#[derive(Debug, Clone)]40pub struct BenchResult {41 pub runs: u32,42 /// Wall-clock time per run, seconds.43 pub wall_secs: Stats,44 /// Peak resident set per run, KiB (Linux `ru_maxrss`).45 pub max_rss_kib: Stats,46}4748pub struct BenchOpts<'a> {49 pub program: &'a OsString,50 pub args: &'a [OsString],51 pub runs: u32,52 pub warmup: u32,53 pub output: bool,54}5556pub fn bench(opts: BenchOpts<'_>) -> Result<BenchResult> {57 if opts.runs == 0 {58 bail!("runs must be >= 1");59 }6061 for _ in 0..opts.warmup {62 run_once(opts.program, opts.args, opts.output)?;63 }6465 let mut wall = Vec::with_capacity(opts.runs as usize);66 let mut rss = Vec::with_capacity(opts.runs as usize);67 for _ in 0..opts.runs {68 let s = run_once(opts.program, opts.args, opts.output)?;69 wall.push(s.wall_secs);70 rss.push(s.max_rss_kib as f64);71 }7273 Ok(BenchResult {74 runs: opts.runs,75 wall_secs: Stats::from_samples(&wall),76 max_rss_kib: Stats::from_samples(&rss),77 })78}7980struct Sample {81 wall_secs: f64,82 max_rss_kib: i64,83}8485fn run_once(program: &OsString, args: &[OsString], silent: bool) -> Result<Sample> {86 let mut cmd = Command::new(program);87 cmd.args(args);88 if silent {89 cmd.stdout(Stdio::null()).stderr(Stdio::null());90 }9192 let start = Instant::now();93 let child = cmd.spawn()?;94 let pid = child.id() as libc::pid_t;95 // We'll reap via wait4 ourselves; don't let std touch this handle again.96 mem::forget(child);9798 let mut status: libc::c_int = 0;99 let mut ru: libc::rusage = unsafe { mem::zeroed() };100 let waited = unsafe { libc::wait4(pid, &raw mut status, 0, &raw mut ru) };101 let elapsed = start.elapsed();102 if waited < 0 {103 return Err(std::io::Error::last_os_error().into());104 }105106 match WaitStatus::from_raw(Pid::from_raw(pid), status)? {107 WaitStatus::Exited(_, 0) => {}108 WaitStatus::Exited(_, code) => bail!("child exited with code {code}"),109 WaitStatus::Signaled(_, sig, _) => bail!("child killed by signal {sig:?}"),110 other => bail!("unexpected wait status: {other:?}"),111 }112113 Ok(Sample {114 wall_secs: elapsed.as_secs_f64(),115 max_rss_kib: ru.ru_maxrss,116 })117}118119#[cfg(target_os = "linux")]120pub fn bench_cmd(args: &[String], runs: u32, warmup: u32, output: bool) -> Result<()> {121 let program = std::ffi::OsString::from(&args[0]);122 let rest: Vec<std::ffi::OsString> = args[1..].iter().map(Into::into).collect();123 let r = bench(BenchOpts {124 program: &program,125 args: &rest,126 runs,127 warmup,128 output,129 })?;130 eprintln!(131 "runs: {} wall: {:.3}s ± {:.3}s [{:.3}..{:.3}]",132 r.runs, r.wall_secs.mean, r.wall_secs.stddev, r.wall_secs.min, r.wall_secs.max,133 );134 eprintln!(135 " max_rss: {} ± {} KiB [{}..{}]",136 r.max_rss_kib.mean as i64,137 r.max_rss_kib.stddev as i64,138 r.max_rss_kib.min as i64,139 r.max_rss_kib.max as i64,140 );141 Ok(())142}xtask/src/main.rsdiffbeforeafterboth--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -1,10 +1,8 @@
use anyhow::Result;
-#[cfg(not(target_os = "linux"))]
-use anyhow::bail;
use clap::Parser;
use xshell::{Shell, cmd};
-#[cfg(target_os = "linux")]
+#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod bench;
mod sourcegen;
@@ -40,6 +38,7 @@
args: Vec<String>,
},
/// Benchmark a command: repeated runs, reports time + RSS stats (Linux only)
+ #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
Bench {
#[arg(long, default_value_t = 10)]
runs: u32,
@@ -121,7 +120,7 @@
Ok(())
}
- #[cfg(target_os = "linux")]
+ #[cfg(all(target_arch = "x86_64", target_os = "linux"))]
Opts::Bench {
runs,
warmup,