rustc 支持性能剖析引导优化(Profile-Guided Optimization,PGO)。本章介绍 PGO 是什么、适合做什么,以及如何使用。
什么是性能剖析引导优化?
PGO 的基本思路是收集程序典型执行过程的数据,例如程序更可能走哪些分支,再利用这些数据指导内联、机器码布局、寄存器分配等优化。
收集程序执行数据有不同方法。一种是在性能分析器(如 perf)中运行程序;另一种是创建插桩二进制文件,也就是把数据收集功能内置到二进制文件中,再运行它。后者通常能提供更准确的数据,也是此版本 rustc 文档介绍的方式。
使用方法
生成经 PGO 优化的程序,需要完成四个步骤:
- 启用插桩编译程序,例如
rustc -Cprofile-generate=/tmp/pgo-data main.rs。 - 运行插桩后的程序,例如
./main,生成default_<id>.profraw文件。 - 使用 LLVM 的
llvm-profdata工具,把.profraw文件转换为.profdata文件。 - 再次编译程序,这次利用性能剖析数据,例如
rustc -Cprofile-use=merged.profdata main.rs。
插桩程序会生成一个或多个 .profraw 文件,每个插桩二进制文件对应一个。例如,插桩后的可执行文件在运行时加载两个同样插桩后的动态库,就会生成三个 .profraw 文件。另一方面,多次运行同一个插桩二进制文件时,会复用各自的 .profraw 文件,并原地更新它们。
这些 .profraw 文件必须经过后处理,才能交回编译器。这项工作由 llvm-profdata 完成。最方便的安装方式是:
rustup component add llvm-tools-preview
注意,安装 llvm-tools-preview 组件不会把 llvm-profdata 加入 PATH。工具位于:
~/.rustup/toolchains/<toolchain>/lib/rustlib/<target-triple>/bin/
也可以使用较新版本 LLVM 或 Clang 附带的 llvm-profdata,通常也能工作。
llvm-profdata 会把多个 .profraw 文件合并成一个 .profdata 文件,之后通过 -Cprofile-use 交给编译器:
# STEP 1: Compile the binary with instrumentation
rustc -Cprofile-generate=/tmp/pgo-data -O ./main.rs
# STEP 2: Run the binary a few times, maybe with common sets of args.
# Each run will create or update `.profraw` files in /tmp/pgo-data
./main mydata1.csv
./main mydata2.csv
./main mydata3.csv
# STEP 3: Merge and post-process all the `.profraw` files in /tmp/pgo-data
llvm-profdata merge -o ./merged.profdata /tmp/pgo-data
# STEP 4: Use the merged `.profdata` file during optimization. All `rustc`
# flags have to be the same.
rustc -Cprofile-use=./merged.profdata -O ./main.rs
完整的 Cargo 工作流
通过 Cargo 使用这一功能,与直接使用 rustc 很相似。同样是生成插桩二进制文件、运行并收集数据、合并数据,再交回编译器。需要注意以下几点:
- 使用环境变量
RUSTFLAGS,把 PGO 编译选项传给程序中所有 crate 的编译过程。 - 给 Cargo 传入
--target,避免把RUSTFLAGS中的参数传给 Cargo 的构建脚本。构建脚本不应该生成大量.profraw文件。 - 使用
--release,因为 PGO 最适合用于发布构建。理论上调试构建也能使用 PGO,但通常没有必要。 - 建议为
-Cprofile-generate和-Cprofile-use的参数使用绝对路径。Cargo 调用rustc时可能使用不同的工作目录,导致找不到给定的.profdata文件;绝对路径可以避免这一问题。 - 最好确保没有上次编译留下的剖析数据。删除对应目录是一种简单方法,见下面的 STEP 0。
整个工作流如下:
# STEP 0: Make sure there is no left-over profiling data from previous runs
rm -rf /tmp/pgo-data
# STEP 1: Build the instrumented binaries
RUSTFLAGS="-Cprofile-generate=/tmp/pgo-data" \
cargo build --release --target=x86_64-unknown-linux-gnu
# STEP 2: Run the instrumented binaries with some typical data
./target/x86_64-unknown-linux-gnu/release/myprogram mydata1.csv
./target/x86_64-unknown-linux-gnu/release/myprogram mydata2.csv
./target/x86_64-unknown-linux-gnu/release/myprogram mydata3.csv
# STEP 3: Merge the `.profraw` files into a `.profdata` file
llvm-profdata merge -o /tmp/pgo-data/merged.profdata /tmp/pgo-data
# STEP 4: Use the `.profdata` file for guiding optimizations
RUSTFLAGS="-Cprofile-use=/tmp/pgo-data/merged.profdata" \
cargo build --release --target=x86_64-unknown-linux-gnu
这里的命令面向 Linux 的 x86_64-unknown-linux-gnu 目标。执行清理步骤前应确认 /tmp/pgo-data 确实是专用剖析数据目录;程序名和训练数据文件应替换为项目实际内容。以上命令保留自原文,本稿未在该目标环境运行。
排查问题
- 建议在
-Cprofile-use阶段传入-Cllvm-args=-pgo-warn-missing-function。LLVM 默认不会在某个函数缺少剖析数据时发出警告;开启该警告有助于发现配置错误。 - Cargo 1.39 之前有一个会影响 PGO 正常工作的已知问题。使用 PGO 时应选择 Cargo 1.39 或更新版本。
延伸阅读
rustc 的 PGO 支持完全依赖 LLVM 对该功能的实现,相当于 Clang 的 -fprofile-generate / -fprofile-use 选项。想在 Rust 中使用 PGO,可以继续阅读 Clang 文档的 Profile Guided Optimization 一节。
社区维护的工具
除了直接通过编译器使用 PGO,也可以选择 cargo-pgo。它提供直观的命令行接口,省去手工完成整个流程的工作。详见 cargo-pgo 仓库。
为完整起见,下面列出使用 cargo-pgo 的对应步骤:
# Install if you haven't already
cargo install cargo-pgo
cargo pgo build
cargo pgo optimize
这些步骤会像前面一样:
- 从源代码构建插桩二进制文件。
- 运行插桩二进制文件,收集 PGO 剖析数据。
- 利用上一步收集的数据构建优化后的二进制文件。
来源:Profile-guided Optimization – The rustc book。原文作者:The Rust Project Contributors。许可:MIT。中文内容和版式作了调整。
MIT 许可全文
Copyright (c) The Rust Project Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.











暂无评论内容