1. Simpleperf の概要
Simpleperf は、NDK に含まれている強力なコマンド ライン ツールで、アプリケーションの CPU パフォーマンスの分析に役立ちます。Simpleperf は、パフォーマンスの問題に関連することが多いアプリケーションのホットスポットを見つけて、ホットスポットの原因を分析して修正するのに役立ちます。
コマンド ラインを使用したい場合は、Simpleperf を直接使用できます。Simpleperf は、Mac、Linux、および Windows 用の NDK に含まれる汎用コマンドライン CPU プロファイリング ツールです。
完全なドキュメントを表示するには、まず Simpleperf https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.mdをお読みください。
公式情報:
2. 基本的な動作原理
最新の CPU には、パフォーマンス監視ユニット (PMU) と呼ばれるハードウェア コンポーネントが搭載されています。PMU には、経過した CPU サイクルの数、実行された命令の数、発生したキャッシュ ミスの数などのイベントをカウントするハードウェア カウンターがあります。
Linux カーネルは、これらのハードウェア カウンターをハードウェア パフォーマンス イベントにラップします。さらに、Linux カーネルは、ハードウェアに依存しないソフトウェア イベントとトレースポイント イベントを提供します。Linux カーネルは、simpleperf で使用されるメカニズムである perf_event_open システム コールを通じてこれらをユーザー空間に公開します。
Simpleperf には、統計、記録、レポートという 3 つの主な機能があります。
Stat コマンドは、一定期間にわたってプロファイリングされているプロセスで発生したイベントの数の概要を表示します。仕組みは次のとおりです。
- ユーザー オプションを指定すると、simpleperf は Linux カーネルへのシステム コールを実行することでプロファイリングを有効にします。
- Linux カーネルは、プロファイルされたプロセスにディスパッチするときにカウンターを有効にします。
- プロファイリング後、simpleperf はカーネルからカウンターを読み取り、カウンターの概要をレポートします。
Record コマンドは、一定期間にわたるプロファイリングされたプロセスのサンプルを記録します。仕組みは次のとおりです。
- ユーザー オプションを指定すると、simpleperf は Linux カーネルへのシステム コールを実行することでプロファイリングを有効にします。
- Simpleperf は、simpleperf と Linux カーネルの間にマッピング バッファーを作成します。
- Linux カーネルは、プロファイルされたプロセスにディスパッチするときにカウンターを有効にします。
- 指定された数のイベントが発生するたびに、Linux カーネルはマップされたバッファにサンプルをダンプします。
- Simpleperf はマップ バッファからサンプルを読み取り、stat は perf.data を生成します。
Report コマンドは、「perf.data」ファイルとプロファイリング プロセスで使用されるすべての共有ライブラリを読み取り、どこに時間が費やされたかを示すレポートを出力します。
3. 環境要件
Simpleperf を使用するには、次の環境が必要です。
- 分析するアプリは Android 5.0 以降のデバイスで実行されている必要があります。
- 携帯電話とオペレーティングマシンのUSB接続
- アプリケーションはデバッグ可能である必要があります。セキュリティ制限のため、android::debuggable が true に設定されているアプリケーションのみをプロファイリングできます。(ルート化されたデバイスでは、すべてのアプリをプロファイリングできます。) Android Studio では、これは、リリース ビルド タイプではなく、デバッグ ビルド タイプを使用する必要があることを意味します。
- Python スクリプトを実行できるようにするには、ホスト マシンに次のものが必要です。
-
- Python 2.7以降
- NDK のバージョンは r13b 以降であってはなりません
通常、Android アプリケーションのパフォーマンスをプロファイリングするには、次の 3 つの手順が必要です。
- 申請書を準備します。
- プロファイリング データを記録します。
- データをプロファイリングする分析レポートを生成します。
Simpleperf の入手パス: https://android.googlesource.com/platform/prebuilts/simpleperf/
このページでは、圧縮パッケージを直接ダウンロードでき、対応するNDK (R13~N21) またはマスターのバージョンを選択できます。NDK に対応するバージョンを直接選択することをお勧めします。もちろん、git を使用してリポジトリを直接プルすることもできます。
git clone https://android.googlesource.com/platform/prebuilts/simpleperf
ダウンロードした simpleperf ディレクトリを見ると、そのツールセットにはクライアントとホストが含まれていることがわかります。クライアントは Android システム上で実行され、パフォーマンス データの収集を担当します。ホストは開発マシン上で実行され、データの分析と視覚化を担当します (これらの実行可能ファイルは、ダウンロードした bin フォルダーの android および win/linux の下にあります)。
bin フォルダーに加えて、最上位には多数の .py スクリプト ファイルがあります。これらのスクリプトと設定ファイルは主に公式が作成した絶対確実なスクリプトであり、設定ファイルを設定するだけで、開発マシン上で直接スクリプトを実行し、ワンクリックで最終結果を生成できます。
Python スクリプトは、その機能に基づいて 3 つの部分に分かれています。
- プロファイリング データのログ記録を簡素化するための app_profiler.py などのスクリプト。
- プロファイリング レポートの生成に使用されるスクリプト (report.py、report_html.py、inferno など)。
- プロファイリング データを解析するためのスクリプト (simpleperf_report_lib.py など)。
主なスクリプトは、app_profiler.py と report.py です。
simpleperf の実行ファイルと Python スクリプトは android-ndk\simpleperf に含まれており、その機能は次のとおりです。
- bin/: Android や Windows などの実行可能ファイルと共有ライブラリが含まれます。
- bin/android/${arch}/simpleperf: デバイス上で実行される静的な simpleperf 実行可能ファイル。${arch} は、arm や arm64 などのターゲット デバイスの CPU アーキテクチャです。
- bin/${host}/${arch}/simpleperf: ホスト用の simpleperf 実行可能ファイル。レポート生成のみをサポートします。このうち、${host} は Linux などのホストのオペレーティング システム プラットフォームであり、${arch} は x86_64 などのホストの CPU アーキテクチャです。
- bin/${host}/${arch}/libsimpleperf_report.${so/dylib/dll}: ホストのレポート生成ライブラリ。このうち、${host} はホストのオペレーティング システム プラットフォームを指し、${arch} はホストの CPU アーキテクチャを指します。
- app_profiler.py: プロファイリング データを記録するための Python スクリプト。
- binary_cache_builder.py: データをプロファイリングするためのバイナリ キャッシュを構築するための Python スクリプト。
- report.py: プロファイリング レポートを生成し、標準出力に出力するために使用される Python スクリプト。
- report_html.py: プロファイリング レポートを生成し、HTML ファイルとして出力するために使用される Python スクリプト。
- inferno.sh (Windows プラットフォームでは inferno.bat): フレーム グラフを生成し、HTML ファイルとして出力するためのスクリプト ツール。
- inferno/: インフェルノの実装。inferno.sh によって使用されます。
- pprof_proto_generator.py: プロファイリング データの形式を pprof で使用される形式に変換する Python スクリプト。
- report_sample.py: プロファイリング データの形式を FlameGraph で使用される形式に変換する Python スクリプト。
- simpleperf_report_lib.py: プロファイリング データを分析するためのライブラリ。
スクリプトの主な内容は、構成ファイルを読み取り、adb shell... コマンドを実行することであり、実際にはコマンド ライン入力と本質的に同じです。ただし、直接実行すると、設定ファイルの各設定項目の意味を確認する必要があるだけでなく、予期せぬバグが多数発生する可能性があり、スクリプトの本質ではなくなるため、直接実行することはお勧めしません。 。
4. サポートされているコマンド
debug-unwind コマンド: simpleperf をデバッグするための debug/test dwarf に基づくオフライン アンワインド。
Dump コマンド: simpleperf をデバッグするために perf.data の内容をダンプします。
help コマンド: 他のコマンドのヘルプ情報を出力します。
kmem コマンド: カーネルのメモリ割り当て情報を収集します (Python スクリプトによって置き換えられます)。
list コマンド: Android デバイスでサポートされているすべてのイベント タイプを一覧表示します。
ロギング コマンド: ファイル処理を構成し、分析データを perf.data に保存します。
report コマンド: perf.data 内の分析データをレポートします。
report-sample コマンド: Android Studio での simpleperf の統合をサポートするために、perf.data 内の各サンプルをレポートします。
stat コマンド: プロファイルを処理し、カウンタの概要を出力します。
各コマンドはさまざまなオプションをサポートしており、次の例のようにヘルプ メッセージで確認できます。
# すべてのコマンドをリストします。 $ simpleperf --help # 記録コマンドのヘルプ メッセージを出力します。 $ simpleperf レコード --ヘルプ
5. 運用プロセス
方法 1: adb シェルを使用してモバイル ページの操作を開始する
1.simpleperf ファイルを携帯電話にプッシュします
simpleperf/bin/android ディレクトリには、さまざまなアーキテクチャの Android 上で実行される静的バイナリ ファイルが含まれています。arm ディレクトリでコマンド ウィンドウを開いて、次のコマンドを実行します。
adb プッシュ simpleperf データ/データ/
2. simpleperf を読み取りおよび書き込み可能な実行可能ファイルとして承認します。
adb シェル cd データ/データ/ chmod 777 simpleperf
3. 特定のプロセスまたはスレッドを監視する
./simpleperf レコード -p 4281 (pid または tid) --duration 30 (時間/秒)
読み取り専用パーティションが perf.data を書き込むことができなかったというエラー メッセージが表示されました。
simpleperf E 04-19 15:09:29 4109 4109 Record_file_writer.cpp:47] レコード ファイル 'perf.data' を開けませんでした: 読み取り専用 f
4. -o パラメータを使用して、レコードを保存するパスを設定します。
simpleperf I cmd_record.cpp:729] 29.9851 秒間記録されました。後処理を開始します。 simpleperf I cmd_record.cpp:809] 記録されたサンプル数: 1457。失われたサンプル数: 0。
5. レポートを使用して、perf.data 内の分析データをレポートします。
simpleperf レコード -p 17465--duration 4 -f 1000 -o /data/local/tmp/perf.data --call-graph fp
simpleperf レポート -i /data/perf.data -n --sort dso
simpleperf W 04-19 15:31:17 4564 4564 dso.cpp:274] /data/local/rvdecApp にはシンボル テーブルが含まれていません simpleperf W 04-19 15:31:17 4564 4564 dso.cpp:335] シンボル アドレス/proc/kallsyms はすべてゼロです。可能であれば「echo 0 >/proc/sys/kernel/kptr_restrict」。 コマンドライン: /data/local/tmp/simpleperf record -p 4281 --duration 30 -o /data/perf.data Arch: arm64 イベント: cpu-cycles (type 0、config 0) サンプル: 125526 イベント数: 43633757353 オーバーヘッド サンプル共有オブジェクト 88.93% 106529 /data/local/rvdecApp 8.05% 10560 /system/lib/libc.so 3.01% 8437 [kernel.kallsyms]
–sort パラメータは、結果に表示する列を指定するために使用されます。ここでは dso (動的共有オブジェクト) を 1 つだけ記述したため、結果には「共有オブジェクト」の 1 つの列のみが表示されます。dso の分類によれば、結果は行は 3 行しかありません。
–sort パラメータを追加しない場合、デフォルトで次の列が表示されます: Command、Pid、Tid、Shared Object、Symbol。これは次と同等です。
-- ソート comm、pid、tid、dso、シンボル
- -n パラメータは、この行でヒットしたサンプルの数を示すサンプル列を表示するために使用されます。追加はオプションです。
- ご覧のとおり、予想どおり、時間の 88.93% がテスト済みプログラムに費やされています。
6. アプリ内を見て、機能の割合を確認します。
simpleperf report -i /data/perf.data --dsos /data/local/rvdecApp --sort シンボル
- 結果は次のとおりです。
impleperf W 04-19 15:57:34 5046 5046 dso.cpp:274] /data/local/rvdecApp にはシンボル テーブルが含まれていません simpleperf W 04-19 15:57:34 5046 5046 dso.cpp:335] シンボル アドレス/proc/kallsyms はすべてゼロです。可能であれば「echo 0 >/proc/sys/kernel/kptr_restrict」。 コマンドライン: /data/local/tmp/simpleperf record -p 4281 --duration 30 -o /sdcard/perf.data Arch: arm64 イベント: cpu-cycles (type 0、config 0) サンプル: 106529 イベント数: 38804869540 オーバーヘッド サンプルシンボル 5.06% 5373 rvdecApp[+24380] 4.57% 4890 rvdecApp[+24420] 1.43% 1588 rvdecApp[+13a44] 1.01% 1083 rvdecApp[+21f94] 0.94% 999 rvdecApp[+20188] ...
–dsos パラメーターは、simpleperf の 5 つのフィルターの 1 つであり、指定された動的共有オブジェクトに従ってフィルター処理し、パラメーターで指定された dso 内の結果のみを表示することを意味します。5 つのフィルターはすべて次のとおりです。
–comms: コマンドでフィルターします。例: --comm rvdecApp
–pids: ここに来るには pid を押してください
–tids: tid (スレッド ID) でフィルターします。
–dsos: ライブラリ/実行可能ファイル名によるフィルタリング
–symbols: 関数名でフィルターします。例: --symbols "RVComFunc::getPUMVPredictor(RefBlockInfo*, unsigned int, int, int, unsigned int)"。関数内にスペースがある場合は、スペースを囲む必要があることに注意してください。二重引用符で囲みます。
ご覧のとおり、結果には関数名がありません。これは、rvdecApp がシンボル テーブルのないバージョンであるためです。分析にはシンボル テーブルを備えたアプリを使用できます。
シンボル テーブルを含むアプリの実行可能ファイルは、obj ディレクトリにあります。それを電話機にプッシュし、元の実行可能ファイルを上書きします。
rvdecApp を再実行して perf.data を再収集する必要はなく、分析中にシンボル テーブルで rvdecApp を使用するだけでよいことに注意してください。
先ほどのコマンドも使用します。
./simpleperf report -i /data/perf.data -n --dsos /data/local/rvdecApp --sort シンボル
- 次の結果が得られます。
オーバーヘッド サンプル シンボル 10.45% 5354 RVComFunc::DBFShiftedProcess8x8(unsigned char**, int*, unsigned char*, int, unsigned char*, int, bool, bool, bool, bool, unsigned char) 5.55% 3722 RVComFunc::deblockCUTree ( TCBDataTree*、unsigned char**、unsigned int*、int、int、RefBlockInfo*、int、unsigned char**、int*、unsigned char) 4.49% 3675 RVComFunc::reconstructInterPredictors(TCUData*、unsigned char**、unsigned int *, TRefPicList*, RefBlockInfo*, unsigned int, unsigned int, unsigned int, unsigned int) 2.25% 3518 RVComFunc::deriveDBFStrengthFUbyMotionInfo(unsigned char*, unsigned char*, int, int, RefBlockInfo*, int, int, unsigned char, unsigned char、bool、bool) 2.68% 3320 Decoder::parseBitStream_FrameNew() 2.79% 2927 NEON_DBF_EdgeFilter4_Vertical 2.52% 2651 RVComFunc::DBFShiftedProcessFu(unsigned char**, int*, unsigned char*, int, unsigned char*, int, int, bool, bool, bool, bool, unsigned char) 2.36% 2553 (匿名 ) namespace)::decode_gen_vlc(unsigned long const*, int, (匿名名前空間)::VLC*, int, int) ...
DBFShiftedProcess8x8 関数は最も時間がかかる関数であり、最適化する必要があることがわかります。
方法 2: Linux 環境を使用し、Python スクリプトを使用して操作する
1.app-profiler.pyを実行します。
python app_profiler.py -p com.android.settings
simpleperf ディレクトリに入ると、app-profiler.py を使用して Android アプリケーションをプロファイリングできます。出力パスなどはapp_profiler.py設定ファイルで変更可能
14:47:33,547 [情報] (app_profiler.py:206) プロファイリングを準備します 14:47:33,730 [情報] (app_profiler.py:208) プロファイリングを開始します 14:47:33,806 [情報] (app_profiler.py:244) 実行しますadb cmd: ['adb', 'shell', '/data/local/tmp/simpleperf', 'record', '-o', '/data/local/tmp/perf.data', '-e task- Clock:u -f 1000 -g --duration 10', '--log', 'info', '--app', 'com.afmobi.boomplayer'] simpleperf I cmd_record.cpp:696] 9.96625 秒間記録されました。後処理を開始します。 simpleperf W dso.cpp:446] /vendor/lib64/egl/libGLES_mali.so にはシンボル テーブルが含まれていません simpleperf W dso.cpp:446] /vendor/lib64/hw/[email protected] -mediatek.so にはシンボル テーブルが含まれていません simpleperf W dso.cpp:446] /data/app/~~EKnZoTKaDLH3FYfxteqUvg==/com.google.android.trichromelibrary_541411734-ozjH9V7NI4SknoCd0t2CPg==/base.apk!/lib/arm64-v8a/libmonochrome_64.so にはシンボルが含まれていませんtable 14:47:45,689 [情報] (app_profiler.py:211) プロファイリング データを収集します 14:47:46,745 [情報] (binary_cache_builder.py:184) binary_cache の現在のファイルを使用: binary_cache\apex\com.android.runtime\lib64\bionic\libc.so 14:47:46,770 [情報] (binary_cache_builder.py:184) binary_cache の現在のファイルを使用: binary_cache\vendor\lib64\ libged.so simpleperf W dso.cpp:446] /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/lib/arm64/libmmkv.so にはシンボル テーブル simpleperf Iが含まれていませんcmd_record.cpp:771] 記録されたサンプル数: 8647。失われたサンプル数: 0。 14:47:46,800 [情報] (binary_cache_builder.py:184) binary_cache の現在のファイルを使用します: binary_cache\vendor\lib64\egl\libGLES_mali.so 14:47:46,835 [情報] (binary_cache_builder.py:184) 現在の ファイルを使用しますbinary_cache 内: binary_cache\system\lib64\libEGL.so 14:47:46,867 [情報] (binary_cache_builder.py:184) binary_cache 内の現在のファイルを使用します: binary_cache\system\lib64\libhwui.so 14:47:46,888 [情報] (binary_cache_builder.py:184) binary_cache で現在のファイルを使用します: binary_cache\system\lib64\libutils.so 14:47:46,913 [情報] (binary_cache_builder.py:184) binary_cache で現在のファイルを使用します: binary_cache\system\lib64\libgui.so 14:47:46,992 [情報] (binary_cache_builder.py:184) binary_cache で現在の 14:47:46,932 [情報] (binary_cache_builder.py:184) binary_cache 内の現在のファイルを使用します: binary_cache\system\lib64\libnativewindow.so ファイルを使用します: binary_cache\system\framework\arm64\boot-framework.oat 14:47:47,069 [情報] (binary_cache_builder.py:184) binary_cache 内の現在のファイルを使用します: binary_cache\apex\com.android.art\lib64\libart.so 14:47:47,130 [情報] (binary_cache_builder.py:184) binary_cache の現在のファイルを使用します: binary_cache\system\framework\arm64\boot.oat 14:47:47,159 [情報] (binary_cache_builder.py:184) 現在の ファイルを使用しますbinary_cache 内: binary_cache\system\lib64\libandroid_runtime.so 14:47:47,179 [情報] (binary_cache_builder.py:184) binary_cache 内の現在のファイルを使用します: binary_cache\system\bin\app_process64 14:47:47,206 [情報] (binary_cache_builder.py:184) binary_cache の現在のファイルを使用します: binary_cache\apex\com.android.vndk.v31\lib64\libhidlbase.so 14:47: 47,230 [情報] (binary_cache_builder .py:184) binary_cache 内の現在のファイルを使用します: binary_cache\system\lib64\libhidlbase.so 14:47:47,260 [情報] (binary_cache_builder.py:184) binary_cache 内の現在のファイルを使用します: binary_cache\system\lib64\[email protected] 14: 47:47,301 [情報] (binary_cache_builder.py :184) binary_cache 内の現在のファイルを使用します: binary_cache\system\lib64\libui.so
2. report_html.py スクリプトを実行してレポートを分析し、出力します。
Pythonレポート_html.py
simpleperf W dso.cpp:448] /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/lib/arm64/libmmkv.so からのシンボルの読み取りに失敗しました: ファイルがありません見つかりました Cmdline: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task- Clock:u -f 1000 -g --duration 10 --app com.afmobi.boomplayer Arch : arm64 イベント: task-lock:u (タイプ 1、構成 1) サンプル: 8647 イベント数: 8647000000 オーバーヘッド共有オブジェクト Pid 27.69% /system/lib64/libhwui.so 31183 17.32% /apex/com.android.art/lib64/libart.so 31183 9.06% /apex/com.android.runtime/ lib64/bionic/libc.so 31183 8.60% /vendor/lib64/egl/libGLES_mali.so 31183 8.50% /system/framework/arm64/boot-framework.oat 31183 4.75% /data/ app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/oat/arm64/base.odex 31183 3.05% /system/framework/arm64/boot.oat 31183 2.67% /system/lib64/libandroidfw.so 31183 2.58% [JIT アプリキャッシュ] 31183 1.78% /system/lib64/libgui.so 31183 1.58% /data/app/~~EKnZoTKaDLH3FYfxteqUvg==/com。 google.android.trichromelibrary_541411734-ozjH9V7NI4SknoCd0t2CPg==/base.apk!/lib/arm64-v8a/libmonochrome_64.so 31183 1.02% /system/lib64/libinder.so 31183 0.75% /apex/com.android.art/lib64/libart-compiler.so 31183 0.74% /system/lib64/libminikin。それで 31183 0.73% /system/lib64/libz.so 31183 0.68% /system/lib64/libsqlite。それで 31183 0.65% /system/lib64/libutils.so 31183 0.64% /system/lib64/libjpeg.so 31183 0.53% /apex/com.android.conscrypt/lib64/libcrypto.so 31183 0.43% /apex/com.android.i18n/lib64/libicuuc.so 31183 0.39% /apex/com.android.runtime/ビン/リンカー64 31183 0.39% /system/framework/arm64/boot-core-libart.oat 31183 0.36% /system/lib64/libc++.so 31183 0.27% /system/ lib64/libandroid_runtime.so 31183 0.25% /system/framework/arm64/boot-okhttp.oat 31183 0.24% [vdso] 31183 0.22% /apex/com.android.conscrypt/lib64/libssl.so 31183 0.21% /system/lib64/libcutils.so 31183 0.21% /system/lib64/ libui.so 31183 0.19% /apex/com.android.vndk.v31/lib64/libgralloctypes.so 31183 ... ..
3. コールグラフのレポートを生成し、標準出力に出力します。
コマンドライン: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task- Clock:u -f 1000 -g --duration 10 --app com.afmobi.boomplayer Arch: arm64 イベント: task- Clock:u (type 1、config 1) サンプル: 10841 イベント数: 10841000000 Children Self Command Pid Tid Shared Object Symbol 66.11% 0.00% RenderThread 31183 11235 /apex/com.android.runtime/lib64/bionic/libc .so __start_thread | -- __start_thread | -- __pthread_start(void*) android::Thread::_threadLoop(void*) android::uirenderer::renderthread::RenderThread::threadLoop() |--0.01%-- [関数内ヒット] | |--99.96%-- android::uirenderer::WorkQueue::process() | |--0.03%-- [関数でヒット] | | | |--99.94%-- std::__1::__function::__func<android::uirenderer::renderthread::DrawFrameTask::postAndWait()::$_0, std::__1::allocator<android::uirenderer ::renderthread::DrawFrameTask::postAndWait()::$_0>, void ()>::operator()() (.c1671e787f244890c877724752face20) | | |--0.01%-- [関数でヒット] | | | | | |--86.61%-- android::uirenderer::renderthread::CanvasContext::draw() | | | |--0.11%-- [関数でヒット] | | | | | | | |--77.75%-- android::uirenderer::skiapipeline::SkiaOpenGLPipeline::draw(android::uirenderer::renderthread::Frame const&, SkRect const&, SkRect const&, android::uirenderer::LightGeometry const&, android: :uirenderer::LayerUpdateQueue*、android::uirenderer::Rect const&、bool、android::uirenderer::LightInfo const&、std::__1::vector<android::sp<android::uirenderer::RenderNode>、std ::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, android::uirenderer::FrameInfoVisualizer*) | | | | |--0。 | | | | | | | | | |--58.87%-- android::uirenderer::skiapipeline::SkiaPipeline::renderFrame(android::uirenderer::LayerUpdateQueue const&, SkRect const&, std::__1::vector<android::sp<android::uirenderer ::RenderNode>, std::__1::allocator<android::sp<android::uirenderer::RenderNode> > > const&, bool, android::uirenderer::Rect const&, sk_sp<SkSurface>, SkMatrix const&) | | | | | | | | | | | |--86.22%-- android::uirenderer::skiapipeline::SkiaPipeline::renderFrameImpl(SkRect const&, std::__1::vector<android::sp<android::uirenderer::RenderNode>, std::__1 ::allocator<android::sp<android::uirenderer::RenderNode> > > const&, | | | | | | |--0.12%-- [関数でヒット]
4. フレームダイアグラムの表示
フレームグラフを表示するには、まずコールグラフを記録する必要があります。フレームグラフは、 report_html.py によりFlamegraphタグ内に表示されます。inferno.bat を直接ダブルクリックしてフレーム グラフを表示することもできます。
GitHub - brendangregg/FlameGraph: Stack Trace Visualizerを使用してフレーム グラフを構築することもできます。Perl がインストールされていることを確認してください。
$ git clone https://github.com/brendangregg/FlameGraph.git $ python report_sample.py --symfs binary_cache >out.perf $ FlameGraph/stackcollapse-perf.pl out.perf >out.folded $ FlameGraph/flamegraph.pl out.folded >a.svg
ブラウザで開くと、次のように解析されたフレーム グラフを確認できます。
- 上のフレーム グラフから、netd が実行した内容を確認できるため、それを netd の同僚に引き渡して追跡を続けることができます。
Y 軸は呼び出しスタックを表し、各レベルが関数になります。呼び出しスタックが深くなるほど、炎は高くなります。実行中の関数が一番上にあり、その親関数がその下にあります。
X 軸はサンプル数を表します。関数が X 軸上でより広い幅を占める場合は、より多くの回数サンプリングされたこと、つまり実行に時間がかかったことを意味します。X 軸は時間を表しているのではなく、すべての呼び出しスタックがマージされ、アルファベット順に並べられていることに注意してください。
フレーム グラフは、どのトップレベル関数が最大の幅を占めるかを確認するものです。「プラトー」がある場合は、関数にパフォーマンスの問題がある可能性があることを意味します。
フレーム グラフは CPU のビジー度を示すため、色には特別な意味はなく、通常は暖色が選択されます。
フレーム グラフの使用方法の詳細については、「フレーム グラフの読み方」を参照してください。- Ruan Yifeng のブログ
6. ヒントとコツ
Simpleperf を使い始めたばかりの場合、試してみるとよい特に便利なコマンドをいくつか紹介します。その他のコマンドとオプションについては、「 Simpleperf コマンドとオプションのリファレンス 」を参照してください。
1. 実行時間が最も長い共有ライブラリを見つけます。
このコマンドを実行すると、(CPU サイクルに基づいて) 実行時間の最大の割合を占める .so ファイルを確認できます。プロファイリング セッションを開始するときに、最初にこのコマンドを実行することをお勧めします。
simpleperf レポート --sort dso
例:
コマンドライン: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 イベント: cpu-cycles (type 0、config 0) サンプル: 3294 イベント数: 1193555038 オーバーヘッド サンプル共有オブジェクト 57.18% 2114 [kernel.kallsyms] 8.01% 225 /system/lib64/libhwui.so 7.16% 192 /apex/com.android.runtime/lib64/bionic/libc.so 5.96% 169 /vendor/lib64/egl/libGLES_mali。したがって 4.73% 125 /apex/com.android.art/lib64/libart.so 4.55% 128 /system/framework/arm64/boot-framework.oat 3.84% 96 /system/lib64/libgui.so 1.39% 44 /system/フレームワーク/arm64/boot.oat 1.06% 28 /system/lib64/libutils.so 0.74% 24 /system/ lib64/libbinder.so 0.43% 12 /system/lib64/libui.so 0.42% 10 /system/lib64/libminikin.so 0.34% 10 /system/lib64/libandroid_runtime.so 0.34% 10 /system/lib64/libc++.so 0.29% 7 /apex/ com.android.vndk.v31/lib64/libgralloctypes.so 0.27% 8 /vendor/lib64/egl/libGLES_meow.so 0.27% 6 /system/framework/arm64/boot-mediatek-framework.oat 0.24% 8 [JIT アプリ キャッシュ] ] 0.22% 7 /system/lib64/libEGL.so 0.19% 5 /vendor/lib64/libged.so 0.19% 6 /apex/com.android.vndk.v31/lib64/libhidlbase.so 0.18% 4 不明 0.16% 5 /システム/lib64/libcutils.so 0.15% 2 /apex/com.android.i18n/lib64/libicuuc.so 0.15% 5 /system/framework/arm64/boot-core-libart.oat ...................
2. 実行時間が最も長い関数を見つける
最も実行時間のかかる共有ライブラリを特定したら、このコマンドを実行して、.so ファイルの関数の実行に費やされた時間の割合を確認できます。
simpleperf レポート --dsos library.so --sort シンボル
例:
simpleperf E command.cpp:59] 不明なオプション -dsos。「simpleperf ヘルプ レポート」を試してください。 1|TECNO-KI7:/ # simpleperf レポート -i /data/perf.data --dsos [kernel.kallsyms] --sort シンボル Cmdline: /system/bin/simpleperf record -p 10167 --duration 5 -o /data /perf.data アーチ: arm64 イベント: cpu-cycles (タイプ 0、構成 0) サンプル: 2114 イベント数: 682442263 オーバーヘッド シンボル 8.22% _raw_spin_unlock_irqrestore 6.87% __blockdev_direct_IO 6.72% get_user_pages_fast 6.61% dio_bio_complete 4.13 % mem block_start_of_DRAM 3.97 % el0_da 3.71% blk_queue_split 3.39 % iov_iter_fault_in_readable 2.72% _raw_spin_unlock_irq 2.30% fscrypt_mergeable_bio 2.29% el0_svc_common 2.23% free_unref_page_list 2.02% queue_work_on 1.98% mod_layed_work_on 1.83% blk_crypto_submit_bio 1.79% clear_page 1.68% _mtk_btag_pidlog_set_pid 1.4 7% get_page_from_freelist 1.35% f2fs_is_valid_blkaddr 1.18% fscrypt_generate_dun 1.02% __save_stack_trace 0.97% pagecache_get_page 0.95% __handle_speculative_fault 0.82 % depot_save_stack 0.80% f2fs_map_blocks 0. 73% __rcu_read_unlock 0.67% __pi_memset 0.64% f2fs_wait_on_block_writeback 0.56% __rcu_read_lock 0.54% kmem_cache_alloc
3. スレッドに費やされた時間の割合を求める
.so ファイルの実行時間は、複数のスレッドに分散される可能性があります。このコマンドを実行すると、各スレッドが費やした時間の割合を確認できます。
simpleperf レポート --sort tid,comm
例:
コマンドライン: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 イベント: cpu-cycles (type 0、config 0) サンプル: 3294 イベント数: 1193555038 オーバーヘッド Tid コマンド 42.01 % 12182 スレッド 4 29.48% 11834 レンダースレッド 16.96% 10167 com.andromeda.androbench2 6.04% 11853 mali-cmar-backe 2.70% 11876 バインダー:10167_4 1.24% 11854 ged-swd 0.67% 118 44 マリ・メム・パージ 0.62% 12087 バインダー: 10167_6 0.26% 11968 バインダー:10167_2 0.01% 11820 Jit スレッド プール 0.00% 11824 FinalizerWatchd 0.00% 11859 GPU 完了
4.オブジェクトモジュールの検索に費やした時間の割合
実行時間の大部分を費やしているスレッドを見つけたら、このコマンドを使用して、それらのスレッド上で最も長い実行時間を費やしているオブジェクト モジュールを分離できます。
simpleperf レポート --tids threadID --sort dso
例:
コマンドライン: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 イベント: cpu-cycles (type 0、config 0) サンプル: 1457 イベント数: 501433272 オーバーヘッド共有オブジェクト 96.72 % [kernel.kallsyms] 2.80% /apex/com.android.runtime/lib64/bionic/libc.so 0.33% /apex/com.android.art/lib64/libart.so 0.08% /vendor/lib/modules/memfusion .ko 0.07% /system/lib64/libutils.so
5. 関数呼び出しの相関関係を理解する
コール グラフは、セッションのプロファイリング中に Simpleperf によって記録されたスタック トレースを視覚的に表現します。
report -g コマンドを使用して呼び出しグラフを出力し、どの関数が他の関数によって呼び出されているかを確認できます。これは、関数自体が遅いのか、それとも関数が呼び出す 1 つ以上の関数が遅いのかを判断するのに役立ちます。
Python スクリプト report.py -g を使用して、関数を表示する対話型ツールを起動することもできます。各関数をクリックすると、そのサブ関数にかかる時間を確認できます。
simpleperf レポート -g
例:
TECNO-KI7:/ # simpleperf report -g simpleperf E Record_file_reader.cpp:83] レコード ファイル 'perf.data' を開けませんでした: そのようなファイルまたはディレクトリはありません 1|TECNO-KI7:/ # simpleperf report -i /data/perf .data -g コマンドライン: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data Arch: arm64 イベント: cpu-cycles (type 0、config 0) サンプル: 3294 イベント数: 1193555038 子セルフコマンド Pid Tid 共有オブジェクト シンボル 3.93% 3.93% Thread-4 10167 12182 [kernel.kallsyms] __blockdev_direct_IO 3.84% 3.84% スレッド 4 10167 12182 [kernel.kallsyms] get_user_pages_fast 3.78% 3.78% スレッド 4 10167 12182 [kernel.kallsyms] dio_bio_complete 2.55% 2.55% mali-cmar-backe 10167 11853 [カーネル.kallsyms] _raw_spin_unlock_irqrestore 2.36% 2.36 % スレッド 4 10167 12182 [kernel.kallsyms] memblock_start_of_DRAM 2.27% 2.27% スレッド 4 10167 12182 [kernel.kallsyms] el0_da 2.12% 2.12 % スレッド 4 10167 12182 [kernel.kallsyms] blk_queue_split 1.94% 1.94% スレッド 4 10167 12182 [kernel.kallsyms] iov_iter_fault_in_readable 1.31% 1.31% スレッド 4 10167 12182 [kernel.kallsyms] fscrypt_mergeable_bio 1.27% 1.27% スレッド 4 10167 12182 [ kernel.kallsyms] free_unref_page_list 1.15% 1.15% レンダースレッド10167 11834 [kernel.kallsyms] queue_work_on 1.15%1.15%スレッド4 10167 12182/apex/com.android.runtime/lib64/bionic/libc.soメムセット 1.13%1.13%スレッド4 10167 1.05% 1.05% スレッド 4 10167 12182 [kernel.kallsyms] blk_crypto_submit_bio 1.02% 1.02% スレッド 4 10167 12182 [kernel.kallsyms] clear_page 1.01% 1.01% RenderThread 10167 11834 [kernel.kallsyms] ] _raw_spin_unlock_irqrestore 0.96% 0.96% スレッド-4 10167 12182 [kernel.kallsyms] _mtk_btag_pidlog_set_pid 0.77% 0.77% Thread-4 10167 12182 [kernel.kallsyms] f2fs_is_valid_blkaddr 0.76% 0.76% RenderThread 10167 11834 /apex/com. android.runtime/lib64/bionic/libc.so __vfprintf 0.70% 0.70% RenderThread 10167 11834 [kernel.kallsyms] _raw_spin_unlock_irq 0.68% 0.68% スレッド 4 10167 12182 [kernel.kallsyms] fscrypt_generate_dun 0.67% 0.67% スレッド 4 10167 12182 [ kernel.kallsyms] get_page_from_freelist 0.64% 0.64% レンダースレッド 10167 11834 [kernel.kallsyms] el0_svc_common 0.62% 0.62% Thread-4 10167 12182 [kernel.kallsyms] _raw_spin_unlock_irqrestore 0.58% 0.58% スレッド 4 10167 12182 [kernel.kallsyms] __save_stack_trace 0.55% 0.55% スレッド 4 10167 12182 [kernel.kallsYSms] pagecache_get_page 0.54% 0.54% com.andromeda.androbench2 10167 1 0167 /apex/com.android.art/ lib64/libart.so ExecuteNterpImpl 0.51% 0.51% スレッド 4 10167 12182 [kernel.kallsyms] __handle_speculative_fault 0.46% 0.46% スレッド 4 10167 12182 [kernel.kallsyms] f2fs_map_blocks 0.45% 0.45% レンダースレッド 10167 11834 /apex/com.android.runtime/lib64/bionic/libc.so scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)> Rigin, unsigned long, bool) 0.44% 0.44% レンダースレッド10167 11834 /system/lib64/libgui.so @plt 0.41% 0.41% スレッド 4 10167 12182 [kernel.kallsyms] depot_save_stack 0.36% 0.36% スレッド 4 10167 12182 [kernel.kallsyms] f2fs_wait_on_block_writeback 0。 36% 0.36% スレッド-4 10167 12182 [kernel.kallsyms] _raw_spin_unlock_irq 0.34% 0.34% スレッド 4 10167 12182 [kernel.kallsyms] __rcu_read_unlock 0.34% 0.34% com.andromeda.androbench2 10167 10167 [kernel.kallsyms] _raw_spin_unlock_irq 0.32% 0.32% スレッド 4 101 67 12182 [kernel.kallsyms] __pi_memset 0.31% 0.31 % Thread-4 10167 12182 [kernel.kallsyms] kmem_cache_alloc 0.31% 0.31% com.andromeda.androbench2 10167 10167 /apex/com.android.art/lib64/libart.so artAllocStringFromCharsFromCodeRegionTLAB 0.26% 0.26% mali-cmar-backe 10167 11853 [kernel.kallsyms] el0_svc_common 0.26% 0.26% RenderThread 10167 11834 /apex/com.android.runtime/lib64/bionic/libc.so 書き込み 0.25% 0.25% Thread-4 10167 12182 [kernel.kallsyms] pte_map_lock ......
6. プロファイルされたプログラムまたはシステム内の生のイベント カウンター情報を取得する
simpleperf stat は、プロファイリングされたプログラムまたはシステム内の生のイベント カウンター情報を取得するために使用されます。オプションを渡すことで、使用するイベント、監視するプロセス/スレッド、監視する時間、および印刷の間隔を選択できます。
パフォーマンス カウンター統計: # countevent_name # count / runtime 17,839,958,825 cpu-cycles # 1.758283 GHz 6,411,685,476 stoped-cycles-frontend # 632.274 M/sec 5,413,391,502 stoped-cycles-backend # 534.113 M/sec 11,755, 131,810 命令 # 1.160 G/秒 1,409,829,788 ブランチ-命令数 # 139.262 M/秒 171,458,771 ブランチミス # 16.946 M/秒 10070.704634(ms) タスククロック # 1.006817 CPU 使用数 7,210 コンテキストスイッチ # 716.330 /秒 94,430 ページフォールト # 9.387 K/秒 合計テスト時間: 10.002513秒。
7. 参考資料
[Simpleperf] Android CPU解析・パフォーマンス最適化ツール_android perf_Yngz_Miaoのブログ - CSDNブログ
プロファイル ツール シリーズ 4: simpleperf_old_man のブログ - CSDN ブログ
Simpleperf を使用したネイティブ コードのパフォーマンスの分析 | WolfcsTech
フレームグラフの読み方は?- Ruan Yifeng のブログ
シンプルパーフ | Android NDK | Android 開発者
Simpleperf コマンドとオプションのリファレンス ドキュメント | Android NDK | Android 開発者