Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 18 additions & 0 deletions bootstrap.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,24 @@
#dist.vendor = if "is a tarball source" || "is a git repository" { true } else { false }


# =============================================================================
# Profile-guided optimization options
#
# Configure the PGO profile to be used for compilation, or a path where the
# profile will be written by an instrumented binary, for individual components
# =============================================================================

# Use the following profile to PGO optimize the Rust compiler.
#pgo.rustc.use = "/tmp/profiles/foo.profraw"
# Instrument the Rust compiler, so that when executed, it will gather profiles
# to this path.
#pgo.rustc.generate = "/tmp/profiles/foo.profraw"
# Use the following profile to PGO optimize LLVM.
#pgo.llvm.use = "/tmp/profiles/foo.profraw"
# Instrument LLVM, so that when executed, it will gather profiles
# Note: for LLVM specifically, this should be a directory, not a file path.
#pgo.llvm.generate = "/tmp/profiles"

# =============================================================================
# Options for specific targets
#
Expand Down
14 changes: 6 additions & 8 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,22 +1293,20 @@ pub fn rustc_cargo(
cargo.rustflag("-Clink-args=-Wl,--icf=all");
}

if builder.config.rust_profile_use.is_some() && builder.config.rust_profile_generate.is_some() {
panic!("Cannot use and generate PGO profiles at the same time");
}
let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
let is_collecting = if let Some(path) = &builder.config.rust_pgo.generate_profile {
if build_compiler.stage == 1 {
cargo.rustflag(&format!("-Cprofile-generate={path}"));
cargo
.rustflag(&format!("-Cprofile-generate={}", path.to_str().expect("non-UTF8 path")));
// Apparently necessary to avoid overflowing the counters during
// a Cargo build profile
cargo.rustflag("-Cllvm-args=-vp-counters-per-site=4");
true
} else {
false
}
} else if let Some(path) = &builder.config.rust_profile_use {
} else if let Some(path) = &builder.config.rust_pgo.use_profile {
if build_compiler.stage == 1 {
cargo.rustflag(&format!("-Cprofile-use={path}"));
cargo.rustflag(&format!("-Cprofile-use={}", path.to_str().expect("non-UTF8 path")));
if builder.is_verbose() {
cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
}
Expand Down Expand Up @@ -1464,7 +1462,7 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect
// found. This is to avoid the linker errors about undefined references to
// `__llvm_profile_instrument_memop` when linking `rustc_driver`.
let mut llvm_linker_flags = String::new();
if builder.config.llvm_profile_generate
if builder.config.llvm_pgo.generate_profile.is_some()
&& target.is_msvc()
&& let Some(ref clang_cl_path) = builder.config.llvm_clang_cl
{
Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3035,11 +3035,11 @@ impl Step for ReproducibleArtifacts {
fn run(self, builder: &Builder<'_>) -> Self::Output {
let mut added_anything = false;
let tarball = Tarball::new(builder, "reproducible-artifacts", &self.target.triple);
if let Some(path) = builder.config.rust_profile_use.as_ref() {
if let Some(path) = builder.config.rust_pgo.use_profile.as_ref() {
tarball.add_file(path, ".", FileType::Regular);
added_anything = true;
}
if let Some(path) = builder.config.llvm_profile_use.as_ref() {
if let Some(path) = builder.config.llvm_pgo.use_profile.as_ref() {
tarball.add_file(path, ".", FileType::Regular);
added_anything = true;
}
Expand Down
15 changes: 9 additions & 6 deletions src/bootstrap/src/core/build_steps/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use build_helper::git::PathFreshness;

use crate::core::build_steps::llvm;
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step, StepMetadata};
use crate::core::config::{Config, TargetSelection};
use crate::core::config::{Config, LlvmPgoGenerationMode, TargetSelection};
use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
use crate::utils::exec::command;
use crate::utils::helpers::{
Expand Down Expand Up @@ -369,14 +369,17 @@ impl Step for Llvm {
// This flag makes sure `FileCheck` is copied in the final binaries directory.
cfg.define("LLVM_INSTALL_UTILS", "ON");

if builder.config.llvm_profile_generate {
if let Some(mode) = builder.config.llvm_pgo.generate_profile.as_ref() {
cfg.define("LLVM_BUILD_INSTRUMENTED", "IR");
if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") {
cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir);
match mode {
LlvmPgoGenerationMode::Implicit => {}
LlvmPgoGenerationMode::Directory(llvm_profile_dir) => {
cfg.define("LLVM_PROFILE_DATA_DIR", llvm_profile_dir);
}
}
cfg.define("LLVM_BUILD_RUNTIME", "No");
}
if let Some(path) = builder.config.llvm_profile_use.as_ref() {
if let Some(path) = builder.config.llvm_pgo.use_profile.as_ref() {
cfg.define("LLVM_PROFDATA_FILE", path);
}

Expand Down Expand Up @@ -1326,7 +1329,7 @@ impl Step for Lld {
// when doing PGO on CI, cmake or clang-cl don't automatically link clang's
// profiler runtime in. In that case, we need to manually ask cmake to do it, to avoid
// linking errors, much like LLVM's cmake setup does in that situation.
if builder.config.llvm_profile_generate
if builder.config.llvm_pgo.generate_profile.is_some()
&& target.is_msvc()
&& let Some(clang_cl_path) = builder.config.llvm_clang_cl.as_ref()
{
Expand Down
102 changes: 85 additions & 17 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use crate::core::config::toml::dist::Dist;
use crate::core::config::toml::gcc::Gcc;
use crate::core::config::toml::install::Install;
use crate::core::config::toml::llvm::Llvm;
use crate::core::config::toml::pgo::{Pgo, PgoConfig};
use crate::core::config::toml::rust::{
BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc,
parse_codegen_backends,
Expand Down Expand Up @@ -190,6 +191,7 @@ pub struct Config {
pub llvm_cxxflags: Option<String>,
pub llvm_ldflags: Option<String>,
pub llvm_use_libcxx: bool,
pub llvm_pgo: LlvmPgoConfig,

// gcc codegen options
pub gcc_ci_mode: GccCiMode,
Expand Down Expand Up @@ -225,17 +227,14 @@ pub struct Config {
pub rust_remap_debuginfo: bool,
pub rust_new_symbol_mangling: Option<bool>,
pub rust_annotate_moves_size_limit: Option<u64>,
pub rust_profile_use: Option<String>,
pub rust_profile_generate: Option<String>,
pub rust_lto: RustcLto,
pub rust_validate_mir_opts: Option<u32>,
pub rust_std_features: BTreeSet<String>,
pub rust_break_on_ice: bool,
pub rust_parallel_frontend_threads: Option<u32>,
pub rust_rustflags: Vec<String>,
pub rust_pgo: PgoConfig,

pub llvm_profile_use: Option<String>,
pub llvm_profile_generate: bool,
pub llvm_libunwind_default: Option<LlvmLibunwind>,
pub enable_bolt_settings: bool,

Expand Down Expand Up @@ -456,8 +455,20 @@ impl Config {

// Now load the TOML config, as soon as possible
let (mut toml, toml_path) = load_toml_config(&src, flags_config, &get_toml);

postprocess_toml(&mut toml, &src, toml_path.clone(), &exec_ctx, &flags_set, &get_toml);
let TomlConfig {
change_id: toml_change_id,
build: toml_build,
install: toml_install,
llvm: toml_llvm,
gcc: toml_gcc,
rust: toml_rust,
target: toml_target,
dist: toml_dist,
pgo: toml_pgo,
profile: _,
include: _,
} = toml;

// Now override TOML values with flags, to make sure that we won't later override flags with
// TOML values by accident instead, because flags have higher priority.
Expand Down Expand Up @@ -523,7 +534,7 @@ impl Config {
ccache: build_ccache,
exclude: build_exclude,
compiletest_allow_stage0: build_compiletest_allow_stage0,
} = toml.build.unwrap_or_default();
} = toml_build.unwrap_or_default();

let Install {
prefix: install_prefix,
Expand All @@ -533,7 +544,7 @@ impl Config {
libdir: install_libdir,
mandir: install_mandir,
datadir: install_datadir,
} = toml.install.unwrap_or_default();
} = toml_install.unwrap_or_default();

let Rust {
optimize: rust_optimize,
Expand Down Expand Up @@ -595,7 +606,7 @@ impl Config {
std_features: rust_std_features,
break_on_ice: rust_break_on_ice,
rustflags: rust_rustflags,
} = toml.rust.unwrap_or_default();
} = toml_rust.unwrap_or_default();

let Llvm {
optimize: llvm_optimize,
Expand Down Expand Up @@ -627,7 +638,7 @@ impl Config {
enable_warnings: llvm_enable_warnings,
download_ci_llvm: llvm_download_ci_llvm,
build_config: llvm_build_config,
} = toml.llvm.unwrap_or_default();
} = toml_llvm.unwrap_or_default();

let Dist {
sign_folder: dist_sign_folder,
Expand All @@ -637,12 +648,57 @@ impl Config {
compression_profile: dist_compression_profile,
include_mingw_linker: dist_include_mingw_linker,
vendor: dist_vendor,
} = toml.dist.unwrap_or_default();
} = toml_dist.unwrap_or_default();

let Gcc {
download_ci_gcc: gcc_download_ci_gcc,
libgccjit_libs_dir: gcc_libgccjit_libs_dir,
} = toml.gcc.unwrap_or_default();
} = toml_gcc.unwrap_or_default();

let Pgo { rustc: pgo_rustc, llvm: pgo_llvm } = toml_pgo.unwrap_or_default();

// Backcompat: flags have priority over config
if flags_rust_profile_use.is_some() || flags_rust_profile_generate.is_some() {
eprintln!(
"WARNING: the `--rust-profile-generate` and `--rust-profile-use` flags have been deprecated. Configure PGO through the config file instead, in the [pgo.rustc] section."
);
}
if rust_profile_use.is_some() || rust_profile_generate.is_some() {
eprintln!(
"WARNING: the `rust.profile-generate` and `rust.profile-use` config options have been deprecated. Configure PGO through the config file instead, in the [pgo.rustc] section."
);
}
if flags_llvm_profile_use.is_some() || flags_llvm_profile_generate {
eprintln!(
"WARNING: the `--llvm-profile-generate` and `--llvm-profile-use` flags have been deprecated. Configure PGO through the config file instead, in the [pgo.llvm] section."
);
}

let mut pgo_rustc = pgo_rustc.unwrap_or_default();
pgo_rustc.use_profile =
flags_rust_profile_use.or(pgo_rustc.use_profile).or(rust_profile_use);
pgo_rustc.generate_profile =
flags_rust_profile_generate.or(pgo_rustc.generate_profile).or(rust_profile_generate);
if pgo_rustc.use_profile.is_some() && pgo_rustc.generate_profile.is_some() {
panic!("Cannot use and generate rust PGO profiles at the same time");
}

let pgo_llvm = pgo_llvm.unwrap_or_default();
let pgo_llvm = LlvmPgoConfig {
use_profile: flags_llvm_profile_use.or(pgo_llvm.use_profile),
generate_profile: if flags_llvm_profile_generate {
Some(if let Ok(llvm_profile_dir) = std::env::var("LLVM_PROFILE_DIR") {
LlvmPgoGenerationMode::Directory(PathBuf::from(llvm_profile_dir))
} else {
LlvmPgoGenerationMode::Implicit
})
} else {
pgo_llvm.generate_profile.map(LlvmPgoGenerationMode::Directory)
},
};
if pgo_llvm.use_profile.is_some() && pgo_llvm.generate_profile.is_some() {
panic!("Cannot use and generate LLVM PGO profiles at the same time");
}

if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() {
panic!(
Expand Down Expand Up @@ -877,7 +933,7 @@ impl Config {
// Linux targets for which the user explicitly overrode the used linker
let mut targets_with_user_linker_override = HashSet::new();

if let Some(t) = toml.target {
if let Some(t) = toml_target {
for (triple, cfg) in t {
let TomlTarget {
cc: target_cc,
Expand Down Expand Up @@ -1337,7 +1393,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to
cargo_info,
cargo_native_static: build_cargo_native_static.unwrap_or(false),
ccache,
change_id: toml.change_id.inner,
change_id: toml_change_id.inner,
channel,
ci_env,
clippy_info,
Expand Down Expand Up @@ -1428,10 +1484,9 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to
),
llvm_offload: llvm_offload.unwrap_or(false),
llvm_optimize: llvm_optimize.unwrap_or(true),
llvm_pgo: pgo_llvm,
llvm_plugins: llvm_plugin.unwrap_or(false),
llvm_polly: llvm_polly.unwrap_or(false),
llvm_profile_generate: flags_llvm_profile_generate,
llvm_profile_use: flags_llvm_profile_use,
llvm_release_debuginfo: llvm_release_debuginfo.unwrap_or(false),
llvm_static_stdcpp: llvm_static_libstdcpp.unwrap_or(false),
llvm_targets,
Expand Down Expand Up @@ -1496,8 +1551,7 @@ NOTE: Please add `--stage 2` to your command line, or if you're sure you want to
.or(rust_overflow_checks)
.unwrap_or(rust_debug == Some(true)),
rust_parallel_frontend_threads: rust_parallel_frontend_threads.map(threads_from_config),
rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate),
rust_profile_use: flags_rust_profile_use.or(rust_profile_use),
rust_pgo: pgo_rustc,
rust_randomize_layout: rust_randomize_layout.unwrap_or(false),
rust_remap_debuginfo: rust_remap_debuginfo.unwrap_or(false),
rust_rpath: rust_rpath.unwrap_or(true),
Expand Down Expand Up @@ -2030,6 +2084,20 @@ fn compute_src_directory(src_dir: Option<PathBuf>, exec_ctx: &ExecutionContext)
None
}

#[derive(Clone)]
pub enum LlvmPgoGenerationMode {
/// Enable PGO instrumentation that will write profiles into a default path.
Implicit,
/// Enable PGO instrumentation that will write profiles into the specified directory.
Directory(PathBuf),
}

#[derive(Clone)]
pub struct LlvmPgoConfig {
pub use_profile: Option<PathBuf>,
pub generate_profile: Option<LlvmPgoGenerationMode>,
}

/// Loads bootstrap TOML config and returns the config together with a path from where
/// it was loaded.
/// `src` is the source root directory, and `config_path` is an optionally provided path to the
Expand Down
10 changes: 7 additions & 3 deletions src/bootstrap/src/core/config/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,22 @@ pub struct Flags {

/// generate PGO profile with rustc build
#[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
pub rust_profile_generate: Option<String>,
// FIXME: Remove this option at the end of 2026
pub rust_profile_generate: Option<PathBuf>,
/// use PGO profile for rustc build
// FIXME: Remove this option at the end of 2026
#[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
pub rust_profile_use: Option<String>,
pub rust_profile_use: Option<PathBuf>,
/// use PGO profile for LLVM build
// FIXME: Remove this option at the end of 2026
#[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
pub llvm_profile_use: Option<String>,
pub llvm_profile_use: Option<PathBuf>,
// LLVM doesn't support a custom location for generating profile
// information.
//
// llvm_out/build/profiles/ is the location this writes to.
/// generate PGO profile with llvm built for rustc
// FIXME: Remove this option at the end of 2026
#[arg(global = true, long)]
pub llvm_profile_generate: bool,
/// Enable BOLT link flags
Expand Down
Loading
Loading