Skip to content

Commit c5d65aa

Browse files
committed
Apply BOLT optimizations without rebuilding LLVM
1 parent 276b75a commit c5d65aa

File tree

4 files changed

+32
-36
lines changed

4 files changed

+32
-36
lines changed

src/bootstrap/bolt.rs

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
use std::path::Path;
1+
use std::path::{Path, PathBuf};
22
use std::process::Command;
33

44
/// Uses the `llvm-bolt` binary to instrument the binary/library at the given `path` with BOLT.
55
/// When the instrumented artifact is executed, it will generate BOLT profiles into
66
/// `/tmp/prof.fdata.<pid>.fdata`.
7-
pub fn instrument_with_bolt_inplace(path: &Path) {
7+
/// Returns a path to the instrumented artifact, created in a temporary directory.
8+
pub fn instrument_with_bolt(path: &Path) -> PathBuf {
89
let dir = std::env::temp_dir();
9-
let instrumented_path = dir.join("instrumented.so");
10+
let instrumented_path = dir.join(path.file_name().unwrap());
1011

1112
let status = Command::new("llvm-bolt")
1213
.arg("-instrument")
@@ -21,19 +22,19 @@ pub fn instrument_with_bolt_inplace(path: &Path) {
2122
if !status.success() {
2223
panic!("Could not instrument {} with BOLT, exit code {:?}", path.display(), status.code());
2324
}
24-
25-
std::fs::copy(&instrumented_path, path).expect("Cannot copy instrumented artifact");
26-
std::fs::remove_file(instrumented_path).expect("Cannot delete instrumented artifact");
25+
instrumented_path
2726
}
2827

2928
/// Uses the `llvm-bolt` binary to optimize the binary/library at the given `path` with BOLT,
3029
/// using merged profiles from `profile_path`.
3130
///
3231
/// The recorded profiles have to be merged using the `merge-fdata` tool from LLVM and the merged
3332
/// profile path should be then passed to this function.
34-
pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) {
33+
///
34+
/// Returns a path to the optimized artifact, created in a temporary directory.
35+
pub fn optimize_with_bolt(path: &Path, profile_path: &Path) -> PathBuf {
3536
let dir = std::env::temp_dir();
36-
let optimized_path = dir.join("optimized.so");
37+
let optimized_path = dir.join(path.file_name().unwrap());
3738

3839
let status = Command::new("llvm-bolt")
3940
.arg(&path)
@@ -65,7 +66,5 @@ pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) {
6566
if !status.success() {
6667
panic!("Could not optimize {} with BOLT, exit code {:?}", path.display(), status.code());
6768
}
68-
69-
std::fs::copy(&optimized_path, path).expect("Cannot copy optimized artifact");
70-
std::fs::remove_file(optimized_path).expect("Cannot delete optimized artifact");
69+
optimized_path
7170
}

src/bootstrap/dist.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::process::Command;
1919
use object::read::archive::ArchiveFile;
2020
use object::BinaryFormat;
2121

22+
use crate::bolt::{instrument_with_bolt, optimize_with_bolt};
2223
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
2324
use crate::cache::{Interned, INTERNER};
2425
use crate::channel;
@@ -1904,6 +1905,26 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
19041905
}
19051906
}
19061907

1908+
fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
1909+
if source.as_os_str().is_empty() {
1910+
return;
1911+
}
1912+
1913+
// After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
1914+
// This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
1915+
// We perform the instrumentation/optimization here, on the fly, just before they are being
1916+
// packaged into some destination directory.
1917+
let postprocessed = if builder.config.llvm_bolt_profile_generate {
1918+
instrument_with_bolt(source)
1919+
} else if let Some(path) = &builder.config.llvm_bolt_profile_use {
1920+
optimize_with_bolt(source, &Path::new(&path))
1921+
} else {
1922+
source.to_path_buf()
1923+
};
1924+
1925+
builder.install(&postprocessed, destination, 0o644);
1926+
}
1927+
19071928
/// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
19081929
///
19091930
/// Returns whether the files were actually copied.
@@ -1955,7 +1976,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
19551976
} else {
19561977
PathBuf::from(file)
19571978
};
1958-
builder.install(&file, dst_libdir, 0o644);
1979+
install_llvm_file(builder, &file, dst_libdir);
19591980
}
19601981
!builder.config.dry_run()
19611982
} else {

src/bootstrap/native.rs

-23
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use std::io;
1616
use std::path::{Path, PathBuf};
1717
use std::process::Command;
1818

19-
use crate::bolt::{instrument_with_bolt_inplace, optimize_library_with_bolt_inplace};
2019
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
2120
use crate::channel;
2221
use crate::config::{Config, TargetSelection};
@@ -523,34 +522,12 @@ impl Step for Llvm {
523522
}
524523
}
525524

526-
// After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file
527-
// in place. This is fine, because currently we do not support incrementally rebuilding
528-
// LLVM after a configuration change, so to rebuild it the build files have to be removed,
529-
// which will also remove these modified files.
530-
if builder.config.llvm_bolt_profile_generate {
531-
instrument_with_bolt_inplace(&get_built_llvm_lib_path(&res.llvm_config));
532-
}
533-
if let Some(path) = &builder.config.llvm_bolt_profile_use {
534-
optimize_library_with_bolt_inplace(
535-
&get_built_llvm_lib_path(&res.llvm_config),
536-
&Path::new(path),
537-
);
538-
}
539-
540525
t!(stamp.write());
541526

542527
res
543528
}
544529
}
545530

546-
/// Returns path to a built LLVM library (libLLVM.so).
547-
/// Assumes that we have built LLVM into a single library file.
548-
fn get_built_llvm_lib_path(llvm_config_path: &Path) -> PathBuf {
549-
let mut cmd = Command::new(llvm_config_path);
550-
cmd.arg("--libfiles");
551-
PathBuf::from(output(&mut cmd).trim())
552-
}
553-
554531
fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
555532
if !builder.config.llvm_version_check {
556533
return;

src/ci/stage-build.py

-1
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,6 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L
805805
gather_llvm_bolt_profiles(pipeline)
806806

807807
print_free_disk_space(pipeline)
808-
clear_llvm_files(pipeline)
809808
final_build_args += [
810809
"--llvm-bolt-profile-use",
811810
pipeline.llvm_bolt_profile_merged_file()

0 commit comments

Comments
 (0)