From 142995f15f3d843f7453d2cd875eab4aababd410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 29 Jul 2023 17:29:54 +0200 Subject: [PATCH] Pass BOLT profile to bootstrap to be included in the reproducible artifacts archive --- src/bootstrap/config.rs | 6 ++++-- src/bootstrap/dist.rs | 4 ++-- src/bootstrap/flags.rs | 7 ++----- src/tools/opt-dist/src/bolt.rs | 2 +- src/tools/opt-dist/src/exec.rs | 7 ++++++- src/tools/opt-dist/src/main.rs | 18 ++++++++++++------ src/tools/opt-dist/src/training.rs | 2 +- src/tools/opt-dist/src/utils/io.rs | 22 ++++++++-------------- 8 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 56e667d4d12..45bea9608fc 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -232,8 +232,8 @@ pub struct Config { pub llvm_profile_use: Option, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option, - pub llvm_bolt_profile_generate: bool, - pub llvm_bolt_profile_use: Option, + + pub reproducible_artifacts: Vec, pub build: TargetSelection, pub hosts: Vec, @@ -1462,6 +1462,8 @@ impl Config { 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. let default = config.channel == "dev"; config.omit_git_hash = omit_git_hash.unwrap_or(default); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 16d25b9b814..32da4ac29a4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2265,8 +2265,8 @@ impl Step for ReproducibleArtifacts { tarball.add_file(path, ".", 0o644); added_anything = true; } - if let Some(path) = builder.config.llvm_bolt_profile_use.as_ref() { - tarball.add_file(path, ".", 0o644); + for profile in &builder.config.reproducible_artifacts { + tarball.add_file(profile, ".", 0o644); added_anything = true; } if added_anything { Some(tarball.generate()) } else { None } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 96c9daf2c2c..a1e0a440729 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -149,12 +149,9 @@ pub struct Flags { /// generate PGO profile with llvm built for rustc #[arg(global(true), long)] 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)] - pub llvm_bolt_profile_generate: bool, - /// use BOLT profile for LLVM build - #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] - pub llvm_bolt_profile_use: Option, + pub reproducible_artifact: Vec, #[arg(global(true))] /// paths for the subcommand pub paths: Vec, diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs index 161ba4f3291..e44b8a4db92 100644 --- a/src/tools/opt-dist/src/bolt.rs +++ b/src/tools/opt-dist/src/bolt.rs @@ -40,7 +40,7 @@ pub fn with_bolt_instrumented anyhow::Result, R>( } /// 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. // BOLT cannot handle optimizing when the input and output is the same file, because it performs // in-place patching. diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs index 100b3ada7f2..4765dceb5dd 100644 --- a/src/tools/opt-dist/src/exec.rs +++ b/src/tools/opt-dist/src/exec.rs @@ -1,7 +1,7 @@ use crate::environment::Environment; use crate::metrics::{load_metrics, record_metrics}; use crate::timer::TimerSection; -use crate::training::{LlvmPGOProfile, RustcPGOProfile}; +use crate::training::{LlvmBoltProfile, LlvmPGOProfile, RustcPGOProfile}; use camino::{Utf8Path, Utf8PathBuf}; use std::collections::BTreeMap; use std::fs::File; @@ -159,6 +159,11 @@ impl Bootstrap { 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. pub fn avoid_rustc_rebuild(mut self) -> Self { self.cmd = self.cmd.arg("--keep-stage").arg("0").arg("--keep-stage").arg("1"); diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 256317a3bcc..f6edd008845 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -95,7 +95,7 @@ fn execute_pipeline( Ok(profile) })?; - if env.supports_bolt() { + let llvm_bolt_profile = if env.supports_bolt() { // Stage 3: Build BOLT instrumented LLVM // 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. @@ -128,18 +128,24 @@ fn execute_pipeline( // 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 // 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 - 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) .rustc_pgo_optimize(&rustc_pgo_profile) .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 // The previous PGO optimized rustc build and PGO optimized LLVM builds should be reused. timer.section("Stage 4 (final build)", |stage| dist.run(stage))?; diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 951bc6f9264..a9e88bdbb60 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -175,7 +175,7 @@ pub fn gather_llvm_bolt_profiles(env: &dyn Environment) -> anyhow::Result anyhow::Result { - let mut files = glob::glob(&format!("{directory}/{prefix}*{suffix}"))? + let files = glob::glob(&format!("{directory}/{prefix}*{suffix}"))? .into_iter() .collect::, _>>()?; - match files.pop() { - Some(file) => { - if !files.is_empty() { - files.push(file); - Err(anyhow::anyhow!( - "More than one file with prefix {prefix} found in {directory}: {:?}", - files - )) - } else { - Ok(Utf8PathBuf::from_path_buf(file).unwrap()) - } - } - None => Err(anyhow::anyhow!("No file with prefix {prefix} found in {directory}")), + match files.len() { + 0 => Err(anyhow::anyhow!("No file with prefix {prefix} found in {directory}")), + 1 => Ok(Utf8PathBuf::from_path_buf(files[0].clone()).unwrap()), + _ => Err(anyhow::anyhow!( + "More than one file with prefix {prefix} found in {directory}: {:?}", + files + )), } }