PGO(Profile-Guided Optimization)1はコンパイラにおけるフィードバック最適化の一つです。コードの実行時プロファイルをコンパイラにフィードバックして、リコンパイルすることで、より効果的な最適化ができるというものになります。
LLVMでは手法の異なるPGOが複数あるようです。この記事では、インストルメントを利用したPGOについて、特性を簡単に纏めてみます。記載する情報の多くは"The many faces of LLVM PGO and FDO"2を参考にしています。
インストルメントを利用したPGOの手順
インストルメントはコンパイルにおいて、実行バイナリの各ブロックに計測モジュールを埋め込むことで、実行プロファイルを取得するものです。
PGOでは以下のステップで最適化を行います。
- インストルメントオプションを付けてソースをコンパイル
- コンパイルした実行バイナリを実行(プロファイルが生成)
- コンパイラにプロファイルを読み込ませて再度ソースをコンパイル
ここで、1, 3で指定するオプションにより、インストルメントを埋め込むフェーズや、適用されるPGO最適化が異なります。
Clang Front-end PGO
1のオプション: -fprofile-instr-generate
3のオプション: -fprofile-instr-use
Clangのフロントエンドで、ソースコードレベルでインストルメントが挿入されます。このインストルメントにより取得されたプロファイルは、デバック行情報を利用してコードへマッピングされることになります。このレベルでの情報(プロファイル)は、後続の最適化の影響(インライン化、アンロール、テール複製、CFGの簡略化など)を考慮できないため、プロファイルの精度損失が大きくなります。
IR PGO
1のオプション: -fprofile-generate
3のオプション: -fprofile-use
LLVM IRレベルでインストルメントが挿入されます。コンパイルの後半で挿入されるため、プロファイルの精度は落ちにくいという特徴があります。具体的には初期のインライン化のあとに行われるようです3。
CSIR PGO
1のオプション: -fcs-profile-generate
3のオプション: -fprofile-use
CSIR PGOのインストルメント挿入はIR PGOよりもさらに後段で行われます。具体的にはインライン化のあとのようです。これにより、プロファイルが複製コードの情報を持つことができるようになり、精度が向上します。CSIR PGOはIR PGOと併用することができるようです。4