【CEDEC2018】一歩先のUnityでのパフォーマンス/メモリ計測、デバッグ術

16K Views

August 23, 18

スライド概要

2018/8/22に開催されたCEDEC2018の講演資料です。
講師:黒河 優介(ユニティ・テクノロジーズ・ジャパン合同会社)

profile-image

リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

2018/8/22 一歩先の Unity でのパフォーマンス / メモリ計測、デバッグ術 講演者名 黒河 優介 所属団体 Unity Technologies Japan 肩書・役職 Developer Relation Engineer

2.

自己紹介 • 役職 • ユニティ・テクノロジーズ・ジャパン合同会社 エンタープライズコンサルティングデベロッパー リレーションマネージャー/エンジニア • 仕事内容 • 大規模プロジェクトのサポート業務 • プロジェクトに合う形で、パフォーマンスに関す る提案等を行っている

3.

まず初めに… 快適に動作するアプリケーションを作成するためには、 パフォーマンス計測を行いボトルネックとなる箇所を修 正や、デバッグを行いバグを修正していくことが重要に なります。 Unityはパフォーマンス計測や、デバッグのための機能を 日々アップデートしています。 このセッションでは直近のアップデートを紹介し、皆様 の開発に役立てれば幸いです。 ※テストの話はしません

4.

本日のアジェンダ • Profiler、デバッグ機能についてのおさらい • 実機だけでも使えるパフォーマンス計測術 • Profiler、デバッグ機能関連のアップデート情報

5.

Profiler、デバッグ機能おさらい

6.

おさらい • Unity Profiler • Frame Debugger • Consoleウィンドウ • Script Debugging • プラットフォーム毎のツール

7.

おさらい • Unity Profiler • Frame Debugger • Consoleウィンドウ • Script Debugging • プラットフォーム毎のツール

8.

Unity Profiler CPU/Rendering/Memoryなどの パフォーマンス測定が出来ます。

9.

Unity Profiler 画面上半分は各項目の推移グラフで、 下半分は選択した項目の詳細が表示されます

10.

Unity Profiler Timeline表示に切り替えて 別スレッドの処理も確認する事 が出来ます

11.

Unity Profiler Deep ProfileをONにすると、C#呼び出しで 深い階層も自動的に計測対象となります (Editor上での実行時のみ有効)

12.

Unity Profiler Profile EditorをONにすると、Editorで のC#処理が計測の対象となります。

13.

Unity Profiler ネットワークや有線ケーブルを利用して、 実機でのパフォーマンス計測も可能です ※要Development ビルド

14.

Unity Profiler Profilerに自分で定義した項目を載せる事が可能です

15.

Unity Profiler public class Sample : MonoBehaviour { private CustomSampler sampler; void Start () { sampler = CustomSampler.Create("処理計測"); } void Update () { コードはこんな sampler.Begin(); // ..何か処理をします 感じです sampler.End(); } }

16.

豆知識 Editor⇔実機間では Sample名の文字列も含 まれているため、Profilerさえ繋げてしまえ ば別プロジェクトのProfilingが出来ます。 ※Unityのバージョン毎にデータフォーマットが変わるので バージョンは合わせる必要があります

17.

おさらい • Unity Profiler • Frame Debugger • Consoleウィンドウ • Script Debugging • プラットフォーム毎のツール

18.

Frame Debugger Unityの描画処理を1ステップずつ確認出来ます。Shader パラメーターも確認出来ますので、描画関連のデバッグ に利用できます

19.

おさらい • Unity Profiler • Frame Debugger • Consoleウィンドウ • Script Debugging • プラットフォーム毎のツール

20.

Consoleウィンドウ Debug.Logの出力先のConsoleウィンドウ です

21.

Consoleウィンドウ ネットワークや有線経由で実機と接続し て実機上のログを出力する事が出来ます (2017.1+)

22.

おさらい • Unity Profiler • Frame Debugger • Consoleウィンドウ • Script Debugging • プラットフォーム毎のツール

23.

Script Debugging Visual Studio等のIDE環境等を利用 してUnity Editor上で動作している C# スクリプトのデバッグが出来ま す。

24.

Script Debugging breakポイントを貼ったり、変数をウォッチしたりと 普通にデバッグが出来ます

25.

Script Debugging BackEndがMonoでかつ、 Script Debuggingを有効にして いる場合には実機上で動いてい るC# スクリプトのデバッグが 出来ます

26.

Script Debugging ネットワーク/もしくは 有線を 利用して、実機上で動いている C#スクリプトのデバッグが出来 ます(Mono限定)

27.

おさらい • Unity Profiler • Frame Debugger • Consoleウィンドウ • Script Debugging • プラットフォーム毎のツール

28.

プラットフォーム毎のツール • PC/Android • RenderDoc • iOS • Instruments • OpenGLES Frame Debugger • Android • Systrace • DS-5™ Streamline • Snapdragon Profiler • Mali Graphics Debugger • GAPID 等々…

29.

RenderDoc 描画の深いレベルでの デバッグに使えます

30.

Instruments 深いレベルでのCPUプロファ イルが出来ます

31.

OpenGLES Frame Debugger 深いレベルでの描画のデバッ グ・プロファイルが出来ます

32.

Systrace CPUで動いている処理等が 確認出来ます

33.

DS-5™ Streamline ARM製のツールです。 CPUの様子等が確認出来ます

34.

Snapdragon Profiler 描画のデバッグが出来ます。 チップセットがSnapdragonである必要があります。

35.

Mali Graphics Debugger 描画のデバッグやプロファイ ルが出来ます。GPUがMaliの 場合に利用できます

36.

GAPID Google製のGraphicsデバッグ ツールです。画像付きでキャ プチャーしてくれるので非常 に便利です。

37.

Android向けツールは、コマンドライン向け SimplePerf、Intel Android向けツールなど 多々あります。 詳細は下記Webで https://unity3d.com/jp/learn/tutorials/topics/best-practices/android-profiling-tools

39.

実機でも使えるパフォーマンス計測術

40.

簡易的にパフォーマンス計測を日常的に行い、 大事にならないようにしておく必要があります。 日常的に目標とする端末でパフォーマンス上の 問題が起きていないか確認しましょう。

41.

このような感じで実機上で視認できる形で パフォーマンスを「視える化」しておくの が大事です

42.

そのために必要な機能として、実機上でも動作 するパフォーマンス計測の手法をお伝えいたし ます。

43.

実機でも使えるパフォーマンス計測術 • Time.realtimeSinceStartupを利用 • Time.realtimeSinceStartup + PlayerLoop(2018.1+) • Recorder APIについて • Memory情報の取得 • Profilerログデータ書き出し

44.

実機でも使えるパフォーマンス計測術 • Time.realtimeSinceStartupを利用 • Time.realtimeSinceStartup + PlayerLoop(2018.1+) • Recorder APIについて • Memory情報の取得 • Profilerログデータ書き出し

45.
[beta]
Time.realtimeSinceStartupの利用
void Update(){
float startTime = Time.realtimeSinceStartup;
DoSomething();
float executeTime = Time.realtimeSinceStartup - startTime;
Debug.Log(string.Format("DoSomethingに{0}ms掛かりました",
executeTime * 1000.0f));
}

Time.realtimeSinceStartupはアクセスした瞬間に時間を取りに行

きます。そのため、計測する箇所の前後の差分を求める事で処理
時間が取れます。 Releaseビルドでも計測可能です

46.

実機でも使えるパフォーマンス計測術 • Time.realtimeSinceStartupを利用 • Time.realtimeSinceStartup + PlayerLoop(2018.1+) • Recorder APIについて • Memory情報の取得 • Profilerログデータ書き出し

47.

PlayerLoopも活用 Unity 2018.1より追加されたPlayerLoopを利用すること で、MainLoop中に行われる特定のUnity処理を省いたり、 Unity処理の間に独自のC#処理を差し込むことが可能で す。 これと Time.realtimeSinceStartupを組み合わせて、更に 情報をとることが可能です

48.

PlayerLoopについて MonoBehaviour Updateを処理 Animatorの処理 MonoBehaviour LateUpdateを処理 Etc....

49.

PlayerLoopについて MonoBehaviour Updateを処理 Animatorの処理 MonoBehaviour LateUpdateを処理 LateUpdateは全くないので、この部分の処理を 全て省くという事が出来たり… Etc....

50.

PlayerLoopについて MonoBehaviour Updateを処理 MonoBehaviour Animatorの処理 LateUpdateを処理 Animatorの処理の前後に特定のC#スクリプトを 差し込むこともできます。 Etc....

51.

PlayerLoopについて PlayerLoopで設定できるステップはかな り種類が多いです。 どんな種類があるかはProfielrのトップ 階層を見ると何となくわかります。

52.

PlayerLoopも活用 MonoBehaviour Updateを処理 MonoBehaviour Animatorの処理 LateUpdateを処理 Animatorの処理の前後で Time.realtimeSinceFromStartup を取っておけば、 Animatorの処理時間をランタイムで計測出来ます! Etc....

53.

PlayerLoopも活用 https://github.com/wotakuro/MainLoopProfilingSample

54.

PlayerLoopも活用 水色:スクリプト処理 赤色:Animator関連処理 黄緑:描画関係 紫色:その他 それぞれの処理時間を表します https://github.com/wotakuro/MainLoopProfilingSample

55.

実機でも使えるパフォーマンス計測術 • Time.realtimeSinceStartupを利用 • Time.realtimeSinceStartup + PlayerLoop(2018.1+) • Recorder APIについて • Memory情報の取得 • Profilerログデータ書き出し

56.

Recorder APIについて Profilerに載っている名前を指定して、そこに掛かった 処理時間をRuntime上で取得することが出来ます

57.

Recorder APIについて Recorder recorder = Recorder.Get("Camera.Render"); Debug.Log(string.Format(“{0}ms ({1} Calls)", recorder.elapsedNanoseconds * 0.00001f), recorder.sampleBlockCount); Recorder API で Profilerに表示される項目を取得できます。 ※ただし全Threadでの累計処理時間のみ取得可能です

58.

Recorder API について 「Camera.Renderer」に 5.94ms(3.13 + 2.81)で2回呼び出しが あったという情報が取得できます

59.

先ほどのMainLoopとうまく組み合わせて … Camera.Renderの合計時間 - Main Thread側の描画処理時間で RenderThreadの処理負荷が概算できます

60.

実機でも使えるパフォーマンス計測術 • Time.realtimeSinceStartupを利用 • Time.realtimeSinceStartup + PlayerLoop(2018.1+) • Recorder APIについて • Memory情報の取得 • Profilerログデータ書き出し

61.

Memory情報の取得 • Profiler APIを利用して概要のざっくり把握 • Resources APIを利用して 読み込んでるアセットを一覧で把握

62.

Profiler APIを使用して取得 • Managed Memoryの使用状況 • Profiler.GetMonoHeapSizeLong • Profiler.GetMonoUsedSizeLong • Unityが確保したメモリの使用状況 • Profiler.GetRuntimeMemorySizeLong • Profiler.GetTotalReservedMemoryLong • Profiler.GetTotalUnusedReservedMemoryLong

63.

読み込んでいるアセット一覧を取得 Resources.FindObjectsOfTypeAllを利用すること で、実行中にメモリ上にあるアセットを列挙す ることが可能です。 ※Editor上で行った場合は、Editor実行時に読み込んだアセットも列 挙されてしまうため、実機上で行う必要があります

64.

読み込んでいるアセット一覧を取得 Texture2D[] textures = Resources.FindObjectsOfTypeAll<Texture2D>(); Mesh[] meshes = Resources.FindObjectsOfTypeAll<Mesh>(); AudioClip[] audioClips = Resources.FindObjectsOfTypeAll<AudioClip>(); AnimationClip[] animationClips = Resources.FindObjectsOfTypeAll<AnimationClip>(); メモリに読み込んだアセット一覧の取得が上記のように出来ます

65.

実機でも使えるパフォーマンス計測術 • Time.realtimeSinceStartupを利用 • Time.realtimeSinceStartup + PlayerLoop(2018.1+) • Recorder APIについて • Memory情報の取得 • Profilerログデータ書き出し

66.

Profilerログデータ書き出し string logfile = Path.Combine(Application.persistentDataPath, "profiler.log"); Profiler.logFile = logfile; Profiler.enableBinaryLog = true; Profiler.enabled = true; Profilerを内部的に動かし、ログファイルとして結果を保存し 始めます。止めるときは、下記呼び出しをします 「Profiler.enabled = false;Profiler.logFile = null;」

67.

Profilerログデータ書き出し 保存したログファイルは ProfilerのLoadで読み込めます。 ※1.Androidならば「adb pull ファイルパス」という形でコマンドライ ンでPCからログファイル取得できます。 ※2.iOSの場合、XCode上の「info.plist」を編集することで、iTunes からログファイルへのアクセスが可能になります。

68.

Profilerログデータ書き出し ログファイル自体には、ログ書き出しを開始してからの 全てのフレームが保存されていますが、表示側の問題で 300フレーム分しか表示されません…

69.

Profilerログデータ書き出し 300フレーム問題を解決するために専 用のEditor拡張を作成しました。 リポジトリ https://github.com/wotakuro/ProfilerBinarylogSplit

70.

アップデート情報

71.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin Callbackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

72.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin Callbackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

73.

実機上でのProfiler動作の高速化 • 2017.3のタイミングで 実機⇔Editor間での通信フォー マットから見直し、実機上で動作するProfilerの負荷が 下がりました • 1フレーム毎に全てのSample名を送っていたのをやめ、前のフ レームで送っていた場合は、Sample名を送らないようにしまし た • 実機側で集計処理を行って結果をEditorに送信する実装になって いましたが、新しくEditor側で集計するようにしました

74.

2017.3以前では文字列を都度送ってます 1フレーム目 BehaviourUpdate 2ms Player.Update 1ms Enemy.Update 0.5ms Bullet.Update 0.5ms 2フレーム目 Memoryや Rendering等の情報 BehaviourUpdate 1.8ms Player.Update 0.9ms Enemy.Update 0.4ms Bullet.Update 0.5ms Memoryや Rendering等の情報 1フレーム毎にSample名の文字列情報を含む全ての情報を含 んでいるため、巨大なデータをEditorと実機の間でやり取り していました

75.

2017.3以降では文字列を都度送りません Dictonary 0:BehaviourUpdate 1:Player.Update 2:Enemy.Update 3:Bullet.Update 1フレーム目 Sampleの情報 Memoryや Rendering等の情報 2フレーム目 Sampleの情報 Memoryや Rendering等の情報 Sample名とID(int)がセットになった辞書を送っておき、 以降は IDベースでやり取りします

76.

集計処理について BehaivourUpdate BeginSample 起動から 1000ms Player.Update BeginSample 起動から 1000ms Enemy.Update EndSample 起動から1001.5ms Player.Update EndSample 起動から1001ms Enemy.Update BeginSample 起動から 1001ms Bullet.Update Bullet.Update BeginSample EndSample 起動から1001.5ms 起動から1002ms BehaivourUpdate End 起動から1002ms Thread毎にBeginSample/EndSampleが発生した タイミングでキューにデータを溜めていきます

77.

集計処理について BehaivourUpdate 1000ms から開始して 2ms掛かった 以降の3つを呼び出している Player.Update 1000msから開始して 1ms掛かった 呼び出し先なし Enemy.Update 1001msから開始して 0.5ms掛かった 呼び出し先なし Bullet.Update 1001.5msから開始して 0.5ms掛かった 呼び出し先なし Profilerに表示するために 先のイベントを集計して このようなデータに変換 する必要があります

78.

集計処理について BehaivourUpdate BeginSample 起動から 1000ms Player.Update BeginSample 起動から 1000ms Player.Update EndSample 起動から1001ms Enemy.Update BeginSample 起動から 1001ms Enemy.Update EndSample 起動から 1001.5ms Bullet.Update BeginSample 起動から 1001.5ms Bullet.Update EndSample 起動から1002ms BehaivourUpdate End 起動から1002ms この集計処理を Editor側で受け持つように し、実機上では上のデータをそのまま転送 するようにしました BehaivourUpdate 1000msから開始して 2ms掛かった 以降3つを呼び出している Player.Update 1000msから開始して 1ms掛かった 呼び出し先はない Enemy.Update 1001ms から開始して 0.5ms掛かった 呼び出し先はない Bullet.Update 1001.5msから開始して0.5ms掛かった 呼び出し先はない

79.

豆知識 2017.3以降では API ”Profiler.logFile”を利用して書き込ん だデータと、Profiler Window上でSaveしたデータは一致 しなくなりました。 ”Profiler.logFile”は集計前の形式のデータなのに対して、 Profiler Window上でSaveするデータは集計後のデータだ からです。

80.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin Callbackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

81.

実機上でのDeep Profiling これまでは実機上でのDeepProfilingは出来ませんでしたが、 引数に「-deepprofiling」を渡して実行することで、実機上でも DeepProfilingが可能になりました ※.Net 4.x系で Mono限定

82.

Androidでの引数渡し Androidでは下記のようなadb コマンドを利用する事で引数を指定し てアプリを実行できます adb shell am start -n [パッケージ名]/ [アクティビティ名] -e “unity -deepprofiling" 例:adb shell am start -n com.unity.test/com.unity3d.player.UnityPlayerActivity -e “unity -deepprofiling"

83.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin Callbackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

84.

User Threadへの対応

85.

User Threadへの対応 Thread th = new Thread(ThreadExec); th.Start(); static void ThreadExec(){ CustomSampler sampler = CustomSampler.Create("Exec"); Profiler.BeginThreadProfiling("User","DoSomething"); while (flag){ sampler.Begin(); Exec(); // .. 何か処理する sampler.End(); } Profiler.EndThreadProfiling(); } ※2018.3から C#で作成したThreadは自動的に登録されるようになります

86.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin Callbackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

87.

Native Plugin Callbackへの対応 2018.2から導入されました 利用するには Editor/Data/PluginAPI/IUnityProfilerCallbacks.hをinclude します。 ※ヘッダーにサンプルコードもあります

88.

Native Plugin Callbackへの対応 BehaivourUpdate BeginSample 起動から 1000ms Player.Update BeginSample 起動から 1000ms Player.Update EndSample 起動から1001ms Enemy.Update BeginSample 起動から 1001ms Enemy.Update EndSample 起動から 1001.5ms Bullet.Update BeginSample 起動から 1001.5ms Bullet.Update EndSample 起動から1002ms BehaivourUpdate End 起動から1002ms これらのイベントが呼び出されたときにNative Pluginへ コールバックさせるインターフェースが追加されました

89.

Native Plugin Callbackへの対応 NativePlugin内でProfilerのタイムライン 相当のデータを構築することが出来ます

90.

Native Plugin側でデータを保存して、 それを表示するツールを作れば独自の Profilerも作成出来ます

91.

Native Plugin Callbackの利用例 Unity Profilerから取得した情報を Profilerから取得した情報を Unity AndroidのSystraceに載せています AndroidのSystraceに載せています https://github.com/Over17/UnitySystracePlugin

92.

Native Plugin Callbackの利用例 python [android-sdkパス]/platform-tools/systrace/systrace.py --time=5 -o \output.html -a com.unity.sample[アプリのBundleID] 上記のようなコマンドで取得することが可能です https://github.com/Over17/UnitySystracePlugin

93.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin CallBackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

94.

IL2CPP でのScript Debugging IL2CPPでビルドしたアプリ ケーションに対しても、C#の コードレベルでデバッグが可能 です

95.

IL2CPP でのScript Debugging • 2018.2から導入されました • PC/iOS/Android/Consoleゲーム機に入ってます (Xbox Oneは2018.3に入る予定です) • 「.Net 4.x Equivalement」にのみ対応しています ※Processにアタッチしてからbreakpointを認識するまでに10秒ほどのラグがあります。 1度認識してしまえば、その後のレスポンスは早いです

96.

アップデート情報 • 実機上でのProfiler動作の高速化(2017.3+) • 実機上でのDeepProfiling (2017.3+) • User Threadへの対応(2017.3+) • Native Plugin Callbackへの対応(2018.2+) • IL2CPPでのScript Debugging(2018.2+) • 新しいMemory Profiler(2018.3+)

97.

新しいMemoryProfiler • Memoryの計測ツールの現状 • Unity標準搭載 • UnityのBuilt-In Profiler • 拡張機能系 • Memory Profiler • Memory Profiler Extension • Memory Profiler Advanced( PerfAssist )

98.

Unity標準のMemoryProfiler リアルタイムでメモリのサマリー情報が 確認出来る Simpleモード

99.

Unity標準のMemoryProfiler メモリのsnapshotをとって、 その時点でのデータを詳細に 閲覧できるDetailedモード

100.

[拡張系] Memory Profiler メモリのsnapshotをとって、 その時点でのデータを見やす くした Editor拡張です https://bitbucket.org/Unity-Technologies/memoryprofiler にて配布

101.

[拡張系] Memory Profiler Extention IL2CPPビルドが必要ですが、 依存関係がグラフ表示された りする Memory Profilerです https://github.com/robertoardila/support-unity-memoryprofiler にて配布

102.

[拡張系] Memory Profiler Advanced PA_ResourceTrackerという名前で配布されていた MemoryProfiler。リスト化されており見やすいです https://github.com/GameBuildingBlocks/PerfAssist/ にて配布

103.

Memory Profiler使い分け大変… 大体標準機能として入っていない …

104.

新しいMemory Profilerを開発中 • 2018.3で alpha previewとして公開予定 • PackageManagerで配布を予定 • エンジン側のMemory Allocatorにも手を加えて、これ まで取得できなかったデータも取れるようにします

105.

新しいMemoryProfiler ざっくり見る Tree表示

106.

新しいMemoryProfiler メモリの状況確認 出来る Memory Map表示

107.

新しいMemoryProfiler リスト表示

108.

新しいMemoryProfiler 複数のsnapshotを 比較するDiff

109.

新機能についてもデバッグ/計測のための機能 もセットで開発をしています

110.

RM Profilerの話 • 2018.2から提供されるパッケージ 「ResourceManager」向けに作成されたProfiler Load/UnloadしたResourceの確認が 出来ます

111.

Entity Debuggerの話 • 2018.1から提供される 「Entity Component System」向けに作成された Debugger 動作しているComponentSystemを 確認出来ます

112.

最後に • より良いパフォーマンスを出すには、まずは計測か ら! • UnityのProfiler/Debugのための機能は随時アップデート しております。 • 今回は直近のアップデートを紹介しましたが、まだま だProfilerではアップデートの予定があるので今後も注 目してください