• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Profile-guided Optimization
2
3`rustc` supports doing profile-guided optimization (PGO).
4This chapter describes what PGO is, what it is good for, and how it can be used.
5
6## What Is Profiled-Guided Optimization?
7
8The basic concept of PGO is to collect data about the typical execution of
9a program (e.g. which branches it is likely to take) and then use this data
10to inform optimizations such as inlining, machine-code layout,
11register allocation, etc.
12
13There are different ways of collecting data about a program's execution.
14One is to run the program inside a profiler (such as `perf`) and another
15is to create an instrumented binary, that is, a binary that has data
16collection built into it, and run that.
17The latter usually provides more accurate data and it is also what is
18supported by `rustc`.
19
20## Usage
21
22Generating a PGO-optimized program involves following a workflow with four steps:
23
241. Compile the program with instrumentation enabled
25   (e.g. `rustc -Cprofile-generate=/tmp/pgo-data main.rs`)
262. Run the instrumented program (e.g. `./main`) which generates a
27   `default_<id>.profraw` file
283. Convert the `.profraw` file into a `.profdata` file using
29   LLVM's `llvm-profdata` tool
304. Compile the program again, this time making use of the profiling data
31   (for example `rustc -Cprofile-use=merged.profdata main.rs`)
32
33An instrumented program will create one or more `.profraw` files, one for each
34instrumented binary. E.g. an instrumented executable that loads two instrumented
35dynamic libraries at runtime will generate three `.profraw` files. Running an
36instrumented binary multiple times, on the other hand, will re-use the
37respective `.profraw` files, updating them in place.
38
39These `.profraw` files have to be post-processed before they can be fed back
40into the compiler. This is done by the `llvm-profdata` tool. This tool
41is most easily installed via
42
43```bash
44rustup component add llvm-tools-preview
45```
46
47Note that installing the `llvm-tools-preview` component won't add
48`llvm-profdata` to the `PATH`. Rather, the tool can be found in:
49
50```bash
51~/.rustup/toolchains/<toolchain>/lib/rustlib/<target-triple>/bin/
52```
53
54Alternatively, an `llvm-profdata` coming with a recent LLVM or Clang
55version usually works too.
56
57The `llvm-profdata` tool merges multiple `.profraw` files into a single
58`.profdata` file that can then be fed back into the compiler via
59`-Cprofile-use`:
60
61```bash
62# STEP 1: Compile the binary with instrumentation
63rustc -Cprofile-generate=/tmp/pgo-data -O ./main.rs
64
65# STEP 2: Run the binary a few times, maybe with common sets of args.
66#         Each run will create or update `.profraw` files in /tmp/pgo-data
67./main mydata1.csv
68./main mydata2.csv
69./main mydata3.csv
70
71# STEP 3: Merge and post-process all the `.profraw` files in /tmp/pgo-data
72llvm-profdata merge -o ./merged.profdata /tmp/pgo-data
73
74# STEP 4: Use the merged `.profdata` file during optimization. All `rustc`
75#         flags have to be the same.
76rustc -Cprofile-use=./merged.profdata -O ./main.rs
77```
78
79### A Complete Cargo Workflow
80
81Using this feature with Cargo works very similar to using it with `rustc`
82directly. Again, we generate an instrumented binary, run it to produce data,
83merge the data, and feed it back into the compiler. Some things of note:
84
85- We use the `RUSTFLAGS` environment variable in order to pass the PGO compiler
86  flags to the compilation of all crates in the program.
87
88- We pass the `--target` flag to Cargo, which prevents the `RUSTFLAGS`
89  arguments to be passed to Cargo build scripts. We don't want the build
90  scripts to generate a bunch of `.profraw` files.
91
92- We pass `--release` to Cargo because that's where PGO makes the most sense.
93  In theory, PGO can also be done on debug builds but there is little reason
94  to do so.
95
96- It is recommended to use *absolute paths* for the argument of
97  `-Cprofile-generate` and `-Cprofile-use`. Cargo can invoke `rustc` with
98  varying working directories, meaning that `rustc` will not be able to find
99  the supplied `.profdata` file. With absolute paths this is not an issue.
100
101- It is good practice to make sure that there is no left-over profiling data
102  from previous compilation sessions. Just deleting the directory is a simple
103  way of doing so (see `STEP 0` below).
104
105This is what the entire workflow looks like:
106
107```bash
108# STEP 0: Make sure there is no left-over profiling data from previous runs
109rm -rf /tmp/pgo-data
110
111# STEP 1: Build the instrumented binaries
112RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data" \
113    cargo build --release --target=x86_64-unknown-linux-gnu
114
115# STEP 2: Run the instrumented binaries with some typical data
116./target/x86_64-unknown-linux-gnu/release/myprogram mydata1.csv
117./target/x86_64-unknown-linux-gnu/release/myprogram mydata2.csv
118./target/x86_64-unknown-linux-gnu/release/myprogram mydata3.csv
119
120# STEP 3: Merge the `.profraw` files into a `.profdata` file
121llvm-profdata merge -o /tmp/pgo-data/merged.profdata /tmp/pgo-data
122
123# STEP 4: Use the `.profdata` file for guiding optimizations
124RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
125    cargo build --release --target=x86_64-unknown-linux-gnu
126```
127
128### Troubleshooting
129
130- It is recommended to pass `-Cllvm-args=-pgo-warn-missing-function` during the
131  `-Cprofile-use` phase. LLVM by default does not warn if it cannot find
132  profiling data for a given function. Enabling this warning will make it
133  easier to spot errors in your setup.
134
135- There is a [known issue](https://github.com/rust-lang/cargo/issues/7416) in
136  Cargo prior to version 1.39 that will prevent PGO from working correctly. Be
137  sure to use Cargo 1.39 or newer when doing PGO.
138
139## Further Reading
140
141`rustc`'s PGO support relies entirely on LLVM's implementation of the feature
142and is equivalent to what Clang offers via the `-fprofile-generate` /
143`-fprofile-use` flags. The [Profile Guided Optimization][clang-pgo] section
144in Clang's documentation is therefore an interesting read for anyone who wants
145to use PGO with Rust.
146
147[clang-pgo]: https://clang.llvm.org/docs/UsersManual.html#profile-guided-optimization
148