[UE4] Unreal InsightsによるCookプロファイル (Cook Trace)

検証バージョン：UE4.27
# 1. 概要
　[Unreal Insights](https://docs.unrealengine.com/4.26/ja/TestingAndOptimization/PerformanceAndProfiling/UnrealInsights/)にUE4.26からCookトレースの機能が追加されました。これを利用することでCookが実行されている状況のパフォーマンスキャプチャを取得し、Cookのプロファイルができるようになります。以下はこの利点について少し具体的に示したものです。

**[できること]**
**① アセット毎にクック処理に掛かった時間や処理を確認できる**
　・どのアセットのクックに時間がかかっているか？
　　→ アセット単位でのクック処理に掛かっている時間を調べることができます

　・不要なアセットもクックされていないか？
　　→ クックされたアセットを調べることができます

　・具体的にクック処理のどこで時間が掛かっているか？
　　→ クック処理の詳細情報を確認して最適化の余地があるか検討することができます

**② CPUの動作を並列して確認できる**
　・DDCを利用しているか？どの程度アクセスに時間が掛かっているか？
　　→ DDCの処理時間や動作スレッドを確認することができます

　・TextureStreamingに時間かかっている？
　　→ 非同期スレッドで実行されるテクスチャストリーミング状況を確認できます

　・CPUコアどのくらい使ってクックできている？
　　→ バックグランドで動作するスレッドの動作を確認できて無駄なスレッドやボトルネックを調べることができます

# 2. キャプチャ方法
　以下の2つの手順で利用することができます。

**① Unreal Insightsを開く**
　Cook実行前にUnreal Insightsを起動しておきます。

**② Cookをコマンドレットから実行する**
　コマンドレットを利用してプロジェクトをCookします。以下はCookをバッチからプロジェクトを実行する一例です。プロジェクトで利用したい場合は、UE4Editor.exeとプロジェクトパスを自分の環境に沿ったものに書き換えるだけです。

```batchfile:CookCommandlet.bat
rem UE4Editor.exeパス
set ENGINE_PATH="D:\Release-4.27\Engine\Binaries\Win64\UE4Editor-Cmd.exe"
rem プロジェクトパス
set PROJECT_PATH="D:\Projects\ShooterGame\ShooterGame.uproject"
rem Traceコマンド
set COMMAND=-tracehost=localhost -trace=cpu,cook,loadtime,savetime

%ENGINE_PATH% %PROJECT_PATH% -run=cook -targetplatform=WindowsNoEditor %COMMAND%
```
　これでCook時のプロファイルはキャプチャできたので完了です。

**(追記) ※ 上記はUE4の例ですが、UE5では以下のようになります**
```batchfile:CookCommandlet.bat
rem UnrealEditor.exeパス
set ENGINE_PATH="D:\Release-5.0\Engine\Binaries\Win64\UnrealEditor-Cmd.exe"
rem プロジェクトパス
set PROJECT_PATH="D:\Projects\ShooterGame\ShooterGame.uproject"
rem Traceコマンド
set COMMAND=-tracehost=localhost -trace=default,cook

%ENGINE_PATH% %PROJECT_PATH% -run=cook -targetplatform=Windows %COMMAND%
```

# 3. キャプチャ結果
　キャプチャしたデータはTiming Insights上に表示されます。

**Cook Traceを有効にした際のTiming Insights (Channel=cpu,cook,loadtime,savetime)**
![2021-07-16_17h42_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/f582e10b-e8dd-eebc-67cd-785fbccb15c9.png)

　詳細を見ていくと、以下のようにパッケージ（アセット）の保存ログなどが確認できます。以下のケースはテクスチャが保存された際のログですが、アセットのクック時の主な処理はアセットのロードとセーブです。Cook時間を改善したいようなケースでは、これらのタイムラインを俯瞰して見ながら長い部分を減らすことを意識して設定を変更したりアセットの組み合わせを変更するなど、修正を行います。
![2021-07-16_19h16_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/990c6d2b-135e-d536-4834-9acddebe0d70.png)

# 4. クックの改善
　Cook時間を短縮するための幾つかの方法を以下に記載します。

## 1) シリアライズ
　クックをトレースした際にタイムラインに表示されますが、クック時にはアセットのセーブ/ロードが行われます。その処理の多くはシリアライズやオブジェクトロードに起因しています。

**・リソースの適切な設定**
　Texture、Mesh、Materialのシリアライズ処理は設定によって大きく変わります。クオリティとの兼ね合いもあるので、無駄が無いようにバランスを鑑みて調整します。

**・スクリプトの多用に注意する**
　Material、Niagara、Blueprint、Widget、Sequencer等、スクリプト上のプロパティやノードはオブジェクトを多く使用しがちなため、スクリプトの利用が多くなるとシリアライズにかかる時間が長くなります。

**・Component/Actorの細分化におけるバランス調整**
　1つのComponentやActorに多くの機能を持たせることはロードに時間を要したり、役割を越えてしまい扱いが難しくなりがちですが、細かく分けた事によっての弊害もあります。例えば、1つのComponentを2つに分割することによって共通処理が1回から2回実行することになり、ケースによっては冗長です。細分化したComponent/Actorを複製して利用するケースでは負荷も大きく増える事になるので、時には処理を纏めた方が有利なこともあります。

## 2) 共通項
　クックのトレース結果とは別に、一般的なクック時間の改善方法は以下の例があります。

**・[NeverCook](https://qiita.com/donbutsu17/items/d910d22d6ed3867e3d43#directoriestonevercook-directories-to-never-cook)ディレクトリを設定する**
 （当然のことですが）クック時間を短縮する最適な方法はクックするアセットを減らすことです。Cookしない/Packageに含めないディレクトリを作成しておくことは重要で、DevelopersフォルダやNeverCook対象のフォルダをチームで予め定めておくとよいです。

**・[SharedDDC](https://docs.unrealengine.com/4.26/ja/ProductionPipelines/DerivedDataCache/)を使用する**
　DDCキャッシュを使用してクックすることで処理を短縮することができます。

**・ストレージにSSDを使用する**
　頻繁にファイルアクセスが行われるため、HDDではなくSSDを使用することで処理を短縮します。

**・クック用GC設定を調整する**
　クック中はGCを抑制することによってクック全体の時間を短縮します。GCをセーブすることによる一時的なメモリ消費量は増加します。以下はその設定の一例でDefaultEditor.iniで設定することで適用できます。

```
[CookSettings]
PackagesPerGC=0
IdleTimeToGC=0
MemoryMinFreeVirtual=8192
MemoryMaxUsedVirtual=98304
MemoryMaxUsedPhysical=0
MemoryMinFreePhysical=8192
```

## 3) テスト
　以下のオプションは、テストや評価用の環境で反復操作をする際のクック時間を短縮します。これらのオプションは本番用やリリースビルドで使用することは推奨されません。

**・CookerOption`-iterate`を追加する**
デフォルトでは全てのクック済みアセットを削除しますが、このオプションによって変更のあるアセットのみをクックします。

**・CookerOption`-cooksinglepackage`を利用する**
全アセットクックではなく指定したアセット(とそれに付随するアセット)のみをクックできます。

# 5. 応用
　アセットがクックされるタイミングを調べたい場合は、以下のようにログを追加しつつ、トレースチャンネルを追加すると便利です。

```batchfile:CookCommandlet.bat
rem UE4Editor.exeパス
set ENGINE_PATH="D:\Release-4.27\Engine\Binaries\Win64\UE4Editor-Cmd.exe"
rem プロジェクトパス
set PROJECT_PATH="D:\Projects\ShooterGame\ShooterGame.uproject"
rem Traceコマンド
set COMMAND=-tracehost=localhost -trace=cpu,cook,loadtime,savetime,log -ini:Engine:[ConsoleVariables]:cook.displaymode=2

%ENGINE_PATH% %PROJECT_PATH% -run=cook -targetplatform=WindowsNoEditor %COMMAND%
```

上記のようにアセットのクックタイミングでログが出力されるので、ログも同様にトレースしてからログを検索ボックスとして利用するとよいです。[M]キーを押すとタイムライン内に表示が追加され、アセットを調べる場合には検索ボックスにアセット名をしてダブルクリックすると対象のログのありかが分かります。
![2021-07-16_18h46_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/6be67646-eafa-1310-1f64-11b77c9b362e.png)