Skip to content

Commit f51a04b

Browse files
committed
Add x perf command for profiling the compiler using rustc-perf
1 parent 1d3a728 commit f51a04b

File tree

11 files changed

+309
-11
lines changed

11 files changed

+309
-11
lines changed

src/bootstrap/src/core/build_steps/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub(crate) mod doc;
77
pub(crate) mod format;
88
pub(crate) mod install;
99
pub(crate) mod llvm;
10+
pub(crate) mod perf;
1011
pub(crate) mod run;
1112
pub(crate) mod setup;
1213
pub(crate) mod suggest;
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::process::Command;
2+
3+
use crate::core::build_steps::compile::{Std, Sysroot};
4+
use crate::core::build_steps::tool::RustcPerf;
5+
use crate::core::builder::Builder;
6+
use crate::core::config::DebuginfoLevel;
7+
8+
/// Performs profiling using `rustc-perf` on a built version of the compiler.
9+
pub fn perf(builder: &Builder<'_>) {
10+
let collector = builder.ensure(RustcPerf {
11+
compiler: builder.compiler(0, builder.config.build),
12+
target: builder.config.build,
13+
});
14+
15+
if builder.build.config.rust_debuginfo_level_rustc == DebuginfoLevel::None {
16+
builder.info(r#"WARNING: You are compiling rustc without debuginfo, this will make profiling less useful.
17+
Consider setting `rust.debuginfo-level = 1` in `config.toml`."#);
18+
}
19+
20+
let compiler = builder.compiler(builder.top_stage, builder.config.build);
21+
builder.ensure(Std::new(compiler, builder.config.build));
22+
let sysroot = builder.ensure(Sysroot::new(compiler));
23+
let rustc = sysroot.join("bin/rustc");
24+
25+
let results_dir = builder.build.out.join("rustc-perf");
26+
27+
let mut cmd = Command::new(collector);
28+
let cmd = cmd
29+
.arg("profile_local")
30+
.arg("eprintln")
31+
.arg("--out-dir")
32+
.arg(&results_dir)
33+
.arg("--include")
34+
.arg("helloworld")
35+
.arg(&rustc);
36+
37+
builder.info(&format!("Running `rustc-perf` using `{}`", rustc.display()));
38+
39+
// We need to set the working directory to `src/tools/perf`, so that it can find the directory
40+
// with compile-time benchmarks.
41+
let cmd = cmd.current_dir(builder.src.join("src/tools/rustc-perf"));
42+
builder.build.run(cmd);
43+
44+
builder.info(&format!("You can find the results at `{}`", results_dir.display()));
45+
}

src/bootstrap/src/core/build_steps/tool.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ struct ToolBuild {
3333
/// Nightly-only features that are allowed (comma-separated list).
3434
allow_features: &'static str,
3535
/// Additional arguments to pass to the `cargo` invocation.
36-
cargo_args: Vec<String>
36+
cargo_args: Vec<String>,
3737
}
3838

3939
impl Builder<'_> {
@@ -365,7 +365,7 @@ impl Step for OptimizedDist {
365365
source_type: SourceType::InTree,
366366
extra_features: Vec::new(),
367367
allow_features: "",
368-
cargo_args: Vec::new()
368+
cargo_args: Vec::new(),
369369
})
370370
}
371371
}
@@ -469,7 +469,7 @@ impl Step for ErrorIndex {
469469
source_type: SourceType::InTree,
470470
extra_features: Vec::new(),
471471
allow_features: "",
472-
cargo_args: Vec::new()
472+
cargo_args: Vec::new(),
473473
})
474474
}
475475
}
@@ -504,7 +504,7 @@ impl Step for RemoteTestServer {
504504
source_type: SourceType::InTree,
505505
extra_features: Vec::new(),
506506
allow_features: "",
507-
cargo_args: Vec::new()
507+
cargo_args: Vec::new(),
508508
})
509509
}
510510
}
@@ -666,7 +666,7 @@ impl Step for Cargo {
666666
source_type: SourceType::Submodule,
667667
extra_features: Vec::new(),
668668
allow_features: "",
669-
cargo_args: Vec::new()
669+
cargo_args: Vec::new(),
670670
})
671671
}
672672
}
@@ -694,7 +694,7 @@ impl Step for LldWrapper {
694694
source_type: SourceType::InTree,
695695
extra_features: Vec::new(),
696696
allow_features: "",
697-
cargo_args: Vec::new()
697+
cargo_args: Vec::new(),
698698
})
699699
}
700700
}
@@ -743,7 +743,7 @@ impl Step for RustAnalyzer {
743743
extra_features: vec!["in-rust-tree".to_owned()],
744744
source_type: SourceType::InTree,
745745
allow_features: RustAnalyzer::ALLOW_FEATURES,
746-
cargo_args: Vec::new()
746+
cargo_args: Vec::new(),
747747
})
748748
}
749749
}
@@ -791,7 +791,7 @@ impl Step for RustAnalyzerProcMacroSrv {
791791
extra_features: vec!["in-rust-tree".to_owned()],
792792
source_type: SourceType::InTree,
793793
allow_features: RustAnalyzer::ALLOW_FEATURES,
794-
cargo_args: Vec::new()
794+
cargo_args: Vec::new(),
795795
});
796796

797797
// Copy `rust-analyzer-proc-macro-srv` to `<sysroot>/libexec/`

src/bootstrap/src/core/builder.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ pub enum Kind {
666666
Setup,
667667
Suggest,
668668
Vendor,
669+
Perf,
669670
}
670671

671672
impl Kind {
@@ -687,6 +688,7 @@ impl Kind {
687688
Kind::Setup => "setup",
688689
Kind::Suggest => "suggest",
689690
Kind::Vendor => "vendor",
691+
Kind::Perf => "perf",
690692
}
691693
}
692694

@@ -698,6 +700,7 @@ impl Kind {
698700
Kind::Run => "Running",
699701
Kind::Suggest => "Suggesting",
700702
Kind::Clippy => "Linting",
703+
Kind::Perf => "Profiling & benchmarking",
701704
_ => {
702705
let title_letter = self.as_str()[0..1].to_ascii_uppercase();
703706
return format!("{title_letter}{}ing", &self.as_str()[1..]);
@@ -951,7 +954,7 @@ impl<'a> Builder<'a> {
951954
Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std),
952955
Kind::Vendor => describe!(vendor::Vendor),
953956
// special-cased in Build::build()
954-
Kind::Format | Kind::Suggest => vec![],
957+
Kind::Format | Kind::Suggest | Kind::Perf => vec![],
955958
}
956959
}
957960

@@ -1023,6 +1026,7 @@ impl<'a> Builder<'a> {
10231026
path.as_ref().map_or([].as_slice(), |path| std::slice::from_ref(path)),
10241027
),
10251028
Subcommand::Vendor { .. } => (Kind::Vendor, &paths[..]),
1029+
Subcommand::Perf { .. } => (Kind::Perf, &paths[..]),
10261030
};
10271031

10281032
Self::new_internal(build, kind, paths.to_owned())

src/bootstrap/src/core/config/config.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2027,6 +2027,7 @@ impl Config {
20272027
Subcommand::Bench { .. } => flags.stage.or(bench_stage).unwrap_or(2),
20282028
Subcommand::Dist { .. } => flags.stage.or(dist_stage).unwrap_or(2),
20292029
Subcommand::Install { .. } => flags.stage.or(install_stage).unwrap_or(2),
2030+
Subcommand::Perf { .. } => flags.stage.unwrap_or(1),
20302031
// These are all bootstrap tools, which don't depend on the compiler.
20312032
// The stage we pass shouldn't matter, but use 0 just in case.
20322033
Subcommand::Clean { .. }
@@ -2064,7 +2065,8 @@ impl Config {
20642065
| Subcommand::Setup { .. }
20652066
| Subcommand::Format { .. }
20662067
| Subcommand::Suggest { .. }
2067-
| Subcommand::Vendor { .. } => {}
2068+
| Subcommand::Vendor { .. }
2069+
| Subcommand::Perf { .. } => {}
20682070
}
20692071
}
20702072

src/bootstrap/src/core/config/flags.rs

+4
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,9 @@ Arguments:
469469
#[arg(long)]
470470
versioned_dirs: bool,
471471
},
472+
/// Perform profiling and benchmarking of the compiler using the
473+
/// `rustc-perf` benchmark suite.
474+
Perf {},
472475
}
473476

474477
impl Subcommand {
@@ -490,6 +493,7 @@ impl Subcommand {
490493
Subcommand::Setup { .. } => Kind::Setup,
491494
Subcommand::Suggest { .. } => Kind::Suggest,
492495
Subcommand::Vendor { .. } => Kind::Vendor,
496+
Subcommand::Perf { .. } => Kind::Perf,
493497
}
494498
}
495499

src/bootstrap/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,9 @@ impl Build {
672672
Subcommand::Suggest { run } => {
673673
return core::build_steps::suggest::suggest(&builder::Builder::new(self), *run);
674674
}
675+
Subcommand::Perf { .. } => {
676+
return core::build_steps::perf::perf(&builder::Builder::new(self));
677+
}
675678
_ => (),
676679
}
677680

src/etc/completions/x.py.fish

+35
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained
4848
complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development'
4949
complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files'
5050
complete -c x.py -n "__fish_use_subcommand" -f -a "vendor" -d 'Vendor dependencies'
51+
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'
5152
complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F
5253
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)"
5354
complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f
@@ -628,3 +629,37 @@ complete -c x.py -n "__fish_seen_subcommand_from vendor" -l llvm-profile-generat
628629
complete -c x.py -n "__fish_seen_subcommand_from vendor" -l enable-bolt-settings -d 'Enable BOLT link flags'
629630
complete -c x.py -n "__fish_seen_subcommand_from vendor" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
630631
complete -c x.py -n "__fish_seen_subcommand_from vendor" -s h -l help -d 'Print help (see more with \'--help\')'
632+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l config -d 'TOML configuration file for build' -r -F
633+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)"
634+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l build -d 'build target of the stage0 compiler' -r -f
635+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l host -d 'host targets to build' -r -f
636+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l target -d 'target targets to build' -r -f
637+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l exclude -d 'build paths to exclude' -r -F
638+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip -d 'build paths to skip' -r -F
639+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l rustc-error-format -r -f
640+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)"
641+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f
642+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
643+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f
644+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)"
645+
complete -c x.py -n "__fish_seen_subcommand_from perf" -s j -l jobs -d 'number of jobs to run in parallel' -r -f
646+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny '',warn '',default ''}"
647+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l error-format -d 'rustc error format' -r -f
648+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always '',never '',auto ''}"
649+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true '',false ''}"
650+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F
651+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F
652+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F
653+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l reproducible-artifact -d 'Additional reproducible artifacts that should be added to the reproducible artifacts archive' -r
654+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l set -d 'override options in config.toml' -r -f
655+
complete -c x.py -n "__fish_seen_subcommand_from perf" -s v -l verbose -d 'use verbose output (-vv for very verbose)'
656+
complete -c x.py -n "__fish_seen_subcommand_from perf" -s i -l incremental -d 'use incremental compilation'
657+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l include-default-paths -d 'include default paths in addition to the provided ones'
658+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l dry-run -d 'dry run; don\'t build anything'
659+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l dump-bootstrap-shims -d 'Indicates whether to dump the work done from bootstrap shims'
660+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l json-output -d 'use message-format=json'
661+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l bypass-bootstrap-lock -d 'Bootstrap uses this value to decide whether it should bypass locking the build process. This is rarely needed (e.g., compiling the std library for different targets in parallel)'
662+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc'
663+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l enable-bolt-settings -d 'Enable BOLT link flags'
664+
complete -c x.py -n "__fish_seen_subcommand_from perf" -l skip-stage0-validation -d 'Skip stage0 compiler validation'
665+
complete -c x.py -n "__fish_seen_subcommand_from perf" -s h -l help -d 'Print help (see more with \'--help\')'

0 commit comments

Comments
 (0)