summaryrefslogtreecommitdiffstats
path: root/src/bootstrap/bolt.rs
blob: ea37cd47049bfcedf454fa976b13f6537980c6e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use std::path::Path;
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) {
    let dir = std::env::temp_dir();
    let instrumented_path = dir.join("instrumented.so");

    let status = Command::new("llvm-bolt")
        .arg("-instrument")
        .arg(&path)
        // Make sure that each process will write its profiles into a separate file
        .arg("--instrumentation-file-append-pid")
        .arg("-o")
        .arg(&instrumented_path)
        .status()
        .expect("Could not instrument artifact using BOLT");

    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");
}

/// Uses the `llvm-bolt` binary to optimize the binary/library at the given `path` with BOLT,
/// using merged profiles from `profile_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) {
    let dir = std::env::temp_dir();
    let optimized_path = dir.join("optimized.so");

    let status = Command::new("llvm-bolt")
        .arg(&path)
        .arg("-data")
        .arg(&profile_path)
        .arg("-o")
        .arg(&optimized_path)
        // Reorder basic blocks within functions
        .arg("-reorder-blocks=ext-tsp")
        // Reorder functions within the binary
        .arg("-reorder-functions=hfsort+")
        // Split function code into hot and code regions
        .arg("-split-functions=2")
        // Split as many basic blocks as possible
        .arg("-split-all-cold")
        // Move jump tables to a separate section
        .arg("-jump-tables=move")
        // Use GNU_STACK program header for new segment (workaround for issues with strip/objcopy)
        .arg("-use-gnu-stack")
        // Fold functions with identical code
        .arg("-icf=1")
        // Update DWARF debug info in the final binary
        .arg("-update-debug-sections")
        // Print optimization statistics
        .arg("-dyno-stats")
        .status()
        .expect("Could not optimize artifact using BOLT");

    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");
}