Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement x perf as a separate tool #127002

Merged
merged 3 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3453,6 +3453,13 @@ dependencies = [
"stable_mir",
]

[[package]]
name = "rustc-perf-wrapper"
version = "0.1.0"
dependencies = [
"clap",
]

[[package]]
name = "rustc-rayon"
version = "0.5.0"
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ members = [
"src/tools/rustdoc-gui-test",
"src/tools/opt-dist",
"src/tools/coverage-dump",
"src/tools/rustc-perf-wrapper",
]

exclude = [
Expand Down
32 changes: 11 additions & 21 deletions src/bootstrap/src/core/build_steps/perf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::process::Command;

use crate::core::build_steps::compile::{Std, Sysroot};
use crate::core::build_steps::tool::RustcPerf;
use crate::core::build_steps::tool::{RustcPerf, Tool};
use crate::core::builder::Builder;
use crate::core::config::DebuginfoLevel;

Expand All @@ -22,24 +20,16 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#);
let sysroot = builder.ensure(Sysroot::new(compiler));
let rustc = sysroot.join("bin/rustc");

let results_dir = builder.build.tempdir().join("rustc-perf");

let mut cmd = Command::new(collector);
let cmd = cmd
.arg("profile_local")
.arg("eprintln")
.arg("--out-dir")
.arg(&results_dir)
.arg("--include")
.arg("helloworld")
.arg(&rustc);

builder.info(&format!("Running `rustc-perf` using `{}`", rustc.display()));
let rustc_perf_dir = builder.build.tempdir().join("rustc-perf");
let profile_results_dir = rustc_perf_dir.join("results");

// 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(builder.src.join("src/tools/rustc-perf"));
builder.build.run(cmd);
// We need to take args passed after `--` and pass them to `rustc-perf-wrapper`
let args = std::env::args().skip_while(|a| a != "--").skip(1);

builder.info(&format!("You can find the results at `{}`", results_dir.display()));
let mut cmd = builder.tool_cmd(Tool::RustcPerfWrapper);
cmd.env("PERF_RUSTC", rustc)
.env("PERF_COLLECTOR", collector)
Kobzol marked this conversation as resolved.
Show resolved Hide resolved
.env("PERF_RESULT_DIR", profile_results_dir)
.args(args);
builder.run(&mut cmd);
}
Kobzol marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions src/bootstrap/src/core/build_steps/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ bootstrap_tool!(
GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
RustcPerfWrapper, "src/tools/rustc-perf-wrapper", "rustc-perf-wrapper";
);

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
Expand Down
4 changes: 3 additions & 1 deletion src/bootstrap/src/core/config/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,9 @@ Arguments:
versioned_dirs: bool,
},
/// Perform profiling and benchmarking of the compiler using the
/// `rustc-perf` benchmark suite.
/// `rustc-perf-wrapper` tool.
///
/// You need to pass arguments after `--`, e.g.`x perf -- cachegrind`.
Kobzol marked this conversation as resolved.
Show resolved Hide resolved
Perf {},
}

Expand Down
2 changes: 1 addition & 1 deletion src/etc/completions/x.py.fish
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained
complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development'
complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files'
complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies'
complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite'
complete -c x.py -n "__fish_use_subcommand" -f -a "perf" -d 'Perform profiling and benchmarking of the compiler using the `rustc-perf-wrapper` tool'
complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F
complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f
Expand Down
2 changes: 1 addition & 1 deletion src/etc/completions/x.py.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
[CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development')
[CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files')
[CompletionResult]::new('vendor', 'vendor', [CompletionResultType]::ParameterValue, 'Vendor dependencies')
[CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf` benchmark suite')
[CompletionResult]::new('perf', 'perf', [CompletionResultType]::ParameterValue, 'Perform profiling and benchmarking of the compiler using the `rustc-perf-wrapper` tool')
break
}
'x.py;build' {
Expand Down
2 changes: 1 addition & 1 deletion src/etc/completions/x.py.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ _x.py_commands() {
'setup:Set up the environment for development' \
'suggest:Suggest a subset of tests to run, based on modified files' \
'vendor:Vendor dependencies' \
'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf\` benchmark suite' \
'perf:Perform profiling and benchmarking of the compiler using the \`rustc-perf-wrapper\` tool' \
)
_describe -t commands 'x.py commands' commands "$@"
}
Expand Down
7 changes: 7 additions & 0 deletions src/tools/rustc-perf-wrapper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "rustc-perf-wrapper"
version = "0.1.0"
edition = "2021"

[dependencies]
clap = { version = "4.5.7", features = ["derive", "env"] }
3 changes: 3 additions & 0 deletions src/tools/rustc-perf-wrapper/README.md
Original file line number Diff line number Diff line change
@@ -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 run perf`.
45 changes: 45 additions & 0 deletions src/tools/rustc-perf-wrapper/src/config.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
130 changes: 130 additions & 0 deletions src/tools/rustc-perf-wrapper/src/main.rs
Original file line number Diff line number Diff line change
@@ -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 = "PERF_RUSTC")]
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());
}
}
Loading