9K Views
July 31, 25
スライド概要
Unreal Insightsは、プロジェクトのパフォーマンスを分析し問題を診断するための便利なツールで、Unreal Engineで作成したゲームを最適化するのに最適なツールです。Insightsを使えば、CPU/GPUパフォーマンスのボトルネック、メモリリーク、アセットのロード時間の長さなどを調査し、ゲームをリリースする前にこれらの問題に対処することができます。このセッションでは、様々なタイトルのプロファイリング経験に基づき、パフォーマンスの問題とは何か説明し、そして各ボトルネックケース別での分析方法を解説します。また、ご自身のプロジェクトのパフォーマンス分析に活用できる、Unreal Insightsの新機能もご紹介します。
Unreal Engineを開発・提供しているエピック ゲームズ ジャパンによる公式アカウントです。 勉強会や配信などで行った講演資料を公開しています。 公式サイトはこちら https://www.unrealengine.com/ja/
Unreal Insights を使用した パフォーマンス分析と最適化マスタリー Epic Games Japan Lead Software Engineer, Developer Relations 鍬農 健二郎
Table of contents ● パフォーマンスの問題 ● Unreal Insights の基本 ● パフォーマンス分析の基本 ● パフォーマンス分析の応用 ● 最適化まとめ
Section1 パフォーマンスの問題
パフォーマンスの問題とは?
プレイ可能なフレームレートが安 定して維持できない状態
パフォーマンスの問題が ないケース
パフォーマンスの問題が あるケース ヒッチング フレームドロップ
パフォーマンス問題を改善(最適化をする)理由 ● スムーズなゲームプレイ = より良いゲーム体験 ● パフォーマンスはバッテリー寿命、熱、プラットフォームでの規則に影響 ● 最適化はクラッシュの機会やロード時間を削減にも貢献 ● デバッグや反復操作の短縮にもつながる
はじめは ”stat unit” 項目 説明 Frame 1フレームにかかった時間 Game Game Thread の処理時間 Draw Rendering Thread の処理時間 RHIT RHI Thread の処理時間 GPU Time GPU の処理時間 ※RHIRendering Hardware Interface
1フレームのデータの流れ 入力 Game Game Thread Draw Render Thread CPU RHIT RHI Thread GPU GPU 画面出力
毎フレームのデータの流れと処理 Game Thread Render Thread RHI Thread GPU
毎フレームのデータの流れと処理 Game Thread Render Thread RHI Thread GPU
Section2 Unreal Insights の基本
Insights によるパフォーマンス最適化の 3ステップ プロファイル取得 プロファイル分析 問題点の修正 パフォーマンス収集用の 設定を追加してゲームを起動 してシーンをプレイ 取得したプロファイルを Insights で読み込んで問題 点を見つける アセットや設定の変更、 プログラムのロジック変更な どを行う
プロファイルの取得 ● Insightsで解析するためのプロファイルデータを取 得するためにプロファイルデータ収集を指示 ● 起動引数 もしくは コンソールコマンド -trace=[Channel]or trace.file [Channel] ● “Channel” は収集するデータ Channel 一覧はドキュメント参照 https://dev.epicgames.com/documentation/ja-jp/unreal-engine/unre al-insights-reference-in-unreal-engine-5
Frames: フレーム毎の処理時間を表示 どのフレームが重たいか?
Timers: イベントと処理時間の詳細を表示 どのイベントが重たいか?
Timing View: スレッド毎の処理とタイムライン 時系列順に見た時にどのスレッドのどの処理が重たいか?
コード内に埋め込まれたイベントマーカー
void UMyGameSystem ::TestEvent ()
{
TRACE_CPUPROFILER_EVENT_SCOPE (TestEvent_Scope );
if( GFastReturn )
{
return;
}
if( bUpdateCount )
{
for (int i = 0; i < 100; i++)
{
Count++;
}
}
UE_LOG( LogTemp, Log, TEXT( "Count=%d" ), Count);
}
ボトルネックを見つける3ステップ 1. Framesタブ から処理時間が長いフレームを見つける 2. Timing View からそのフレームで処理時間が長いスレッドを見つける 3. Timing View からそのスレッドで処理時間が長い関数を見つける ○ "xxx thread idle time" や "Wait for Tasks" といった、 スレッドが動いていないことを示す非アクティブなマーカーは除外
ボトルネックにはパターンがある ● ● ● Tick や Blueprint をたくさん使っている ○ CPU(Game Thread)が重くなりがち 広大なマップへレベルを移動 ○ CPU(Game Thread), FileI/O が重くなりがち HWRT、Lumen、Nanite、VSM などをフルで活用している ○ GPU が重くなりがち これらのパターン理解しつつ、自身のタイトル特有の問題や傾向を分析する
Section3 パフォーマンス分析の基本 Game, Render, GPU
Game Thread
はじめは ”stat unit” 項目 説明 Frame 1フレームにかかった時間 Game Game Thread の処理時間 Draw Rendering Thread の処理時間 RHIT RHI Thread の処理時間 GPUTime GPU の処理時間 ※RHIRendering Hardware Interface
Game Thread のボトルネックの調べ方 ● コマンド -trace=cpu,frame,assetloadtime -statnamedevents ● オプション log, bookmark, object, objectproperties, net, slate, animation, stats, counter, screenshot, regions, metadata
Frames タブでスパイクが発生しているフレームを見つける
ボトルネックのスレッド( Game Thread)にフォーカス
処理時間の長いイベントを見つける
Caller: 選択したフレームの処理を階層構造で表示
ホットアイコン 🔥 は処理時間が長い箇所を示す
Game Threadの最適化 Frames Game Frames Threads Game Thread Frame 10 Frame 11 Frame 12 Frame 13
Game Threadの最適化 Frames Game Frames Threads Game Thread Frame 10 Frame 11 13 Frame 12 FrameFrame 12 Frame 13
Game Threadの最適化 Frames Game Frames Threads Game Thread Worker Thread Frame 10 Frame 11 Frame 12 Frame 13
Game Thread 最適化 https://www.youtube.com/watch?v=KxREKDYu70&t
Game Thread プロファイルのポイント ● Game Thread はゲームのメイン処理 ○ プロジェクト側での処理が集中するとフレームの遅延に直結 ○ 毎フレーム、毎ティックで呼び出される多数の処理は累積的な負荷 ○ ローディングやGCなど、一時的に負荷が集中する処理を特定する ● 他のスレッドとの依存関係 ○ Game Thread が Worker Thread など、他のスレッドの処理完了を待っている ときは他のスレッドの処理を改善する必要がある
Render Thread
はじめは ”stat unit” 項目 説明 Frame 1フレームにかかった時間 Game Game Thread の処理時間 Draw Rendering Thread の処理時間 RHIT RHI Thread の処理時間 GPUTime GPU の処理時間 ※RHIRendering Hardware Interface
Render Thread のボトルネックの調べ方 ● コマンド -trace=cpu,frame,rendercommands,rhicommands,rdg ● ユースケース ○ Render Thread の処理が長い = ドローコールが多い可能性 ○ 重いレンダリングコマンドのキュー ○ シーン描画やポストプロセスパスの視覚化
Frames タブでスパイクが発生しているフレームを見つける
Render Threadの並列処理 Frames Game Frames Frame 10 Frame 11 Frame 12 Frame 13 Render Frames Frame 9 Frame 10 Frame 11 Frame 12 Threads Game Thread Render Thread
Render Threadの並列処理 Frames Game Frames Frame 10 Frame 11 Frame 12 Frame 13 Render Frames Frame 9 Frame 10 Frame 11 Frame 12 Threads Game Thread Render Thread
Render Threadの並列処理 Frames Game Frames Frame 10 Frame 11 Frame 12 Frame 13 Render Frames Frame 9 Frame 10 Frame 11 Frame 12 Threads Game Thread Render Thread Execute Tracks RDG ※RDGRendering Dependancy Graph RDG
RDG Insights https://dev.epicgames.com/documentation/en-us/unreal-engine/render-dependency-graph-in-unreal-engine
Render Thread プロファイルのポイント ● Render Thread の1フレームあたりの処理時間を理解する ○ 各レンダリング関数のコストを理解する ■ 特定のパス(PostProcess, Shadow, Lumen等)は負荷が高いか? ● Render Thread の処理時間が RHI Thread と GPU にも影響を与える ○ Render Threadが過度に速いか遅いかを確認する ■ Render Thread > GPU : CPU (Render Thread) がボトルネック ■ Render Thread < GPU : GPU がボトルネック
GPU
はじめは ”stat unit” 項目 説明 Frame 1フレームにかかった時間 Game Game Thread の処理時間 Draw Rendering Thread の処理時間 RHIT RHI Thread の処理時間 GPUTime GPU の処理時間 ※RHIRendering Hardware Interface
GPU のボトルネックの調べ方 ● コマンド -trace=cpu,gpu,frame (default) -trace=Rendering (gpu,cpu,frame,log,bookmark) ● GPU トラックではレンダリングパスとタイミングが表示されます ○ ポストプロセス、シャドウパスなどが支配的になる場合があります ● 詳細なシェーダー内容とレンダリング コマンドを分析したい場合は、 専用の GPU プロファイラー/デバッガー ツールを使用してください
GPU プロファイルのポイント ターゲットとする画面解像度でプロファイルを取得すること ● r.DynamicRes.TestScreenPercentage 60 コンソール:動的解像度の値を指定する値で固定 ● r.screenpercentage 60 PC:レンダリング解像度は出力解像度のパーセンテージで明示的に固定 ● r.RDG.AsyncCompute 0 個々のパスのパフォーマンスを正確に測定したい場合は非同期処理を無効化
New GPU Profiler
New GPU Profiler
New GPU Profiler GPU Fence Relations Signal to Wait Fence) Signal Fence Wait Fence GPU Work GPU Wait
GPU プロファイラー ・ デバッガー プラットフォーム ツール Windows DumpGPU, RenderDoc, PIX for Windows, iOS XCode GPU capture/trace Android RenderDoc (OpenGLES / Vulkan) ARM Graphics Analyzer (Mali GPU specific) Snapdragon Profiler (Qualcomm Adreno GPUs) Swicth/XBox/PlayStation Platform GPU profiler
Section 3 まとめ ● Game, Render, GPUについてはまず各スレッドとユニットの負荷を確認 ○ Game :ゲームロジックが過重 ○ Render :シーンの複雑さ ○ GPU :レンダリング/シェーダーの過負荷 ● Game -> Render -> RHI -> GPU というデータフロー ○ どのスレッドの処理が長いか、どこで待機しているか、およびスレッド同士の 関係を理解する必要がある
Section4 パフォーマンス分析の応用 Worker Thread, FileI/O
Worker Thread
Game Threadの最適化 Frames Game Frames Frame 10 Frame 11 Frame 12 Frame 13 Threads Game Thread Worker Thread 他スレッドの処理をブロッキングしないように背後で並列処理
はじめは ”stat unit” 項目 説明 Frame 1フレームにかかった時間 Game Game Thread の処理時間 Draw Rendering Thread の処理時間 RHIT RHI Thread の処理時間 GPUTime GPU の処理時間 ※RHIRendering Hardware Interface Game, Draw, RHIT, GPU Time は小さいが Frame が大きい ⇒ Worker Threadのネック?
Worker Thread のボトルネックの調べ方 ● コマンド -trace=cpu,frame,task -statnamedevents -trace=TaskGraph (cpu,gpu,frame,log,bookmark,screenshot,region,task) ● ユースケース ナビメッシュビルド、テクスチャストリーミング、アニメーション評価 RHIタスクパイプ、物理ステート作成、物理アップデート ⇒ メイン処理の背後で動いているもの
Worker Thread プロファイルのポイント ● Worker Thread は並列処理におけるメインの背後で動くスレッド ● タスクへの依存と並列処理の効率性をチェック ○ タスクごとの処理時間:特定のタスクに長時間かかっていないか? ■ 他のスレッドが処理完了待ちでボトルネックになっている ○ 待機中のスレッド:長時間待機中の Worker Thread がないか? ■ 待機中のスレッドに割り当て可能な処理を追加して効率化 ○ 並列処理の効率性:同期処理と非同期処理のバランスは十分か? ■ Coreが制限されるケース(コンソール、PC等)での動作
他のタスク待ち
他のタスク待ち
Activity Execute Task Overview Frames Game Frames Threads Game Thread Worker Thread#1 Frame 10 Frame 11 Frame 12 Frame 13
Activity Task Overview Frames Game Frames Threads Game Thread Worker Thread#1 Frame 10 Frame 11 Frame 12 Frame 13 Frame 14
Frames Game Frames Threads Game Thread Render Thread RHI Thread Worker Thread#1 Worker Thread#2 Worker Thread#3 Frame 10 Frame 11 Frame 12 Frame 13
ContextSwitch トレース
ContextSwitch トレースの方法 ● コマンド -trace=cpu,frame,contextswitch,task -statnamedevents -trace=ContextSwitching (cpu,gpu,frame,log,bookmark,screenshot,region,contextswitch) ● Windows においては “管理者として実行” で起動する必要がある ○ コンソールの場合は不要 ● CPUが現在実行中のプロセス/スレッドの状態(コンテキスト)を保存し、別のプロセ スまたはスレッドに切り替えるプロセス ○ 短命なスレッドが多すぎると、過剰なコンテキストスイッチが発生
ContextSwitch の問題への検証 ● 指定コア数(N)に制限して強制的にスレッドをスケジュール -corelimit=[N] -processaffinity=[N] N16 N3
Affinity Mask の調整方法 ● 起動引数 -execcmds="SetThreadConfig GT:TPri_Normal:0x3f Task:TPri_Normal:0x3f" ● 設定ファイル (Engine.ini) [/Script/Engine.Engine] ; Game - cores 0-6 +ThreadConfigs=GT:TPri_Normal:0x3f ; Task - cores 0-6 +ThreadConfigs=Task:TPri_Normal:0x3f Game ThreadのAffinity設定 GT:0x01 -> 0x08
FileIO
FileI/O のボトルネックの調べ方 ● コマンド -trace=cpu,file,assetloadtime,loadtimes,iostore -statnamedevents -trace=Loading (cpu,frame,log,bookmark,screenshot,region,loadtime,assetloadtime,file) ● ユースケース ○ ゲームプレイ中でのブロッキングI/O呼び出しを見つける ○ AsyncLoading Threadの長いストールを見つける
FileI/O プロファイルのポイント ● アセットのロードとファイルアクセスは、FileI/O専用のスレッドで実行 ○ Game Thread はアセットロードのリクエストを発行するだけ ● アクセスが発生する場所とタイミングを特定する ○ どのスレッドとどのプロセスがI/Oを生成している? ○ Game Thread または他のスレッドがI/Oを待って停止している? ● ロードするファイルのサイズと頻度を確認する ○ 小さなファイルへの頻繁なアクセス ○ 単一のファイルへの長いアクセス
Asset Loading Insights : アセットロード全般の分析ビュー
Loading Track : アセット毎のロード処理
I/O Activity: ファイル名のトラッキング IoStore Activity: Chunkアクセストラッキング
パッケージ別での統計情報
Asset Loading Game AsyncLoading Threads Game Thread Async Loading IoDispatcher IoServices Activity I/O File IOStore Memory
Asset Loading Game AsyncLoading Threads Game Thread Async Loading IoDispatcher IoServices Activity I/O File IOStore Memory
Asset Loading Game AsyncLoading Threads Game Thread Async Loading IoDispatcher 1 ブロッキング処理の削減 IoServices Activity 2 待ち時間の削減 I/O File IOStore Memory 3 ファイルアクセスの効率化
FileI/O ボトルネックの傾向と解決策 ボトルネック 解決策 Asset Loading アセットの同期ロード FileI/O帯域幅の使用 ランダムアクセスパターン 事前ロード、非同期ロード 常駐オブジェクト Disregard Object)の利用 必要な範囲のみのロード Chunking 適切にチャンキングされていない チャンキングパターンの最適化 .utoc/.ucas の最適配置 FileOpenOrder) File Access ゲームセーブ /ロードプロセス ファイル生成や読み書き 大容量テクスチャストリーミング 非同期処理によるファイルアクセス 頻繁なファイルアクセスを避ける メモリキャッシュを使う
Section 4 まとめ ● Task Graph、FileI/O のボトルネックは “stat unit” から直接特定できない ○ Unreal Insightsでスレッド処理を確認 ● Task Graph ○ スレッドを効率的に使用する ■ アイドル状態のスレッドに作業を割り当てる → 処理の分散 ■ 集中的な処理を避ける → フレームの分散 FileI/O ○ 関連スレッドのブロックポイントを特定しトラフィックを管理 ■ OSレベルでファイルの読み書きに制限があるため メインプロセスでストリーミングを効果的に制御 ●
Section5 最適化まとめ
本日のまとめ ● コンソールコマンド “stat unit” でハイレベルなボトルネックを把握 ● “Unreal Insights” を使用してローレベルな分析 ● 各ボトルネックに応じた適切な最適化 ● 検証サイクルの反復
最適化のための心構え ● データ優先 ○ 行動する前にすべてを測定する ● 仮定を避ける ○ ツールを使用し、推測に頼らない ● 優先順位をつける ○ 最も重要な問題を優先して解決する ● 反復する ○ 変更ごとに再テストを行う トレース 分析 検証 最適化
最適化時に意識すること ● ● ● ● ● 可能な限り少ない処理を心がける できるだけシンプルで複雑でないように保つ プロセスを短くし、迅速に完了させる 可能な限り成熟した機能を活用する ○ 新しい機能は最適化されていない可能性がある 何かを行う際は、以下の点を念頭に置く ○ 並列化 ○ プール化、再利用 ○ 必要に応じてゲームプレイの優先順位を調整する 重要なこととして 可能な限り少ない処理を心がける
リファレンス Documentation: Unreal Insights https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-insights-in-unreal-engine Documentation: Unreal Insights Reference https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-insights-reference-in-unreal-engi ne-5 Documentation: Stat Commands https://dev.epicgames.com/documentation/en-us/unreal-engine/stat-commands-in-unreal-engine Superluminal https://superluminal.eu/ Guidelines for Optimizing Rendering for Real-Time https://dev.epicgames.com/documentation/en-us/unreal-engine/guidelines-for-optimizing-rendering-forreal-time-in-unreal-engine [Intel] Unreal Engine* Optimization Guide: Profiling Fundamentals https://www.intel.com/content/www/us/en/developer/articles/technical/unreal-engine-optimization-profil ing-fundamentals.html Optimize Unreal Engine 5 performance on low-end computers https://irendering.net/optimize-unreal-engine-5-performance-on-low-end-computers/ Unreal Engine Performance Guide https://gpuopen.com/learn/unreal-engine-performance-guide/
Thank you!