GPU プロファイリング

ゲームの GPU 需要を最適化する方法です。

Windows
MacOS
Linux

GPU では多くのユニットが平行して動いており、フレームの異なるシーケンスに対して異なるユニットで結合されることが一般的です。このような動作の性質上、ボトルネックを調べるときに GPU の負荷がかかっている場所の特定や、GPU のボトルネックが何であるかを理解しておくと便利です。

デベロッパーがパフォーマンスを最適化するときにボトルネックを特定したい場合は、Unreal Insights というアプリケーションが便利です。Unreal Insights は、大まかに言うと Unreal Engine 4 (UE4) と統合されたスタンドアロン プロファイリング システムで、エンジンから出力されたデータを収集、分析、可視化するのに役立ちます。

Unreal Insights を設定する方法

Unreal Insights ツールは Unreal Engine に同梱されています。「UnrealInsights.exe 」は、エンジン ソース ディレクトリ フォルダ「Engine/Binaries/Win64」内か、またはランチャー エンジン ディレクトリ「Program Files/EpicGames/EngineVersion/Engine/Binaries/Win64/UnrealInsights.exe」にあります。

UnrealInsights.png

UE4 ソースコードをダウンロードしてローカルでコンパイルする場合、UE4 ソリューション全体を開発モードまたは出荷モードでビルドするか、「UnrealInsights」プロジェクトを直接ビルドしてコンパイルできます。

UnrealInsightsBuild.png

コンパイル済みのプログラム (UnrealInsights.exe) を見つけたら、データの記録やライブ セッションの表示に使用するデバイスで実行します。

GPU トレースデータをレコーディングする

トレース は、実行中のプロセスからインストルメンテーション イベントをトレースするための構造化されたログ フレームワークです。Insights には、CPU、フレーム、ログ、ブックマークに関する情報を自動的に追跡するためのデフォルト プリセット (-trace=default) が含まれており、追加で最適化が必要な領域を特定するのに役立ちます。

プロジェクトの GPU トレース データを追跡するには、コマンドライン引数を使用してプロジェクトを (スタンドアロンまたはパッケージ ビルドで) 起動します。

-trace= default, gpu

または、チルダ (〜) キーを押してコマンドを入力することで、コンソールのコマンド ウィンドウに移動できます。

Trace.Start[gpu]

GPU トレース データを監視する

トレース データは、「UnrealInsights/Saved/TraceSeissons」フォルダにある Trace Store Directory に保存されており、監視も可能です。

TraceStoreDirectory.png

もしくは、Unreal Insights アプリケーション内からライブセッションをダブルクリックして Insights Viewer を開くこともできます。

TraceSessionsInsights.png

GPU トレース データを分析する

Insights ビューア には、パフォーマンス データを参照および視覚化できる Timing Insights ウィンドウもあります。Timing Insights ウィンドウには、CPU および GPU のフレームごとのパフォーマンスデータが表示されます。ここでは、Rendering および RHI Thread トラックで CPU タイミング イベントを監視できます。これら 2 つのトラックは、GPU タイミング イベントと関連付けができるものの中で最も重要です。

GpuTrack.png

[Timing (タイミング)] パネル では、個々のトレース イベントが表示され、サブマイクロ秒の精度で時間測定が可能です。これらのイベントは、スコープを示すために垂直にスタックされ、異なるスレッドでのアクティビティを示すために個別のトラックを使用します。トラック表示では、イベントはスレッドごとに分割され、スコープを示すために垂直方向に分割され、開始時間と終了時間に基づいて水平方向に配置されます。

TimingPanel.jpg

[Timing] パネル (1) 内のタイマー イベントにカーソルを合わせたときに表示されるツールチップ。同じスレッド上のネストされたイベントのスタック (2)。

[Log (ログ)] パネルには、UE4 セッションからのすべてのログ (コールによって生成) が表示されます。ログは、エディタの [Output Log (アウトプットログ)] ウィンドウと同様に、冗長性とカテゴリによってフィルタリングできます。

LogPanel.jpg

[Log] を使用すると、[Timing] ビューで垂直なマーカーラインを表示できるようになります。デフォルトでは、ブックマークのみがマーカーラインとして表示されます。ただし、ショートカットキー M を使用するか、 Bookmarks (ブックマーク) トラックを右クリックしてコンテキスト メニューから [Logs (ログ)] を選択することで、これを変更することもできます。

BookMarks.png

Insights ブラウザをナビゲートしてログ カテゴリを表示します。(1).Bookmark トラック。(2) コンテキスト メニューは、Bookmark トラックの表示をフィルタリングします。

Unreal Insights には、アニメーションネットワーキング、および UI プロファイリングのための堅牢な機能もあります。

Unreal フロントエンド

以下の情報は、UnrealFrontEnd で GPU コストをプロファイリングするために使用するコマンドの詳細です。このツールのプロファイリング機能は、Unreal Insights に取って代わられました。

Unreal Frontend は、ゲーム ビルドの準備、デバイスへのデプロイ、起動など、日々のビデオゲーム開発とテスト タスクを簡素化および高速化することを目的としたツールです。

ProfileGPU コマンド

ProfileGPU コマンドを使用すると、さまざまなパスの GPU コストを特定できます。場合によっては、ドローコールも可能です。 マウスベースの UI またはテキストベースのバージョンのいずれかを使用できます。r.ProfileGPU.ShowUI を使用して UI を制御できます。データは GPU タイムスタンプに基づいており、 これは通常、非常に正確な結果を出力します。最適化の種類によっては数値の信頼性が低下する可能性があるため、数値に関しては注意深く確認するようにしてください。また、一部のドライバでは、 シェーダーを使用してから数秒後にシェーダのコストが最適化される傾向があることがわかりました。これによる差異は目立つ場合があるので、そのような場合は少し待つか、別の機会にもう一度測定することで、より信頼性のある結果が得られます。

| ProfileGPU.png |

| CONSOLE:ProfileGPU |

| Shortcut:Ctrl+Shift+, |

...

 1.2% 0.13ms   ClearTranslucentVolumeLighting 1 draws 128 prims 256 verts

42.4% 4.68ms   Lights 0 draws 0 prims 0 verts

   42.4% 4.68ms   DirectLighting 0 draws 0 prims 0 verts

       0.8% 0.09ms   NonShadowedLights 0 draws 0 prims 0 verts

          0.7% 0.08ms   StandardDeferredLighting 3 draws 0 prims 0 verts

          0.1% 0.01ms   InjectNonShadowedTranslucentLighting 6 draws 120 prims 240 verts

      12.3% 1.36ms   RenderTestMap.DirectionalLightImmovable_1 1 draws 0 prims 0 verts

          1.4% 0.15ms   TranslucencyShadowMapGeneration 0 draws 0 prims 0 verts

...

ProfileGPU は、アーティストが適切な光源を最適化しやすくなるライト名を表示します。

各フレームで高いコストがかかっている場所を調べることで、何を行うのが合理的かを判断します (たとえば、ドローコールが重いとき、マテリアルが複雑なとき、三角ポリゴン メッシュの密度が高いとき、表示距離が遠いときなど)。

EarlyZPass

デフォルトでは、一部の z パスを使用します。DBuffer デカールには、完全な Z パスが必要です。これは、 r.EarlyZPass および r.EarlyZPassMovable を使用してカスタマイズできます。

Base Pass (ベース パス)

ディファードを使用する場合、単純なマテリアルは帯域幅がバインドされる可能性があります。実際の頂点とピクセル シェーダーは、マテリアル グラフで定義されます。また、動的オブジェクトで間接ライティングを行う場合、追加コストがかかります。

Shadow map rendering (シャドウマップのレンダリング)

実際の頂点とピクセル シェーダーは、マテリアル グラフで定義されます。ピクセル シェーダーは、マスクされたマテリアルまたは半透明のマテリアルにのみ使用されます。

Shadow projection/filtering (シャドウ投影/フィルタリング)

r.ShadowQuality.Disable シャドウ キャストを使用してシェーダー コストを調整できます。多くのライトで効果があります。このコマンドはスタティックまたは固定ライト向けです。

Occlusion Culling (オクルージョン カリング)

これにより、HZB オクルージョンの固定コストは高くなりますが、オブジェクトごとのコストが小さくなります。r.HZBOcclusion を切り替えて、オンオフどちらの方がうまくいくかを確認してください。

Deferred lighting (ディファード ライティング)

タッチされたピクセルに合わせてスケーリングします。これは、ライト機能、IES プロファイル、シャドウの受け取り、エリア ライト、および複雑なシェーディング モデルでは負荷が重くなります。

Tiled deferred lighting (タイリング ディファード ライティング)

r.TiledDeferredShading を切り替えて、GPU ライトを無効にするか、 r.TiledDeferredShading.MinimumCount を使用してタイリング メソッドまたは非ディファード メソッドをいつ使用するかを定義します。

Environment reflections (環境の反射)

r.NoTiledReflections を切り替えて、非タイリング方式を使用します。非タイリング方式は、プローブが非常に少ない場合を除いて、たいてい動作が遅くなります。

Ambient occlusion (アンビエントオクルージョン)

品質を調整できます。また、複数のパスを使用することで、効率的に大きな効果を得ることができます。

Post-processing (ポスト プロセス)

一部のパスが共有されます。そのため、show (表示) フラグを切り替えて、効果がパフォーマンスに見合うかどうかを確認してください。

一部のパスが、その後のパスに影響を与える可能性があります。次に例をいくつか示します。

  • 完全な EarlyZ パスを使用すると、ドローコールがより多くなり、GPU コストが少し増えます。しかし、ベースパスでのピクセル処理を回避するため、そこでのコストを大幅に削減できます。

  • HZB を最適化すると、カリングがより保守的になる可能性があります。

  • シャドウを有効にすると、画面の大部分がシャドウになっている場合にライティングのコストを削減できます。

GPU のボトルネックとは?

多くの場合、パフォーマンス コストはピクセル数に比例します。これをテストするには、 r.SetRes を使用してレンダリング解像度を変更するか、エディタでビューポートを拡大縮小します。

r.ScreenPercentage を使用するとさらに使いやすくなります。しかし、この機能を使用すると、アップサンプリング コストが追加で発生することに注意してください。

測定可能なレベルでパフォーマンスに変化が見られる場合は、ピクセル関連にボトルネックがあります。通常、原因としてはメモリ帯域幅 (読み取りと書き込み) または数学バウンド (ALU) のいずれかが考えられますが、まれに、一部の特定のユニットが飽和状態になっている場合もあります (MRT エクスポートなど)。関連するパスでメモリ (または数学) を下げたときにパフォーマンスの違いを確認できる場合は、メモリ帯域幅 (または ALU ユニット) がボトルネックになっています。

これらは単なる例であるため、必ずしも同じように変更する必要はありません。しかし、これでパフォーマンスを向上させるにはコストを削減する必要があることが理解できたと思います。

シャドウマップの解像度は画面の解像度 (r.Shadow.MaxResolution を使用) に比例しませんが、シャドウ キャスティングのマスクされたマテリアルまたは半透明のマテリアルの領域が非常に広い場合を除いて、ピクセル シェーダーにはバインドされません。多くの場合、シャドウマップのレンダリングは、頂点の処理または三角ポリゴンの処理によって制限を受けます (原因: メッシュの密度が高すぎる、LOD がない、テッセレーション、WorldPositionOffset を使用している)。

シャドウマップのレンダリング コストは、ライトの数、キューブマップの側面の数、およびライト錐台内のシャドウ キャスティング オブジェクトの数に比例します。一般的に見られるボトルネックはこれが考えられます。したがって、コンテンツを大幅に変更するだけでコストの削減が可能です。

ワイヤーフレームがソリッド カラーで表示される高度にテッセレーションされたメッシュでは、クワッドの使用率が低くなる可能性があります。これは、GPU が 2x2 ピクセル ブロックの三角ポリゴンを処理し、少し遅れて三角ポリゴンの外側のピクセルを拒否するためです。この動作はミップマップの計算に必要となります。大きな三角ポリゴンの場合、これは問題とはなりません。

しかし、三角ポリゴンが小さいか非常に長い場合、処理されるピクセルの数が増えるとパフォーマンスが低下し、画像に対して実際に寄与するピクセルがほとんどなくなってしまう可能性があります。このような場合、ディファード シェーディングを使用するとライティングで非常に良いクワッド使用率を得られ、状況が改善します。とはいえ、ベースパスの間もその問題は残るため、複雑なマテリアルではレンダリングがかなり遅くなる可能性があります。

これを解決するには、密度の低いメッシュを使用します。詳細度メッシュでは、(距離内の) 問題がある場所でのみ実行されます。

r.EarlyZPass を調整すると、完全な初期 Z パスを使用した恩恵をシーンが受けているかどうかを確認できます (ドローコールがより多くなる、Bass Pass 中のオーバードローがより少なくなる)。

解像度を変更しても変化がない場合は、頂点の処理 (頂点シェーダー、またはテッセレーション) のコストが原因となっている可能性があります。

また、それを確認するには、多くの場合でコンテンツを変更する必要があります。典型的な原因は次のとおりです。

  • 頂点が多すぎる (この場合、詳細度メッシュを使用します)。

  • 複雑なワールド位置オフセット/ディスプレイスメントマテリアルが MIP マッピングが不十分なテクスチャを使用している (この場合、マテリアルを調整します)

  • テッセレーション (この場合、可能であれば、テッセレーション係数を調整して回避します。最も手っ取り早い方法は、テッセレーションを表示することです。一部のハードウェアは、テッセレーション レベルが大きくなるとスケーリングが悪くなります)。

  • UV か法線のシームが多くあり、頂点がより多くなっている (この場合、アンラップ UV を確認します。アイランドの数を減らし、フラットシェード メッシュが三角ポリゴンごとに 3 つの頂点を持つようにします)。

  • 頂点属性が多すぎる (この場合、UV チャンネルを余分に持ちます)。

  • 頂点の数が妥当であることを確認すると、一部のインポータ コードが頂点にくっつけていない (この場合、同じ位置、UV と法線を持つ頂点を結合します)。

頻度は低いものの、他の何かが原因となっている場合もあります。たとえば、次のようなものです。

  • オブジェクトのコスト (CPU コストが増える可能性が高いですが、GPU コストが増える場合もあります)。

  • 三角ポリゴンのセットアップに関するコスト (シャドウマップのスタティック メッシュなど、負荷の低い頂点シェーダーを持つ非常に負荷の重いポリゴン メッシュがある場合です。しかし、これが問題になることはめったにありません)。

  • 詳細レベル (LOD) メッシュの使用。

  • コストの表示 (HZB オクルージョン カリングなど)。

  • シーンのコスト (GPU パーティクル シミュレーションなど)。

ライブ GPU プロファイラ

ライブ GPU プロファイラでは、主要なレンダリング カテゴリのフレームごとのリアルタイム統計を表示できます。ライブ GPU プロファイラを使用するには、 バッククォート (`) キーを押してコンソールを開き、 stat GPU を入力して、 Enter キーを押します。また、 [Viewport Options (ビューポートオプション)] ドロップダウンの [Stat (統計)] サブメニューから、ライブ GPU プロファイラを起動することもできます。

GPU_Stats.png

統計は累積的で非階層的であるため、イベントのツリーを掘り下げることなく、主要なカテゴリを確認できます。たとえば、 [Shadow Projection (シャドウ投影)] は、すべてのビューにわたってすべてのライトのすべてのシャドウ投影の合計を示します。画面上の GPU 統計は、タイトル実行中の GPU 負荷を簡単かつ視覚的に内訳を表したものです。また、変更の影響を瞬時に測定するのにも役立ちます。たとえば、コンソール変数を変更したり、エディタでマテリアルを変更したり、シェーダーをオンザフライで変更および再コンパイルしたりする場合 (リコンパイル シェーダーを変更した場合)、それらがわかりやすく表示されます。後で分析するために、タイトル実行時に GPU 統計をファイルに記録することもできます。

既存の統計と同様に、コンソールコマンド stat startfile および stat stopfile を使用して統計を「ue4stats」ファイルに記録し、Unreal Frontend ツール でファイルを開いてそれらを視覚化できます。

Saved_Profile.png

UnrealFrontend を使用した GPU のプロファイリング。合計、ポストプロセス、およびベースパス時間が表示されます。

統計は、コードで浮動小数点として宣言されます。次に例を示します。

DECLARE_FLOAT_COUNTER_STAT(TEXT("Postprocessing"), Stat_GPU_Postprocessing, STATGROUP_GPU);

レンダリング スレッドのコードブロックは、それらの統計名を参照する SCOPED_GPU_STAT マクロでインストルメント化できます。これらは SCOPED_DRAW_EVENT と同様に機能します。以下に例を示します。たとえば、次のように確認します。

SCOPED_GPU_STAT(RHICmdList, Stat_GPU_Postprocessing);

明示的にインストルメント化されていない GPU の動作は、キャッチオール [unaccounted] 統計に含まれます。それが高くなりすぎる場合は、不足している動作を説明するために、いくつか追加の SCOPED_GPU_STAT イベントが必要であることを示します。

ドロー イベントとは異なり、GPU 統計は累積的であることに注意してください。同じ統計に複数のエントリを追加することもできます。そして、これらはフレーム全体で集計されます。特定の CPU バウンドの場合、GPU のタイミングは GPU が CPU が追いつくのを待っていることによって発生する CPU ボトルネック (バブル) の影響を受ける可能性があるため、ドロー スレッド時間が長い場合に予期しない結果が発生する可能性があることに留意してください。PlayStation 4 では、コマンドリストの送信間の時間をタイミングから除外することで、これらのバブルを修正しています。将来のリリースでは、その機能を他の最新のレンダリング API にも拡張する予定です。

Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
閉じる