xtask/
bench.rs

1use std::process::Command;
2
3use anyhow::Result;
4use clap::Args;
5
6use crate::util::{repository_root, run_cmd};
7
8/// Run one or more benchmarks
9#[derive(Debug, Args)]
10pub(super) struct BenchCmd {
11    #[clap(long, short = 'p')]
12    package: String,
13
14    /// Build benchmarks in debug mode.
15    #[clap(long)]
16    debug: bool,
17
18    /// Template to use while instrumenting
19    #[clap(short = 't')]
20    template: Option<String>,
21
22    #[clap(long)]
23    no_lib: bool,
24
25    #[clap(long)]
26    benches: bool,
27
28    #[clap(long)]
29    bench: Option<String>,
30
31    /// Instrument using https://github.com/dudykr/ddt
32    #[clap(long)]
33    instrument: bool,
34
35    /// Instrument using https://github.com/mstange/samply
36    #[clap(long)]
37    samply: bool,
38
39    #[clap(long)]
40    features: Vec<String>,
41
42    args: Vec<String>,
43}
44
45impl BenchCmd {
46    pub fn run(self) -> Result<()> {
47        let mut cmd = self.build_cmd()?;
48
49        cmd.env("RUST_LOG", "off");
50        cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
51        cmd.env("CARGO_PROFILE_BENCH_DEBUG", "true");
52
53        run_cmd(&mut cmd)
54    }
55
56    fn build_cmd(&self) -> Result<Command> {
57        let mut cmd = if self.samply {
58            // ddt profile instruments cargo -t time
59            let mut cmd = Command::new("ddt");
60            cmd.arg("profile").arg("samply").arg("cargo");
61
62            if !self.debug {
63                cmd.arg("--release");
64            }
65
66            cmd
67        } else if self.instrument {
68            // ddt profile instruments cargo -t time
69            let mut cmd = Command::new("ddt");
70            cmd.arg("profile").arg("instruments").arg("cargo");
71            cmd.arg("-t")
72                .arg(self.template.as_deref().unwrap_or("time"));
73
74            if !self.debug {
75                cmd.arg("--release");
76            }
77
78            cmd
79        } else {
80            let mut cmd = Command::new("cargo");
81            cmd.arg("bench");
82
83            if self.debug {
84                cmd.arg("--debug");
85            }
86
87            cmd
88        };
89
90        cmd.arg("--package").arg(&self.package);
91
92        if self.benches {
93            cmd.arg("--benches");
94        }
95
96        if let Some(b) = &self.bench {
97            cmd.arg("--bench").arg(b);
98        }
99
100        for f in self.features.iter() {
101            cmd.arg("--features").arg(f);
102        }
103
104        if self.samply || self.instrument {
105            cmd.arg("--").arg("--bench").args(&self.args);
106        } else {
107            cmd.arg("--").args(&self.args);
108        }
109
110        // TODO: This should use cargo metadata
111        cmd.current_dir(repository_root()?.join("crates").join(&self.package));
112
113        Ok(cmd)
114    }
115}