Skip to content
/ rust Public
forked from rust-lang/rust

Commit 3114eb1

Browse files
committed
Auto merge of rust-lang#113592 - Kobzol:pgo-script-bolt, r=Mark-Simulacrum
Move BOLT from `bootstrap` to `opt-dist` Currently, we use BOLT to optimize LLVM for x64 Linux. The BOLT instrumentation and optimization step is implemented in `bootstrap`, but it was always quite hacky, because BOLT works quite differently than PGO. Rather than building an instrumented artifact, it takes an already built artifact and instruments it in-place. This is not a good fit for the bootstrap caching mechanism, and it meant that we had to run BOLT "on-the-fly" when packaging LLVM artifacts into the created sysroot. The BOLT code was also really only used by the PGO script (now called `opt-dist`) and nothing else, so it was quite hardcoded for this one single usage. And even if someone wanted to use the `--llvm-bolt-profile-[use/generate]` bootstrap flags outside of the PGO script, they would also need to implement profile gathering, as this is not performed by bootstrap anyway. I think that it could be more practical to move the BOLT logic to the `opt-dist` tool instead. This simplifies bootstrap, removes unneeded implementation of BOLT caching (we will now do it exactly once - no need to check if it has been performed already when bootstrap copies `libLLVM.so` around multiple times) and removes two BOLT-specific bootstrap flags, and also one special case for building LLVM (instead I pass the linker flags with `--set llvm.ldflags` from `opt-dist` now). There are also a few disadvantages to this new approach: - We have to guess/find the path to the built `libLLVM.so` file (but currently this is quite easy, it's just in `stage2/lib`). - We have to provide the BOLT profile externally to bootstrap, so that it is packaged into the reproducible artifacts archive. Doesn't seem like a big deal to me. - We are depending on some inner behavior of boostrap in `opt-dist` (namely, that `libLLVM.so` is hardlinked). But we do that for many other things in the `opt-dist` tool anyway, it's tied quite closely to bootstrap. I would like to go back to my attempts to also use BOLT for `librustc_driver.so`, and I think that it might be a bit simpler if I also do it from the `opt-dist` tool, so this is the first step towards that. Anyway, let me know what you think about this. It's just a refactoring in a way, no big deal. r? bootstrap
2 parents b321edd + 142995f commit 3114eb1

File tree

16 files changed

+225
-314
lines changed

16 files changed

+225
-314
lines changed

Diff for: Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -2495,6 +2495,7 @@ dependencies = [
24952495
"serde_json",
24962496
"sysinfo",
24972497
"tar",
2498+
"tempfile",
24982499
"xz",
24992500
"zip",
25002501
]

Diff for: src/bootstrap/bolt.rs

-62
This file was deleted.

Diff for: src/bootstrap/config.rs

+4-11
Original file line numberDiff line numberDiff line change
@@ -232,8 +232,8 @@ pub struct Config {
232232
pub llvm_profile_use: Option<String>,
233233
pub llvm_profile_generate: bool,
234234
pub llvm_libunwind_default: Option<LlvmLibunwind>,
235-
pub llvm_bolt_profile_generate: bool,
236-
pub llvm_bolt_profile_use: Option<String>,
235+
236+
pub reproducible_artifacts: Vec<String>,
237237

238238
pub build: TargetSelection,
239239
pub hosts: Vec<TargetSelection>,
@@ -1127,15 +1127,6 @@ impl Config {
11271127
config.free_args = std::mem::take(&mut flags.free_args);
11281128
config.llvm_profile_use = flags.llvm_profile_use;
11291129
config.llvm_profile_generate = flags.llvm_profile_generate;
1130-
config.llvm_bolt_profile_generate = flags.llvm_bolt_profile_generate;
1131-
config.llvm_bolt_profile_use = flags.llvm_bolt_profile_use;
1132-
1133-
if config.llvm_bolt_profile_generate && config.llvm_bolt_profile_use.is_some() {
1134-
eprintln!(
1135-
"Cannot use both `llvm_bolt_profile_generate` and `llvm_bolt_profile_use` at the same time"
1136-
);
1137-
exit!(1);
1138-
}
11391130

11401131
// Infer the rest of the configuration.
11411132

@@ -1471,6 +1462,8 @@ impl Config {
14711462
config.rust_profile_generate = flags.rust_profile_generate;
14721463
}
14731464

1465+
config.reproducible_artifacts = flags.reproducible_artifact;
1466+
14741467
// rust_info must be set before is_ci_llvm_available() is called.
14751468
let default = config.channel == "dev";
14761469
config.omit_git_hash = omit_git_hash.unwrap_or(default);

Diff for: src/bootstrap/dist.rs

+3-128
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ use std::process::Command;
1818

1919
use object::read::archive::ArchiveFile;
2020
use object::BinaryFormat;
21-
use sha2::Digest;
2221

23-
use crate::bolt::{instrument_with_bolt, optimize_with_bolt};
2422
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
2523
use crate::cache::{Interned, INTERNER};
2624
use crate::channel;
@@ -1941,19 +1939,7 @@ fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
19411939
return;
19421940
}
19431941

1944-
// After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
1945-
// This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
1946-
// We perform the instrumentation/optimization here, on the fly, just before they are being
1947-
// packaged into some destination directory.
1948-
let postprocessed = if builder.config.llvm_bolt_profile_generate {
1949-
builder.ensure(BoltInstrument::new(source.to_path_buf()))
1950-
} else if let Some(path) = &builder.config.llvm_bolt_profile_use {
1951-
builder.ensure(BoltOptimize::new(source.to_path_buf(), path.into()))
1952-
} else {
1953-
source.to_path_buf()
1954-
};
1955-
1956-
builder.install(&postprocessed, destination, 0o644);
1942+
builder.install(&source, destination, 0o644);
19571943
}
19581944

19591945
/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
@@ -2038,117 +2024,6 @@ pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection
20382024
}
20392025
}
20402026

2041-
/// Creates an output path to a BOLT-manipulated artifact for the given `file`.
2042-
/// The hash of the file is used to make sure that we don't mix BOLT artifacts amongst different
2043-
/// files with the same name.
2044-
///
2045-
/// We need to keep the file-name the same though, to make sure that copying the manipulated file
2046-
/// to a directory will not change the final file path.
2047-
fn create_bolt_output_path(builder: &Builder<'_>, file: &Path, hash: &str) -> PathBuf {
2048-
let directory = builder.out.join("bolt").join(hash);
2049-
t!(fs::create_dir_all(&directory));
2050-
directory.join(file.file_name().unwrap())
2051-
}
2052-
2053-
/// Instrument the provided file with BOLT.
2054-
/// Returns a path to the instrumented artifact.
2055-
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2056-
pub struct BoltInstrument {
2057-
file: PathBuf,
2058-
hash: String,
2059-
}
2060-
2061-
impl BoltInstrument {
2062-
fn new(file: PathBuf) -> Self {
2063-
let mut hasher = sha2::Sha256::new();
2064-
hasher.update(t!(fs::read(&file)));
2065-
let hash = hex::encode(hasher.finalize().as_slice());
2066-
2067-
Self { file, hash }
2068-
}
2069-
}
2070-
2071-
impl Step for BoltInstrument {
2072-
type Output = PathBuf;
2073-
2074-
const ONLY_HOSTS: bool = false;
2075-
const DEFAULT: bool = false;
2076-
2077-
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2078-
run.never()
2079-
}
2080-
2081-
fn run(self, builder: &Builder<'_>) -> PathBuf {
2082-
if builder.build.config.dry_run() {
2083-
return self.file.clone();
2084-
}
2085-
2086-
if builder.build.config.llvm_from_ci {
2087-
println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
2088-
}
2089-
2090-
println!("Instrumenting {} with BOLT", self.file.display());
2091-
2092-
let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
2093-
if !output_path.is_file() {
2094-
instrument_with_bolt(&self.file, &output_path);
2095-
}
2096-
output_path
2097-
}
2098-
}
2099-
2100-
/// Optimize the provided file with BOLT.
2101-
/// Returns a path to the optimized artifact.
2102-
///
2103-
/// The hash is stored in the step to make sure that we don't optimize the same file
2104-
/// twice (even under different file paths).
2105-
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
2106-
pub struct BoltOptimize {
2107-
file: PathBuf,
2108-
profile: PathBuf,
2109-
hash: String,
2110-
}
2111-
2112-
impl BoltOptimize {
2113-
fn new(file: PathBuf, profile: PathBuf) -> Self {
2114-
let mut hasher = sha2::Sha256::new();
2115-
hasher.update(t!(fs::read(&file)));
2116-
hasher.update(t!(fs::read(&profile)));
2117-
let hash = hex::encode(hasher.finalize().as_slice());
2118-
2119-
Self { file, profile, hash }
2120-
}
2121-
}
2122-
2123-
impl Step for BoltOptimize {
2124-
type Output = PathBuf;
2125-
2126-
const ONLY_HOSTS: bool = false;
2127-
const DEFAULT: bool = false;
2128-
2129-
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
2130-
run.never()
2131-
}
2132-
2133-
fn run(self, builder: &Builder<'_>) -> PathBuf {
2134-
if builder.build.config.dry_run() {
2135-
return self.file.clone();
2136-
}
2137-
2138-
if builder.build.config.llvm_from_ci {
2139-
println!("warning: trying to use BOLT with LLVM from CI, this will probably not work");
2140-
}
2141-
2142-
println!("Optimizing {} with BOLT", self.file.display());
2143-
2144-
let output_path = create_bolt_output_path(builder, &self.file, &self.hash);
2145-
if !output_path.is_file() {
2146-
optimize_with_bolt(&self.file, &self.profile, &output_path);
2147-
}
2148-
output_path
2149-
}
2150-
}
2151-
21522027
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
21532028
pub struct LlvmTools {
21542029
pub target: TargetSelection,
@@ -2390,8 +2265,8 @@ impl Step for ReproducibleArtifacts {
23902265
tarball.add_file(path, ".", 0o644);
23912266
added_anything = true;
23922267
}
2393-
if let Some(path) = builder.config.llvm_bolt_profile_use.as_ref() {
2394-
tarball.add_file(path, ".", 0o644);
2268+
for profile in &builder.config.reproducible_artifacts {
2269+
tarball.add_file(profile, ".", 0o644);
23952270
added_anything = true;
23962271
}
23972272
if added_anything { Some(tarball.generate()) } else { None }

Diff for: src/bootstrap/flags.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,9 @@ pub struct Flags {
149149
/// generate PGO profile with llvm built for rustc
150150
#[arg(global(true), long)]
151151
pub llvm_profile_generate: bool,
152-
/// generate BOLT profile for LLVM build
152+
/// Additional reproducible artifacts that should be added to the reproducible artifacts archive.
153153
#[arg(global(true), long)]
154-
pub llvm_bolt_profile_generate: bool,
155-
/// use BOLT profile for LLVM build
156-
#[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
157-
pub llvm_bolt_profile_use: Option<String>,
154+
pub reproducible_artifact: Vec<String>,
158155
#[arg(global(true))]
159156
/// paths for the subcommand
160157
pub paths: Vec<PathBuf>,

Diff for: src/bootstrap/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ use crate::util::{
3939
dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
4040
};
4141

42-
mod bolt;
4342
mod builder;
4443
mod cache;
4544
mod cc_detect;

Diff for: src/bootstrap/llvm.rs

-6
Original file line numberDiff line numberDiff line change
@@ -342,12 +342,6 @@ impl Step for Llvm {
342342
if let Some(path) = builder.config.llvm_profile_use.as_ref() {
343343
cfg.define("LLVM_PROFDATA_FILE", &path);
344344
}
345-
if builder.config.llvm_bolt_profile_generate
346-
|| builder.config.llvm_bolt_profile_use.is_some()
347-
{
348-
// Relocations are required for BOLT to work.
349-
ldflags.push_all("-Wl,-q");
350-
}
351345

352346
// Disable zstd to avoid a dependency on libzstd.so.
353347
cfg.define("LLVM_ENABLE_ZSTD", "OFF");

0 commit comments

Comments
 (0)