💭

スタートアップトレースを使ってXamarin.Androidの起動速度を向上させる

2020/12/09に公開2

この記事はXamarin Advent Calendar 2020の9日目の記事です。

Xamarin.Androidの起動が遅いという問題が長年ありましたが、最近はスタートアップトレース (Startup Tracing / Profiled AOT)という機能である程度改善できるようになっています。
この機能は、残念ながら公式ドキュメントに記載されておらず、公式ブログに2件ほど記事がある程度で、あまり浸透してないのかもと思い、日本語の記事を書いてみることにしました。

このスタートアップトレース機能は2種類の方法があり、一つはデフォルトのプロファイルを使用する方法で、もう一つがカスタムのプロファイルを生成してそれを適用する方法です。

まずはどれくらいの効果があるのかを、私の個人開発アプリ「Fithor」で比較してみました。

ライブラリの使用状況はこんな感じです。

比較動画

結果

スタートアップトレース 起動時間 aabサイズ
なし 6.42s 39.4MB
デフォルト 6.90s 61.4MB
カスタム 6.00s 66.7MB

うむ、微妙ですね。
実は比較とかする以前に初めてスタートアップトレースを有効にした時はもっと劇的に早くなったと思ったんですが、まぁプロジェクト構成もその時と比べて変わったし、そういう影響なんだろうと思います。

スタートアップトレースOFFよりスタートアップトレースONのデフォルトプロファイルの方が遅くなっちゃってますが、これは誤差の範囲だと思います。
というより、この結果で重要なことは、スタートアップトレースはただ有効にするだけ(デフォルトプロファイルを使うだけ)ではほとんど効果が出ない場合があるってことだと思います。

カスタムプロファイルを使うことで1秒弱縮まってます。起動速度の1秒はかなり大きいのでこれは是非有効にすべきだと思います。

カスタムプロファイルの作成方法

Androidのプロジェクトのフォルダに移動し以下のコマンドを実行してビルドします。

msbuild /t:BuildAndStartAotProfiling

この時、シミュレータや接続している実機は1つだけの状態にする必要があります。
使わないシミュレータや実機は外しておきましょう。

ビルドが終わりアプリが起動すると完了です。

次に以下のコマンドを実行してプロファイルを生成します。

msbuild /t:FinishAotProfiling xxxxx.csproj  

以下のようなメッセージが表示されれば完了です。

  Summary:
  	Modules:         51
  	Types:        2,261
  	Methods:      9,125
  Going to write the profile to 'custom.aprof'

これでプロジェクトにcustom.aprofが生成されます。

カスタムプロファイルの有効化

まずはスタートアップトレースを有効にします。以下 VS for Mac の例です。

カスタムプロファイルを使う設定はUIには存在しないのでcsprojを直接開いてリリースビルド構成のところに以下の項目を追加します。

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
...
    <AndroidUseDefaultAotProfile>false</AndroidUseDefaultAotProfile>
</PropertyGroup>

同じくcsprojに以下のように、カスタムプロファイルをプロジェクトに追加します。

<ItemGroup>  
    <AndroidAotProfile Include="$(MSBuildThisFileDirectory)custom.aprof" />
</ItemGroup>  

これで設定完了です。

ビルドした際にログに以下のように表示されればカスタムプロファイルは適用されています。

[aot-compiler stdout] Using profile data file '/Users/xxxxx/custom.aprof'

注意事項

カスタムプロファイルを生成するのに adb と シミュレータまたは実機が必要になるため、この工程はCIには組み込めないと思います。
ライブラリや起動ページの構成なんかが大きく変わらない限りは毎回は生成する必要ないと思いますが、定期的にローカルで実行して生成し直す方が良さそうです。

おわりに

Xamarin.Android (Xamarin.Forms Androidも含む) で起動時間を1秒でも縮めたい場合は是非スタートアップトレース カスタムプロファイルを使いましょう!

参考

Discussion

kuremakurema

参考になりました。時間を計測していないので違いは分かりませんが、遅くはならなさそうなので良い感じです。
またAOTコンパイルの時間とapkサイズが大幅に縮小しました。何か不安になりますが動作に問題はないようです。

私の環境では標準のポート9999が確保できなかったので/p:AndroidAotProfilerPort=12345を指定しました。
注意点としてmsbuild /t:BuildAndStartAotProfilingmsbuild /t:FinishAotProfilingの両方でポートを指定する必要があります。

$ msbuild /t:BuildAndStartAotProfiling /p:AndroidAotProfilerPort=12345
$ msbuild /t:FinishAotProfiling xxxxx.csproj /p:AndroidAotProfilerPort=12345

後者のみで指定して色々試したのですが、以下のようなエラーが出ました。
ビルド時にポート番号を埋め込んでるとかみたいです。当たり前と言えば当たり前ですね。

Reading from '127.0.0.1:12345'...
Read total 0 bytes...
EXEC : error : aotprofile-tool: Unable to read profile through local port: 12345.

エラーで検索すると公式のIssueがヒットしますが、解消済みの問題で関係ありません。
エラーメッセージには権限が足りないとかアドバイスされますが、権限も関係ありません。
ファイヤーウォールも私の場合は問題とは無関係だったようです。