about summary refs log tree commit diff
path: root/src/tools
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-06-29 22:10:56 +0200
committerGitHub <noreply@github.com>2024-06-29 22:10:56 +0200
commit6d74ffd2381b4b42cad64feade96b201ba402dd5 (patch)
tree01644b56beb150659fb51ed096a5f088a2274ab9 /src/tools
parent6df68793f36234cffa9384e056c4575acef5cc27 (diff)
parent6a2638e6c49817de9c2b1d56261de37c6a352571 (diff)
Rollup merge of #127002 - Kobzol:bootstrap-perf-tool, r=onur-ozkan
Implement `x perf` as a separate tool

Continues work from https://github.com/rust-lang/rust/pull/126318, adds a CLI for running `rustc-perf` profiling commands through a new `rustc-perf-wrapper` tool. The CLI is in a separate tool to enable experimentation outside of `bootstrap`.

This is probably most of what we can do so far, I'll add support for benchmarking once `rustc-perf` gets a terminal output for comparing benchmark results.

r? ``@onur-ozkan``
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/rustc-perf-wrapper/Cargo.toml7
-rw-r--r--src/tools/rustc-perf-wrapper/README.md3
-rw-r--r--src/tools/rustc-perf-wrapper/src/config.rs45
-rw-r--r--src/tools/rustc-perf-wrapper/src/main.rs130
4 files changed, 185 insertions, 0 deletions
diff --git a/src/tools/rustc-perf-wrapper/Cargo.toml b/src/tools/rustc-perf-wrapper/Cargo.toml
new file mode 100644
index 00000000000..416bfef41d7
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "rustc-perf-wrapper"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+clap = { version = "4.5.7", features = ["derive", "env"] }
diff --git a/src/tools/rustc-perf-wrapper/README.md b/src/tools/rustc-perf-wrapper/README.md
new file mode 100644
index 00000000000..d7655459a2f
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/README.md
@@ -0,0 +1,3 @@
+# rustc-perf wrapper
+Utility tool for invoking [`rustc-perf`](https://github.com/rust-lang/rustc-perf) for benchmarking/profiling
+a stage1/2 compiler built by bootstrap using `x perf -- <command>`.
diff --git a/src/tools/rustc-perf-wrapper/src/config.rs b/src/tools/rustc-perf-wrapper/src/config.rs
new file mode 100644
index 00000000000..a88abfe4723
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/src/config.rs
@@ -0,0 +1,45 @@
+use std::fmt::{Display, Formatter};
+
+#[derive(Clone, Copy, Debug, clap::ValueEnum)]
+#[value(rename_all = "PascalCase")]
+pub enum Profile {
+    Check,
+    Debug,
+    Doc,
+    Opt,
+    Clippy,
+}
+
+impl Display for Profile {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let name = match self {
+            Profile::Check => "Check",
+            Profile::Debug => "Debug",
+            Profile::Doc => "Doc",
+            Profile::Opt => "Opt",
+            Profile::Clippy => "Clippy",
+        };
+        f.write_str(name)
+    }
+}
+
+#[derive(Clone, Copy, Debug, clap::ValueEnum)]
+#[value(rename_all = "PascalCase")]
+pub enum Scenario {
+    Full,
+    IncrFull,
+    IncrUnchanged,
+    IncrPatched,
+}
+
+impl Display for Scenario {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let name = match self {
+            Scenario::Full => "Full",
+            Scenario::IncrFull => "IncrFull",
+            Scenario::IncrUnchanged => "IncrUnchanged",
+            Scenario::IncrPatched => "IncrPatched",
+        };
+        f.write_str(name)
+    }
+}
diff --git a/src/tools/rustc-perf-wrapper/src/main.rs b/src/tools/rustc-perf-wrapper/src/main.rs
new file mode 100644
index 00000000000..1c0d1745f3d
--- /dev/null
+++ b/src/tools/rustc-perf-wrapper/src/main.rs
@@ -0,0 +1,130 @@
+use crate::config::{Profile, Scenario};
+use clap::Parser;
+use std::path::PathBuf;
+use std::process::Command;
+
+mod config;
+
+/// Performs profiling or benchmarking with [`rustc-perf`](https://github.com/rust-lang/rustc-perf)
+/// using a locally built compiler.
+#[derive(Debug, clap::Parser)]
+// Hide arguments from BuildContext in the default usage string.
+// Clap does not seem to have a way of disabling the usage of these arguments.
+#[clap(override_usage = "rustc-perf-wrapper [OPTIONS] <COMMAND>")]
+pub struct Args {
+    #[clap(subcommand)]
+    cmd: PerfCommand,
+
+    #[clap(flatten)]
+    opts: SharedOpts,
+
+    #[clap(flatten)]
+    ctx: BuildContext,
+}
+
+#[derive(Debug, clap::Parser)]
+enum PerfCommand {
+    /// Run `profile_local eprintln`.
+    /// This executes the compiler on the given benchmarks and stores its stderr output.
+    Eprintln,
+    /// Run `profile_local samply`
+    /// This executes the compiler on the given benchmarks and profiles it with `samply`.
+    /// You need to install `samply`, e.g. using `cargo install samply`.
+    Samply,
+    /// Run `profile_local cachegrind`.
+    /// This executes the compiler on the given benchmarks under `Cachegrind`.
+    Cachegrind,
+}
+
+impl PerfCommand {
+    fn is_profiling(&self) -> bool {
+        match self {
+            PerfCommand::Eprintln | PerfCommand::Samply | PerfCommand::Cachegrind => true,
+        }
+    }
+}
+
+#[derive(Debug, clap::Parser)]
+struct SharedOpts {
+    /// Select the benchmarks that you want to run (separated by commas).
+    /// If unspecified, all benchmarks will be executed.
+    #[clap(long, global = true, value_delimiter = ',')]
+    include: Vec<String>,
+    /// Select the scenarios that should be benchmarked.
+    #[clap(
+        long,
+        global = true,
+        value_delimiter = ',',
+        default_value = "Full,IncrFull,IncrUnchanged,IncrPatched"
+    )]
+    scenarios: Vec<Scenario>,
+    /// Select the profiles that should be benchmarked.
+    #[clap(long, global = true, value_delimiter = ',', default_value = "Check,Debug,Opt")]
+    profiles: Vec<Profile>,
+}
+
+/// These arguments are mostly designed to be passed from bootstrap, not by users
+/// directly.
+#[derive(Debug, clap::Parser)]
+struct BuildContext {
+    /// Compiler binary that will be benchmarked/profiled.
+    #[clap(long, hide = true, env = "RUSTC_REAL")]
+    compiler: PathBuf,
+    /// rustc-perf collector binary that will be used for running benchmarks/profilers.
+    #[clap(long, hide = true, env = "PERF_COLLECTOR")]
+    collector: PathBuf,
+    /// Directory where to store results.
+    #[clap(long, hide = true, env = "PERF_RESULT_DIR")]
+    results_dir: PathBuf,
+}
+
+fn main() {
+    let args = Args::parse();
+    run(args);
+}
+
+fn run(args: Args) {
+    let mut cmd = Command::new(args.ctx.collector);
+    match &args.cmd {
+        PerfCommand::Eprintln => {
+            cmd.arg("profile_local").arg("eprintln");
+        }
+        PerfCommand::Samply => {
+            cmd.arg("profile_local").arg("samply");
+        }
+        PerfCommand::Cachegrind => {
+            cmd.arg("profile_local").arg("cachegrind");
+        }
+    }
+    if args.cmd.is_profiling() {
+        cmd.arg("--out-dir").arg(&args.ctx.results_dir);
+    }
+
+    if !args.opts.include.is_empty() {
+        cmd.arg("--include").arg(args.opts.include.join(","));
+    }
+    if !args.opts.profiles.is_empty() {
+        cmd.arg("--profiles")
+            .arg(args.opts.profiles.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
+    }
+    if !args.opts.scenarios.is_empty() {
+        cmd.arg("--scenarios")
+            .arg(args.opts.scenarios.iter().map(|p| p.to_string()).collect::<Vec<_>>().join(","));
+    }
+    cmd.arg(&args.ctx.compiler);
+
+    println!("Running `rustc-perf` using `{}`", args.ctx.compiler.display());
+
+    const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
+
+    let rustc_perf_dir = PathBuf::from(MANIFEST_DIR).join("../rustc-perf");
+
+    // We need to set the working directory to `src/tools/perf`, so that it can find the directory
+    // with compile-time benchmarks.
+    let cmd = cmd.current_dir(rustc_perf_dir);
+    cmd.status().expect("error while running rustc-perf collector");
+
+    if args.cmd.is_profiling() {
+        println!("You can find the results at `{}`", args.ctx.results_dir.display());
+    }
+}