見出し画像

C#コンパイルの最適化

今回の主な話題:C#コンパイルの最適化、IPAパッケージサイズの問題、Unityパッケージのスピードアップ、AssetBundleのインクリメンタルパッケージ化。


アセット管理

Q1: 現在、プロジェクトのAPKサイズは約120MBで、パッケージ化の平均時間は20〜25分です。Build中のほとんどの時間は「Building Scene0」と「Building additional assets」二パートにかかります。Unityはこれら2つの段階で一体何をしていますか?この段階で時間を節約する方法はありますか?また、ハードウェアから考える場合、パッケージ速度を効果的に向上させる方法は?ハードディスクのR/W速度とCPUのパフォーマンスを向上させることに、どのようなメリットがもたらされますか?

私たちはAssetBundleの方式を使っています。現在、600MBくらいのパッケージ、アセットをあまり変更しない場合、Androidパッケージは約10分で出来ますが、前には7〜8分で十分でした。C#コードを変更しません、ただのPatchなら5〜7分くらいで出来ます。

私たちが使用しているAndroidパッカーの価格は約150,000です。これには複数のCPUが搭載されており、シングルコアCPUのパフォーマンスが可能な限り高いことが保証されています。SDDが必要であり、その他は不要です。

使っているCPUは:Intel(R)Xeon(R)CPU E5-2683 v3 @ 2.00GHz 2.00 GHz

テクスチャ圧縮についても注意すべき点があります。以前はテクスチャ圧縮によってよく苦しさめていました、高品質は遅すぎます。後で、DevとPubのバージョンを区別しました。Devバージョンはローカルテクスチャ圧縮にFastを使用し、公開に使用されるPubバージョンは最高品質を使用します。速度は相当早くなりました〜アーティストに多くのテクスチャ変更がある場合でも、Devバージョンはすぐにパッケージ出来ます。

私はずっと前にGithubでこれを見つけました。
pvrtextool_wrapper:https://github.com/fxgames/pvrtextool_wrapper

Unityのパッケージ化はpvrtextoolをコールします。このwrapperで元のプログラムを置き換えますと、開発バージョンの 圧縮品質を強制的に高速モードに設定でき、テクスチャ圧縮品質パラメーターを変えずに大量の時間を節約できます。Mac Proが高すぎると思っている方は、この方法を試すことができます。

Building SceneはUnityのパッケージシーンアセットであり、Building additional assetsはUnityがResourcesをパッケージする中のアセットであります。私たちのプロジェクトは600 MBに近く、毎回パッケージ化には50分以上かかるため、悲惨です。下記の方法をやってみられます:
1)AssetBundleの形式ですべてのアセットを使用します。初回以外、次回からパッケージされたのは変更と増分のあるアセットのみです。なぜなら、Resourcesの毎回の出版はアセットを再びパッケージしますからです。これで変更されていないアセットのパッケージ化の時間コストを節約出来ます。
2)良質なコンピューターを作り、CPUをより強いCPUに変え、ハードディスクをSSDに交換します。

上記の2つのポイントにより、パッケージを出す時間を節約できます。これも、弊社現在使用している方法です。

アセット管理

Q2:パッケージ化を二回しました、どちらのファイルも変更されていませんが、AssetBundleの内容は変更されました。その原因は、そこに含まれるスクリプトの内容に違いがあるように感じます。Manifestファイルには、CRCとAssetFileHashに変更がありますと表示しています。ファイルはもうUWA Q&A公式Webサイトにアップロードされています。最初のパッケージは完全パッケージで、二番目のパッケージは増分パッケージです。

完全パッケージの流れは下記のように:
1、Revertアセット
2、 すべての BundleNameのアセットをClearします
3、規則によって全体のBundleNameを設定します
4、 BuildPipeline.BuildAssetBundles(outputPath, abBuilds, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);を使用してパッケージします
5、ファイルに対してBundleNameのマッピングテーブルを生成します

増分パッケージの流れは下記のように:
1、Revertアセット
2、 すべての BundleNameのアセットをClearします
3、マッピングテーブルによってアセットBundleNameを設定します
4、規則によって他のアセットのBundleNameを設定します
5、BuildPipeline.BuildAssetBundles(outputPath, abBuilds, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);を使用してパッケージします
6、ファイルに対してBundleNameのマッピングテーブルを生成します

主な問題は、パッケージする前にUIのPrefabを事前処理すると、一部のコントロールにスクリプトコンポーネントを追加したことが分かりました。この変更されたPrefabはアップロードされないため、毎回にこの操作を行います。毎回追加されるスクリプトコンポーネントに割り当てられるFileIdは異なりますから、毎回異なるファイルになります。チェックしたときにこの部分が無視されました。

また、Unity 5.x以降のBuildAssetBundleOptions.DeterministicAssetBundleがデフォルトのオプションであり、特に追加する必要がないことがUnity公式に確認されました。

その他

Q3:出力されるAppStore.ipaがDevelopment.ipaより相当大きいです。なぜこれが発生するのか理解したいと思います。

出力環境:
xcode:9.2
unity:5.6.3p2

データのスクリーンショット:

画像1

画像2

まず、コードはswift + obj-cメソッドを使用し、エクスポート時にALWAYS_EMBED_SWIFT_STANDARD_LIBRARIESがYesに設定されます。スクリーンショットからわかるのは、主にはAppStoreがDevelopmentよりSwiftSupportの内容を増加します。私がパッケージしたAppStore.ipaはDevelopment.ipaより約50MB大きくなっています。 この問題をどのように回避できますか?

AppStoreパッケージにはデフォルトでsymbolsを添付しており、クラッシュログをシンボル化するために使用され、アップロード後に削除されます。最終、ユーザーがダウンロードしますのはこのIPAのサイズではありません。

その他

Q4:C#に一つの関数内容がマクロ定義で囲まれ、コンパイル時に空き関数になりますが、外部からのコールがあり、コンパイル時にこのコールを最適化しませんか?たとえば、入力パラメーターは、いくつかの関数コールを行ってから戻り値を渡すことです。この操作のコストはそのままありますが、定数を入れば、コンパイルされて最適化されますか?


コンパイラーは、マクロでラップしたコードのみを最適化し、対応するマクロは定義されません。

例えば:
if UNITY_EDITOR
Debug.Log(“hello uwa”);
else if UNITY_iOS
Debug.Log("good uwa");
endif
if UNITY_EDITORにのはエディターでのみ有効になり、パッケージ化後に最適化されます。

[Conditional]

上記の回答によると、IL2CPPでマクロ定義と条件付きコンパイルの違いを測定しました。コードは下記のように。
コンパイル後に生成されるC ++コードは図のように

画像3

画像4

どちらも関数の定義を生成することがわかりますが、違いのは:
(1)マクロ定義は関数定義のコードを削除しますが、コールサイトでのパラメーター転送は最適化されないため、関するコールコストを完全に排除することはできません。
(2)条件付きコンパイルは、関数のコールステートメントを直接削除し、関するコールオーバーヘッドが生成されなくなりますが、関数定義のコードはそのまま残ります。


UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析最適化ソリューション及びコンサルティングサービスを提供している会社でございます。

UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com

この記事が気に入ったらサポートをしてみませんか?