Pass BOLT profile to bootstrap to be included in the reproducible artifacts archive

This commit is contained in:
Jakub Beránek 2023-07-29 17:29:54 +02:00
parent 78403f4e13
commit 142995f15f
No known key found for this signature in database
GPG Key ID: 909CD0D26483516B
8 changed files with 36 additions and 32 deletions

View File

@ -232,8 +232,8 @@ pub struct Config {
pub llvm_profile_use: Option<String>, pub llvm_profile_use: Option<String>,
pub llvm_profile_generate: bool, pub llvm_profile_generate: bool,
pub llvm_libunwind_default: Option<LlvmLibunwind>, pub llvm_libunwind_default: Option<LlvmLibunwind>,
pub llvm_bolt_profile_generate: bool,
pub llvm_bolt_profile_use: Option<String>, pub reproducible_artifacts: Vec<String>,
pub build: TargetSelection, pub build: TargetSelection,
pub hosts: Vec<TargetSelection>, pub hosts: Vec<TargetSelection>,
@ -1462,6 +1462,8 @@ impl Config {
config.rust_profile_generate = flags.rust_profile_generate; config.rust_profile_generate = flags.rust_profile_generate;
} }
config.reproducible_artifacts = flags.reproducible_artifact;
// rust_info must be set before is_ci_llvm_available() is called. // rust_info must be set before is_ci_llvm_available() is called.
let default = config.channel == "dev"; let default = config.channel == "dev";
config.omit_git_hash = omit_git_hash.unwrap_or(default); config.omit_git_hash = omit_git_hash.unwrap_or(default);

View File

@ -2265,8 +2265,8 @@ impl Step for ReproducibleArtifacts {
tarball.add_file(path, ".", 0o644); tarball.add_file(path, ".", 0o644);
added_anything = true; added_anything = true;
} }
if let Some(path) = builder.config.llvm_bolt_profile_use.as_ref() { for profile in &builder.config.reproducible_artifacts {
tarball.add_file(path, ".", 0o644); tarball.add_file(profile, ".", 0o644);
added_anything = true; added_anything = true;
} }
if added_anything { Some(tarball.generate()) } else { None } if added_anything { Some(tarball.generate()) } else { None }

View File

@ -149,12 +149,9 @@ pub struct Flags {
/// generate PGO profile with llvm built for rustc /// generate PGO profile with llvm built for rustc
#[arg(global(true), long)] #[arg(global(true), long)]
pub llvm_profile_generate: bool, pub llvm_profile_generate: bool,
/// generate BOLT profile for LLVM build /// Additional reproducible artifacts that should be added to the reproducible artifacts archive.
#[arg(global(true), long)] #[arg(global(true), long)]
pub llvm_bolt_profile_generate: bool, pub reproducible_artifact: Vec<String>,
/// use BOLT profile for LLVM build
#[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
pub llvm_bolt_profile_use: Option<String>,
#[arg(global(true))] #[arg(global(true))]
/// paths for the subcommand /// paths for the subcommand
pub paths: Vec<PathBuf>, pub paths: Vec<PathBuf>,

View File

@ -40,7 +40,7 @@ pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>(
} }
/// Optimizes the file at `path` with BOLT in-place using the given `profile`. /// Optimizes the file at `path` with BOLT in-place using the given `profile`.
pub fn bolt_optimize(path: &Utf8Path, profile: LlvmBoltProfile) -> anyhow::Result<()> { pub fn bolt_optimize(path: &Utf8Path, profile: &LlvmBoltProfile) -> anyhow::Result<()> {
// Copy the artifact to a new location, so that we do not use the same input and output file. // Copy the artifact to a new location, so that we do not use the same input and output file.
// BOLT cannot handle optimizing when the input and output is the same file, because it performs // BOLT cannot handle optimizing when the input and output is the same file, because it performs
// in-place patching. // in-place patching.

View File

@ -1,7 +1,7 @@
use crate::environment::Environment; use crate::environment::Environment;
use crate::metrics::{load_metrics, record_metrics}; use crate::metrics::{load_metrics, record_metrics};
use crate::timer::TimerSection; use crate::timer::TimerSection;
use crate::training::{LlvmPGOProfile, RustcPGOProfile}; use crate::training::{LlvmBoltProfile, LlvmPGOProfile, RustcPGOProfile};
use camino::{Utf8Path, Utf8PathBuf}; use camino::{Utf8Path, Utf8PathBuf};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs::File; use std::fs::File;
@ -159,6 +159,11 @@ impl Bootstrap {
self self
} }
pub fn with_bolt_profile(mut self, profile: LlvmBoltProfile) -> Self {
self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str());
self
}
/// Do not rebuild rustc, and use a previously built rustc sysroot instead. /// Do not rebuild rustc, and use a previously built rustc sysroot instead.
pub fn avoid_rustc_rebuild(mut self) -> Self { pub fn avoid_rustc_rebuild(mut self) -> Self {
self.cmd = self.cmd.arg("--keep-stage").arg("0").arg("--keep-stage").arg("1"); self.cmd = self.cmd.arg("--keep-stage").arg("0").arg("--keep-stage").arg("1");

View File

@ -95,7 +95,7 @@ fn execute_pipeline(
Ok(profile) Ok(profile)
})?; })?;
if env.supports_bolt() { let llvm_bolt_profile = if env.supports_bolt() {
// Stage 3: Build BOLT instrumented LLVM // Stage 3: Build BOLT instrumented LLVM
// We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles. // We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles.
// Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build. // Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build.
@ -128,18 +128,24 @@ fn execute_pipeline(
// the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*, // the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
// therefore it will actually optimize all the hard links, which means that the final // therefore it will actually optimize all the hard links, which means that the final
// packaged `libLLVM.so` file *will* be BOLT optimized. // packaged `libLLVM.so` file *will* be BOLT optimized.
bolt_optimize(&llvm_lib, profile).context("Could not optimize LLVM with BOLT")?; bolt_optimize(&llvm_lib, &profile).context("Could not optimize LLVM with BOLT")?;
// LLVM is not being cleared here, we want to use the BOLT-optimized LLVM // LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
Ok(()) Ok(Some(profile))
})?; })?
} } else {
None
};
let dist = Bootstrap::dist(env, &dist_args) let mut dist = Bootstrap::dist(env, &dist_args)
.llvm_pgo_optimize(&llvm_pgo_profile) .llvm_pgo_optimize(&llvm_pgo_profile)
.rustc_pgo_optimize(&rustc_pgo_profile) .rustc_pgo_optimize(&rustc_pgo_profile)
.avoid_rustc_rebuild(); .avoid_rustc_rebuild();
if let Some(llvm_bolt_profile) = llvm_bolt_profile {
dist = dist.with_bolt_profile(llvm_bolt_profile);
}
// Final stage: Assemble the dist artifacts // Final stage: Assemble the dist artifacts
// The previous PGO optimized rustc build and PGO optimized LLVM builds should be reused. // The previous PGO optimized rustc build and PGO optimized LLVM builds should be reused.
timer.section("Stage 4 (final build)", |stage| dist.run(stage))?; timer.section("Stage 4 (final build)", |stage| dist.run(stage))?;

View File

@ -175,7 +175,7 @@ pub fn gather_llvm_bolt_profiles(env: &dyn Environment) -> anyhow::Result<LlvmBo
.context("Cannot gather LLVM BOLT profiles") .context("Cannot gather LLVM BOLT profiles")
})?; })?;
let merged_profile = env.opt_artifacts().join("bolt.profdata"); let merged_profile = env.opt_artifacts().join("llvm-bolt.profdata");
let profile_root = Utf8PathBuf::from("/tmp/prof.fdata"); let profile_root = Utf8PathBuf::from("/tmp/prof.fdata");
log::info!("Merging LLVM BOLT profiles to {merged_profile}"); log::info!("Merging LLVM BOLT profiles to {merged_profile}");

View File

@ -74,21 +74,15 @@ pub fn find_file_in_dir(
prefix: &str, prefix: &str,
suffix: &str, suffix: &str,
) -> anyhow::Result<Utf8PathBuf> { ) -> anyhow::Result<Utf8PathBuf> {
let mut files = glob::glob(&format!("{directory}/{prefix}*{suffix}"))? let files = glob::glob(&format!("{directory}/{prefix}*{suffix}"))?
.into_iter() .into_iter()
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
match files.pop() { match files.len() {
Some(file) => { 0 => Err(anyhow::anyhow!("No file with prefix {prefix} found in {directory}")),
if !files.is_empty() { 1 => Ok(Utf8PathBuf::from_path_buf(files[0].clone()).unwrap()),
files.push(file); _ => Err(anyhow::anyhow!(
Err(anyhow::anyhow!( "More than one file with prefix {prefix} found in {directory}: {:?}",
"More than one file with prefix {prefix} found in {directory}: {:?}", files
files )),
))
} else {
Ok(Utf8PathBuf::from_path_buf(file).unwrap())
}
}
None => Err(anyhow::anyhow!("No file with prefix {prefix} found in {directory}")),
} }
} }