|
| 1 | +use std::path::Path; |
| 2 | +use std::process::Command; |
| 3 | + |
| 4 | +/// Uses the `llvm-bolt` binary to instrument the binary/library at the given `path` with BOLT. |
| 5 | +/// When the instrumented artifact is executed, it will generate BOLT profiles into |
| 6 | +/// `/tmp/prof.fdata.<pid>.fdata`. |
| 7 | +pub fn instrument_with_bolt_inplace(path: &Path) { |
| 8 | + let dir = std::env::temp_dir(); |
| 9 | + let instrumented_path = dir.join("instrumented.so"); |
| 10 | + |
| 11 | + let status = Command::new("llvm-bolt") |
| 12 | + .arg("-instrument") |
| 13 | + .arg(&path) |
| 14 | + // Make sure that each process will write its profiles into a separate file |
| 15 | + .arg("--instrumentation-file-append-pid") |
| 16 | + .arg("-o") |
| 17 | + .arg(&instrumented_path) |
| 18 | + .status() |
| 19 | + .expect("Could not instrument artifact using BOLT"); |
| 20 | + |
| 21 | + if !status.success() { |
| 22 | + panic!("Could not instrument {} with BOLT, exit code {:?}", path.display(), status.code()); |
| 23 | + } |
| 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"); |
| 27 | +} |
| 28 | + |
| 29 | +/// Uses the `llvm-bolt` binary to optimize the binary/library at the given `path` with BOLT, |
| 30 | +/// using merged profiles from `profile_path`. |
| 31 | +/// |
| 32 | +/// The recorded profiles have to be merged using the `merge-fdata` tool from LLVM and the merged |
| 33 | +/// profile path should be then passed to this function. |
| 34 | +pub fn optimize_library_with_bolt_inplace(path: &Path, profile_path: &Path) { |
| 35 | + let dir = std::env::temp_dir(); |
| 36 | + let optimized_path = dir.join("optimized.so"); |
| 37 | + |
| 38 | + let status = Command::new("llvm-bolt") |
| 39 | + .arg(&path) |
| 40 | + .arg("-data") |
| 41 | + .arg(&profile_path) |
| 42 | + .arg("-o") |
| 43 | + .arg(&optimized_path) |
| 44 | + // Reorder basic blocks within functions |
| 45 | + .arg("-reorder-blocks=ext-tsp") |
| 46 | + // Reorder functions within the binary |
| 47 | + .arg("-reorder-functions=hfsort+") |
| 48 | + // Split function code into hot and code regions |
| 49 | + .arg("-split-functions=2") |
| 50 | + // Split as many basic blocks as possible |
| 51 | + .arg("-split-all-cold") |
| 52 | + // Move jump tables to a separate section |
| 53 | + .arg("-jump-tables=move") |
| 54 | + // Use GNU_STACK program header for new segment (workaround for issues with strip/objcopy) |
| 55 | + .arg("-use-gnu-stack") |
| 56 | + // Fold functions with identical code |
| 57 | + .arg("-icf=1") |
| 58 | + // Update DWARF debug info in the final binary |
| 59 | + .arg("-update-debug-sections") |
| 60 | + // Print optimization statistics |
| 61 | + .arg("-dyno-stats") |
| 62 | + .status() |
| 63 | + .expect("Could not optimize artifact using BOLT"); |
| 64 | + |
| 65 | + if !status.success() { |
| 66 | + panic!("Could not optimize {} with BOLT, exit code {:?}", path.display(), status.code()); |
| 67 | + } |
| 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"); |
| 71 | +} |
0 commit comments