メインコンテンツにスキップ

プロファイリング

プロファイリングとは、アプリのパフォーマンス、リソース使用量、および動作を分析して、潜在的なボトルネックや非効率性を特定するプロセスです。アプリがさまざまなデバイスや環境でスムーズに動作するように、プロファイリングツールを利用することをおすすめします。

iOSの場合は、Instrumentsが非常に役立つツールです。Androidの場合は、systraceを使用する方法を学ぶ必要があります。

ただし、まず、開発モードがオフになっていることを確認してください!アプリケーションログに__DEV__ === false, development-level warning are OFF, performance optimizations are ONと表示されるはずです。

systraceを使用したAndroid UIパフォーマンスのプロファイリング

Androidは1万以上の異なる電話をサポートしており、ソフトウェアレンダリングをサポートするように一般化されています。残念ながら、フレームワークアーキテクチャと多くのハードウェアターゲット間で一般化する必要があるため、iOSに比べて無料で得られるものが少なくなっています。しかし、改善できるものがある場合もあります。多くの場合、ネイティブコードのせいではありません!

このジャンプをデバッグする最初のステップは、各16msフレーム中に時間がどこで費やされているかという根本的な質問に答えることです。そのため、systraceと呼ばれる標準のAndroidプロファイリングツールを使用します。

systraceは、標準のAndroidマーカーベースのプロファイリングツールです(Android platform-toolsパッケージをインストールするとインストールされます)。プロファイルされたコードブロックは、開始/終了マーカーで囲まれ、その後カラフルなグラフ形式で視覚化されます。Android SDKとReact Nativeフレームワークの両方が、視覚化できる標準マーカーを提供します。

1. トレースの収集

まず、調査したいスタッタリングが発生するデバイスをUSB経由でコンピューターに接続し、プロファイルするナビゲーション/アニメーションの直前のポイントにします。次のようにsystraceを実行します。

$ <path_to_android_sdk>/platform-tools/systrace/systrace.py --time=10 -o trace.html sched gfx view -a <your_package_name>

このコマンドの簡単な内訳

  • timeは、トレースが収集される時間(秒単位)です。
  • schedgfxviewは、対象となるAndroid SDKタグ(マーカーのコレクション)です。schedは、携帯電話の各コアで実行されているものに関する情報を提供し、gfxはフレーム境界などのグラフィックス情報を提供し、viewは測定、レイアウト、および描画パスに関する情報を提供します。
  • -a <your_package_name>は、アプリ固有のマーカー(特にReact Nativeフレームワークに組み込まれているもの)を有効にします。your_package_nameは、アプリのAndroidManifest.xmlにあり、com.example.appのようになります。

トレースの収集が開始されたら、対象のアニメーションまたはインタラクションを実行します。トレースの最後に、systraceはブラウザで開くことができるトレースへのリンクを提供します。

2. トレースの読み取り

ブラウザ(できればChrome)でトレースを開くと、次のようなものが表示されるはずです。

Example

ヒント

WASDキーを使用して、横移動とズームを行います。

トレースの.htmlファイルが正しく開かない場合は、ブラウザのコンソールで次を確認してください。

ObjectObserveError

Object.observeが最近のブラウザで非推奨になったため、Google Chrome Tracingツールからファイルを開く必要がある場合があります。これを行うには、次の手順に従います。

  • chrome://tracingでChromeのタブを開く
  • ロードを選択
  • 前のコマンドで生成されたhtmlファイルを選択します。
VSyncの強調表示を有効にする

画面の右上にあるこのチェックボックスをオンにして、16msフレーム境界を強調表示します。

Enable VSync Highlighting

上記のスクリーンショットのように、縞模様が表示されるはずです。表示されない場合は、別のデバイスでプロファイリングを試してください。Samsungはvsyncの表示に問題があることが知られていますが、Nexusシリーズは一般的に非常に信頼性があります。

3. プロセスの検索

パッケージ名の一部が表示されるまでスクロールします。この場合、com.facebook.adsmanagerをプロファイリングしていたため、カーネルのスレッド名制限により、book.adsmanagerとして表示されています。

左側には、右側のタイムライン行に対応する一連のスレッドが表示されます。今回の目的では、UIスレッド(パッケージ名またはUIスレッドという名前)、mqt_jsmqt_native_modulesのいくつかのスレッドが重要です。Android 5以降で実行している場合は、Render Threadも重要です。

  • UIスレッド。これは、標準のAndroidの測定/レイアウト/描画が行われる場所です。右側のスレッド名は、パッケージ名(この場合はbook.adsmanager)またはUIスレッドになります。このスレッドに表示されるイベントは、Choreographertraversals、およびDispatchUIに関連する次のようになります。

    UI Thread Example

  • JSスレッド。これは、JavaScriptが実行される場所です。スレッド名は、デバイスのカーネルの協力度合いに応じて、mqt_jsまたは<...>になります。名前がない場合は、JSCallBridge.executeJSCallなどを探して識別します。

    JS Thread Example

  • ネイティブモジュールスレッド。これは、ネイティブモジュールの呼び出し(UIManagerなど)が実行される場所です。スレッド名は、mqt_native_modulesまたは<...>になります。後者の場合、NativeCallcallJavaModuleMethod、およびonBatchCompleteなどを探して識別します。

    Native Modules Thread Example

  • ボーナス:レンダー スレッド。Android L(5.0)以上を使用している場合は、アプリケーションにもレンダー スレッドがあります。このスレッドは、UIの描画に使用される実際のOpenGLコマンドを生成します。スレッド名は、RenderThreadまたは<...>になります。後者の場合、DrawFramequeueBufferなどを探して識別します。

    Render Thread Example

原因の特定

スムーズなアニメーションは、次のようになります。

Smooth Animation

色の変化はそれぞれフレームです。フレームを表示するには、16msの期間が終わるまでにすべてのUI作業を完了する必要があることを覚えておいてください。どのスレッドもフレーム境界近くで動作していないことに注目してください。このようにレンダリングするアプリケーションは、60 FPSでレンダリングしています。

ただし、途切れに気付いた場合は、次のようなものが表示される場合があります。

Choppy Animation from JS

JSスレッドがほぼ常に実行されており、フレーム境界を越えていることに注目してください。このアプリは60 FPSでレンダリングされていません。この場合、問題はJSにあります

次のようなものが表示される場合もあります。

Choppy Animation from UI

この場合、フレーム境界を越えて動作しているのはUIスレッドとレンダースレッドです。各フレームでレンダリングしようとしているUIには、完了するために多くの作業が必要です。この場合、問題はレンダリングされているネイティブビューにあります

この時点で、次のステップを知らせる非常に役立つ情報が得られます。

JavaScriptの問題の解決

JSの問題を特定した場合は、実行している特定のJSで手がかりを探してください。上記のシナリオでは、RCTEventEmitterがフレームごとに複数回呼び出されていることがわかります。上記のトレースからのJSスレッドの拡大図を次に示します。

Too much JS

これは正しくないようです。なぜこんなに頻繁に呼ばれているのでしょうか。それらは実際に異なるイベントなのでしょうか。これらの質問に対する答えは、おそらく製品コードに依存します。多くの場合、shouldComponentUpdateを調べる必要があります。

ネイティブUIの問題の解決

ネイティブUIの問題を特定した場合、通常、2つのシナリオがあります。

  1. 各フレームで描画しようとしているUIは、GPUで多くの作業を必要とするか、
  2. アニメーション/インタラクション中に新しいUIを構築している場合(スクロール中に新しいコンテンツをロードするなど)。

GPUの作業が多すぎる

最初のシナリオでは、UIスレッドやレンダー スレッドが次のように見えるトレースが表示されます。

Overloaded GPU

DrawFrame に費やされた時間がフレームの境界をまたいで長く続いていることに注目してください。これは、GPU が前のフレームからのコマンドバッファを排出するのを待っている時間です。

これを軽減するには、次のようにする必要があります。

  • アニメーション/変換される複雑な静的コンテンツ (例: Navigator のスライド/アルファアニメーション) には、renderToHardwareTextureAndroid の使用を検討してください。
  • ほとんどの場合、フレームごとの GPU 負荷を大幅に増加させる needsOffscreenAlphaCompositing を使用していないことを確認してください。これはデフォルトで無効になっています。

UIスレッドでの新しいViewの作成

2番目のシナリオでは、次のようになります。

Creating Views

まずJSスレッドがしばらく考え込み、次にネイティブモジュールスレッドでいくらかの作業が行われ、その後、UIスレッドでコストのかかる走査が行われていることに注目してください。

インタラクション後まで新しいUIの作成を延期できるか、作成するUIを簡略化できない限り、これを軽減するための簡単な方法はありません。react nativeチームは、メインスレッド外で新しいUIを作成および構成できるようにするインフラストラクチャレベルのソリューションに取り組んでおり、インタラクションをスムーズに続行できるようにします。