xtask/
bench.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use std::process::Command;

use anyhow::Result;
use clap::Args;

use crate::util::{repository_root, run_cmd};

/// Run one or more benchmarks
#[derive(Debug, Args)]
pub(super) struct BenchCmd {
    #[clap(long, short = 'p')]
    package: String,

    /// Build benchmarks in debug mode.
    #[clap(long)]
    debug: bool,

    /// Template to use while instrumenting
    #[clap(short = 't')]
    template: Option<String>,

    #[clap(long)]
    no_lib: bool,

    #[clap(long)]
    benches: bool,

    #[clap(long)]
    bench: Option<String>,

    /// Instrument using https://github.com/dudykr/ddt
    #[clap(long)]
    instrument: bool,

    /// Instrument using https://github.com/mstange/samply
    #[clap(long)]
    samply: bool,

    #[clap(long)]
    features: Vec<String>,

    args: Vec<String>,
}

impl BenchCmd {
    pub fn run(self) -> Result<()> {
        let mut cmd = self.build_cmd()?;

        cmd.env("RUST_LOG", "off");
        cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
        cmd.env("CARGO_PROFILE_BENCH_DEBUG", "true");

        run_cmd(&mut cmd)
    }

    fn build_cmd(&self) -> Result<Command> {
        let mut cmd = if self.samply {
            // ddt profile instruments cargo -t time
            let mut cmd = Command::new("ddt");
            cmd.arg("profile").arg("samply").arg("cargo");

            if !self.debug {
                cmd.arg("--release");
            }

            cmd
        } else if self.instrument {
            // ddt profile instruments cargo -t time
            let mut cmd = Command::new("ddt");
            cmd.arg("profile").arg("instruments").arg("cargo");
            cmd.arg("-t")
                .arg(self.template.as_deref().unwrap_or("time"));

            if !self.debug {
                cmd.arg("--release");
            }

            cmd
        } else {
            let mut cmd = Command::new("cargo");
            cmd.arg("bench");

            if self.debug {
                cmd.arg("--debug");
            }

            cmd
        };

        cmd.arg("--package").arg(&self.package);

        if self.benches {
            cmd.arg("--benches");
        }

        if let Some(b) = &self.bench {
            cmd.arg("--bench").arg(b);
        }

        for f in self.features.iter() {
            cmd.arg("--features").arg(f);
        }

        if self.samply || self.instrument {
            cmd.arg("--").arg("--bench").args(&self.args);
        } else {
            cmd.arg("--").args(&self.args);
        }

        // TODO: This should use cargo metadata
        cmd.current_dir(repository_root()?.join("crates").join(&self.package));

        Ok(cmd)
    }
}