about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
authorJakub Beránek <berykubik@gmail.com>2023-02-04 00:03:12 +0100
committerJakub Beránek <berykubik@gmail.com>2023-03-04 16:37:40 +0100
commitc5d65aa58043cc1eac76838319009fce9de1b019 (patch)
tree0ce6d0c12717c64326ce83a13559bf6a587b9876 /src/bootstrap
parent276b75a843af8822ffe4e395266d9445679a57a4 (diff)
Apply BOLT optimizations without rebuilding LLVM
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/bolt.rs21
-rw-r--r--src/bootstrap/dist.rs23
-rw-r--r--src/bootstrap/native.rs23
3 files changed, 32 insertions, 35 deletions
diff --git a/src/bootstrap/bolt.rs b/src/bootstrap/bolt.rs
index ea37cd47049..d424852b845 100644
--- a/src/bootstrap/bolt.rs
+++ b/src/bootstrap/bolt.rs
@@ -1,12 +1,13 @@
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 
 /// Uses the `llvm-bolt` binary to instrument the binary/library at the given `path` with BOLT.
 /// When the instrumented artifact is executed, it will generate BOLT profiles into
 /// `/tmp/prof.fdata.<pid>.fdata`.
-pub fn instrument_with_bolt_inplace(path: &Path) {
+/// Returns a path to the instrumented artifact, created in a temporary directory.
+pub fn instrument_with_bolt(path: &Path) -> PathBuf {
     let dir = std::env::temp_dir();
-    let instrumented_path = dir.join("instrumented.so");
+    let instrumented_path = dir.join(path.file_name().unwrap());
 
     let status = Command::new("llvm-bolt")
         .arg("-instrument")
@@ -21,9 +22,7 @@ pub fn instrument_with_bolt_inplace(path: &Path) {
     if !status.success() {
         panic!("Could not instrument {} with BOLT, exit code {:?}", path.display(), status.code());
     }
-
-    std::fs::copy(&instrumented_path, path).expect("Cannot copy instrumented artifact");
-    std::fs::remove_file(instrumented_path).expect("Cannot delete instrumented artifact");
+    instrumented_path
 }
 
 /// Uses the `llvm-bolt` binary to optimize the binary/library at the given `path` with BOLT,
@@ -31,9 +30,11 @@ pub fn instrument_with_bolt_inplace(path: &Path) {
 ///
 /// The recorded profiles have to be merged using the `merge-fdata` tool from LLVM and the merged
 /// profile path should be then passed to this function.
-pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) {
+///
+/// Returns a path to the optimized artifact, created in a temporary directory.
+pub fn optimize_with_bolt(path: &Path, profile_path: &Path) -> PathBuf {
     let dir = std::env::temp_dir();
-    let optimized_path = dir.join("optimized.so");
+    let optimized_path = dir.join(path.file_name().unwrap());
 
     let status = Command::new("llvm-bolt")
         .arg(&path)
@@ -65,7 +66,5 @@ pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) {
     if !status.success() {
         panic!("Could not optimize {} with BOLT, exit code {:?}", path.display(), status.code());
     }
-
-    std::fs::copy(&optimized_path, path).expect("Cannot copy optimized artifact");
-    std::fs::remove_file(optimized_path).expect("Cannot delete optimized artifact");
+    optimized_path
 }
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 9b2b549612d..f6f6f4cc8ea 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -19,6 +19,7 @@ use std::process::Command;
 use object::read::archive::ArchiveFile;
 use object::BinaryFormat;
 
+use crate::bolt::{instrument_with_bolt, optimize_with_bolt};
 use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::channel;
@@ -1904,6 +1905,26 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
     }
 }
 
+fn install_llvm_file(builder: &Builder<'_>, source: &Path, destination: &Path) {
+    if source.as_os_str().is_empty() {
+        return;
+    }
+
+    // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file.
+    // This is not done in-place so that the built LLVM files are not "tainted" with BOLT.
+    // We perform the instrumentation/optimization here, on the fly, just before they are being
+    // packaged into some destination directory.
+    let postprocessed = if builder.config.llvm_bolt_profile_generate {
+        instrument_with_bolt(source)
+    } else if let Some(path) = &builder.config.llvm_bolt_profile_use {
+        optimize_with_bolt(source, &Path::new(&path))
+    } else {
+        source.to_path_buf()
+    };
+
+    builder.install(&postprocessed, destination, 0o644);
+}
+
 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
 ///
 /// Returns whether the files were actually copied.
@@ -1955,7 +1976,7 @@ fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir
             } else {
                 PathBuf::from(file)
             };
-            builder.install(&file, dst_libdir, 0o644);
+            install_llvm_file(builder, &file, dst_libdir);
         }
         !builder.config.dry_run()
     } else {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 5987b641b39..8c2bece1e62 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -16,7 +16,6 @@ use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use crate::bolt::{instrument_with_bolt_inplace, optimize_library_with_bolt_inplace};
 use crate::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::channel;
 use crate::config::{Config, TargetSelection};
@@ -523,34 +522,12 @@ impl Step for Llvm {
             }
         }
 
-        // After LLVM is built, we modify (instrument or optimize) the libLLVM.so library file
-        // in place. This is fine, because currently we do not support incrementally rebuilding
-        // LLVM after a configuration change, so to rebuild it the build files have to be removed,
-        // which will also remove these modified files.
-        if builder.config.llvm_bolt_profile_generate {
-            instrument_with_bolt_inplace(&get_built_llvm_lib_path(&res.llvm_config));
-        }
-        if let Some(path) = &builder.config.llvm_bolt_profile_use {
-            optimize_library_with_bolt_inplace(
-                &get_built_llvm_lib_path(&res.llvm_config),
-                &Path::new(path),
-            );
-        }
-
         t!(stamp.write());
 
         res
     }
 }
 
-/// Returns path to a built LLVM library (libLLVM.so).
-/// Assumes that we have built LLVM into a single library file.
-fn get_built_llvm_lib_path(llvm_config_path: &Path) -> PathBuf {
-    let mut cmd = Command::new(llvm_config_path);
-    cmd.arg("--libfiles");
-    PathBuf::from(output(&mut cmd).trim())
-}
-
 fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     if !builder.config.llvm_version_check {
         return;