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

 

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


まず、コードは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 ++コードは図のように

どちらも関数の定義を生成することがわかりますが、違いのは:

(1)マクロ定義は関数定義のコードを削除しますが、コールサイトでのパラメーター転送は最適化されないため、関するコールコストを完全に排除することはできません。

(2)条件付きコンパイルは、関数のコールステートメントを直接削除し、関するコールオーバーヘッドが生成されなくなりますが、関数定義のコードはそのまま残ります。


UWA公式サイト:https://jp.uwa4d.com

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

UWA公式Q&Aコミュニティ(中国語注意):https://answer.uwa4d.com