发布时间:2020年7月15日 - 3分钟阅读
由软件工程师Pirama Arumuga Nainar发布。
Profile-guided optimization(PGO)是一种著名的编译器优化技术。在PGO中,编译器使用程序执行的运行时配置文件来对内联和代码布局做出最佳选择。这将导致性能的提高和代码大小的减少。开发者现在可以利用谷歌的工具包轻松部署PGO工具,并改进他们的原生Android应用。
在选定的Android系统组件上,启用PGO可将性能提高6-8%。PGO还在一个组件中提供了代码大小的改进,同时略微增加了另外两个组件的代码大小。
安卓系统组件PGO的优势
PGO可以通过以下步骤部署到您的应用程序或库中。
- 确定一个有代表性的工作负载。
- 收集配置文件。
- 在 Release build 中使用配置文件。
步骤1:确定一个有代表性的工作负载
首先,为您的应用程序确定一个代表性的基准或工作负载。这是关键的一步,因为从工作负载中收集的配置文件可以确定代码中的冷热区域。在使用配置文件时,编译器将在热区执行积极的优化和内联。编译器还可以选择减少冷区的代码大小,同时牺牲性能。
识别一个好的工作负载也有利于跟踪一般的性能。
第二步:收集配置文件
通过在应用程序的工具化构建中运行步骤1中的工作负载来收集配置文件。要生成工具化的构建,请在编译器和链接器标志中添加 -fprofile-generate。这个标志应该由一个单独的构建变量来控制,因为在默认构建中不需要这个标志。
当运行工具化的二进制文件时,配置文件会被收集,并在退出时被写入文件。然而,在Android应用中,用atexit注册的函数不会被调用--应用只会被杀死。应用程序/工作负载必须通过调用 __llvm_profile_write_file 函数来显式触发配置文件的写入。
extern int __llvm_profile_write_file(void);
void workload() {
// ...
// run workload
// ...
// write profiles at exit.
__llvm_profile_write_file();
return;
}
工作负载结束时触发配置文件写入的例子
如果工作负载是独立的二进制文件,编写配置文件就更简单了--只需在运行二进制文件之前设置 LLVM_PROFILE_FILE 环境变量。
配置文件的格式为.profraw。使用NDK中的llvm-profdata工具将.profraw转换为.profdata,然后可以将其传递给编译器。
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
merge --output=pgo_profile.profdata \
<list-of-profraw-files>
将.profraw文件转换为.profdata的命令。
使用同一NDK版本的llvm-profdata和clang来避免配置文件文件格式的版本不匹配。
步骤3 使用配置文件来构建应用程序
通过向编译器和链接器传递-fprofile-use=<>.profdata,在应用程序的发布构建过程中使用上一步的配置文件。即使在代码演变的过程中,配置文件也可以被使用--Clang编译器可以容忍源代码和配置文件之间的轻微不匹配。
案例分析
"dex2oat"是安卓系统的片上AOT编译器。为了获得dex2oat的代表性工作负载,我们随机选取了Play商店中安装量最大的100个应用中的25个。我们还随机生成了 dex2oat 的编译选项
。
为了生成PGO配置文件,我们构建了一个挂载PGO的dex2oat二进制文件,并使用它来编译工作负载。然后,我们生成了使用这些 PGO 配置文件的 dex2oat 版本,并评估了 100 个安装量最大的应用程序中剩余 75 个的性能提升。
我们利用 Android 团队可用的测试基础架构来自动收集这些 PGO 配置文件,以便它们能够轻松地保持更新。
结论
PGO是一种非常有用的性能优化技术。在对工作负载进行初始设置并将其集成到构建过程中后,它能以最小的维护量带来令人印象深刻的性能提升。
以下是一些其他主题,可以帮助提高Android应用的性能。
- 链接时间优化:LTO+PGO比各自单独使用更好。
- Java应用的云配置文件
通过www.DeepL.com/Translator(免费版)翻译