プロファイル品質の追跡

Native Image で PGO を使用する際の最も難しいステップは、関連するワークロードのプロファイルを収集することです。ソースコードは進化するため、アプリケーションが時間的に静的なことはほとんどありません。「インストルメント化されたイメージのビルド」、「プロファイルの収集」、「最適化されたイメージのビルド」というステップをソースコードの変更ごとに行うことは、非常に時間がかかる場合があります。このドキュメントでは、「アプリケーションのソースコードが時間とともに変化した場合、既存のプロファイルをどれくらいの期間使用し続けることができますか?」という質問にいくつかの回答を示します。

アプローチ 1: プロファイルを無期限に再利用する #

最適化されたアプリケーションをビルドする場合、Native Image は与えられたプロファイルでできる限り最善を尽くすことを目指します。つまり、アプリケーションの古いプロファイル (または完全に異なるアプリケーションのプロファイル) を提供しても、Native Image がネイティブ実行可能ファイルを生成するのを妨げることはありません。

注: 不正確なプロファイルは、プロファイルがない場合よりもパフォーマンスが悪化する可能性があります。これは、不正確なプロファイルがコンパイラをアプリケーションの誤った要素に最適化リソースを費やさせ、重要な要素を優先順位を下げる可能性があるためです。

とはいえ、進化するアプリケーションに対して 1 つのプロファイルを無期限に再利用すると、遅かれ早かれ逆効果になります。

アプローチ 2: 定期的にプロファイルを収集する #

アプリケーションは定期的に変更される可能性があるため、定期的に新しいプロファイルを収集するのが理にかなっています。これを実現する方法の 1 つは、master ブランチの先端を使用してアプリケーションのインストルメント化されたバージョンをビルドし、ワークロードを実行してプロファイルを収集し、結果の *iprof* ファイルを、他の最適化ビルドがダウンロードできる FTP サーバーにアップロードする、毎日の Linux cron ジョブです。これにより、ビルド中のアプリケーションバージョンと使用中のプロファイルの差が、固定時間間隔 (この例では 24 時間) を超えないようにします。

ただし、定期的にプロファイルを収集すると計算時間が長くなるため、アプリケーションが変更される頻度とバランスを取る必要があります。アプリケーションが比較的安定しており、ソースコードの変更が少ない場合は、再プロファイリングの頻度を少なくしても問題ありません。留意すべき点は次のとおりです。

  • 古いプロファイルでアプリケーションをビルドしないように、プロファイリングのスケジュールをアプリケーション リリースのスケジュールと合わせます。
  • 理想的には、実稼働ワークロードを再現可能なワークロードに変換し、ビルドの一部としてプロファイルを収集してから、常に最新のプロファイルを使用して最適化されたネイティブ実行可能ファイルを作成します。

そうすることで、ワークロードが後で実稼働で実行されるアプリケーションと同じ部分を実行する限り、古いプロファイルや不整合なプロファイルを持つリスクがなくなります。

アプローチ 3: 時間の経過に伴うプロファイル品質メトリクスを追跡する #

プロファイルの品質をより深く理解するために、Native Image は最適化された実行可能ファイルをビルドするときに要求できる 2 つのメトリクス、*プロファイル関連性*と*プロファイル適用性*を提供します。これらのメトリクスは、プロファイルと最適化された実行可能ファイルに表示されるメソッドとクラスとの関係を反映しています。

ビルド (同じプロファイルを使用) 間でこれらの 2 つのメトリクスの値が変化する場合は、それらのビルド内のクラスおよび/またはメソッドのセットも変化したことを示します (プロファイルが収集された時点と現在のビルドの間)。

プロファイル品質メトリクスを取得する方法 #

プロファイル品質メトリクスを計算して印刷するには、最適化されたネイティブ実行可能ファイルをビルドするときに `H:+PGOPrintProfileQuality` オプションを渡します。(このオプションは実験的です。)

プロファイルガイド最適化の基本的な使用法 で紹介した Game Of Life サンプルアプリケーションを検討してみましょう

native-image -cp . GameOfLife -o gameoflife-pgo --pgo=gameoflife.iprof -H:+PGOPrintProfileQuality

ビルド出力のフェーズ 5 で、プロファイルの適用性とプロファイル関連性に関する追加の行が表示されるはずです

GraalVM Native Image: Generating 'gameoflife-pgo' (executable)
...
[5/8] Inlining methods...     [***]                                                                      (0.4s @ 0.28GB)
Info: PGO: Profile applicability is 21.74%. Profile relevance is 72.71%.
...

これらのメトリクスの絶対値はあまり意味がなく、単独で考慮すべきではありません。前述のように、これらのメトリクスはプロファイルとアプリケーションのコードの関係を表しています。アプリケーションを変更してプロファイルを再利用すると、メトリクスの値に変化が見られるはずです。

たとえば、`applyRules ()` アプリケーションメソッドに単純な「メソッド名の変更」リファクタリングを適用します。プロファイルの観点から見ると、`applyRules ()` メソッドがアプリケーションのメソッドのセットから削除され、`applyGameRules` という名前の新しいメソッドが導入されました。同じプロファイルと変更されたアプリケーションで最適化されたビルドを再実行すると、次の出力が返されます

native-image -cp . GameOfLife -o gameoflife-pgo --pgo=gameoflife.iprof -H:+PGOPrintProfileQuality
========================================================================================================================
GraalVM Native Image: Generating 'gameoflife-pgo' (executable)...
...
[5/8] Inlining methods...     [***]                                                                      (0.4s @ 0.28GB)
Info: PGO: Profile applicability is 21.67%. Profile relevance is 72.66%.                                                                  (6.8s @ 0.29GB)
...

最初のビルドでのプロファイルの適用性は 21.74% でしたが、現在は 21.67% になっていることを思い出してください。同様に、最初のビルドでのプロファイルの関連性は 72.71% でしたが、現在は 72.66% になっています。コードを少し変更しただけでメトリクスの値がわずかに変化し、プロファイルがわずかに古くなっている可能性があることを通知しています。

注: この例では、非常にホットなメソッドの名前を変更しました。この変更は、プロファイルがホットなメソッドに適用できないため、パフォーマンスの低下を引き起こす可能性があります。アプリケーションのコールドコードで行われた同様の変更は、これらのメトリクスの同様の低下をもたらしますが、これはパフォーマンスに影響を与えないはずです。これらのメトリクスは、提供されたプロファイルとアプリケーション内のメソッドのセットの関係を測るものであり、プロファイル、アプリケーションのソースコード、または依存関係の変更が与える可能性のあるパフォーマンスへの影響を測定または予測するものではないことに注意してください。これらの数値は、単一のビルドで観察した場合もほとんど意味がないか、ほとんど役に立ちません。その有用性は、ビルド間でプロファイルを再利用したり、アプリケーションの同じビルドに異なるプロファイルを提供したりするときにメトリクスの変化を観察することから生まれます。

プロファイル品質メトリクス: *適用性* #

適用性メトリクスは、「このプロファイルはアプリケーションのメソッドにどの程度適用できるか?」という質問に答えます。アプリケーション内の個々のメソッドのコンパイル中に、コード内のプロファイルを必要とする場所 N の数と、プロファイルが利用可能であった回数 S が追跡されます。プロファイルの適用性メトリクスは、割合 `S / N` をパーセントで表したものです。

つまり、アプリケーションに新しいコードを追加する (プロファイルには追加しない) と、プロファイルの適用性が低下するはずです。これは、コードが増えるほどプロファイルの要求が増え、プロファイルが *適用できる* 回数 (S) が、プロファイルの要求の総数 (N) で除算されるためです。

注: プロファイルの適用性が 100% であると期待するのは間違いです。優れたワークロードでは、ほとんどすべての場合において、アプリケーションのホットな部分とコールドな部分を区別し、コードのコールドな部分の一部を実行しません。このため、プロファイルにはアプリケーションのコールドな部分 (たとえば、例外ハンドラー) のエントリが含まれず、これは実際のワークロードではめったに実行されません。適用率が 100% ということは、イメージ内のコードのすべての部分が完全にプロファイリングされていることを意味しますが、実際にはほとんどの場合そうではありません。

プロファイル品質メトリクス: *関連性* #

関連性メトリクスは、「プロファイルの内容はアプリケーションメソッドとどの程度一致するか?」という質問に答えることを目指しています。プロファイルをロードすると、そのすべてのデータがアプリケーションメソッドのセットと照合され、それらのメソッドと一致しないすべてのエントリがドロップされます。たとえば、クラスからメソッドを削除しても、そのメソッドのエントリがまだあるプロファイルを使用した場合、それらのすべてのエントリはプロファイルのロード中にドロップされます。プロファイルの関連性は、ロード中に*ドロップされなかった*データの割合です。

つまり、アプリケーションからコードを削除する (プロファイルから削除しない) と、プロファイルの関連性が低下するはずです。これは、新しいアプリケーションバージョンに関連するプロファイル内のデータのパーセントが減少するためです。一方、アプリケーションに新しいコード (たとえば、新しいクラスや依存関係) を追加しても、プロファイルから削除する必要があるデータ量は変化しないため、このメトリクスには影響しません。

注意: プロファイル収集に使用したアプリケーションと全く同じアプリケーションの最適化バイナリをビルドしても、プロファイルの関連性が100%になると期待するのは誤りです。これは、インストルメント化されたバイナリと最適化されたバイナリでは、微妙な点でメソッドが異なるためです。たとえば、インストルメント化されたバイナリには、プロファイルデータを収集するためのコードと、そのデータをファイルにシリアライズするためのコードが含まれています。このコードは不要であるため、最適化されたバイナリには存在しません。「Game Of Life」の例を見ると、関連性が約70%であるのは、主にアプリケーションが非常に小さい(120行未満の単一のJavaクラス)ためです。そのため、インストルメント化されたバイナリと最適化されたバイナリのメソッドセットの違いが誇張されています。より大きな実際のアプリケーションでは、この割合は通常大きくなりますが、100%ではありません。

さらに詳しく #

お問い合わせ