Detaillierte Verwendung von Simpleperf

1. Einführung in Simpleperf

Simpleperf ist ein leistungsstarkes Befehlszeilentool, das im NDK enthalten ist und uns bei der Analyse der CPU-Leistung unserer Anwendung helfen kann. Simpleperf kann uns dabei helfen, Anwendungs-Hotspots zu finden, die häufig mit Leistungsproblemen zusammenhängen, sodass wir die Quelle der Hotspots analysieren und beheben können.

Wenn Sie lieber die Befehlszeile verwenden möchten, können Sie Simpleperf direkt verwenden. Simpleperf ist ein allgemeines Befehlszeilen-CPU-Profilierungstool, das im NDK für Mac, Linux und Windows enthalten ist.

Um die vollständige Dokumentation anzuzeigen, lesen Sie bitte zuerst Simpleperf https://android.googlesource.com/platform/system/extras/+/master/simpleperf/doc/README.md .

Offizielle Informationen:

2. Grundlegendes Funktionsprinzip

Moderne CPUs verfügen über eine Hardwarekomponente namens Performance Monitoring Unit (PMU). Die PMU verfügt über Hardware-Zähler, die Ereignisse zählen, z. B. wie viele CPU-Zyklen vergangen sind, wie viele Anweisungen ausgeführt wurden oder wie viele Cache-Fehler aufgetreten sind.

Der Linux-Kernel verpackt diese Hardwareindikatoren in Hardware-Leistungsereignisse. Darüber hinaus stellt der Linux-Kernel hardwareunabhängige Softwareereignisse und Tracepoint-Ereignisse bereit. Der Linux-Kernel stellt diese über den Systemaufruf perf_event_open, den von simpleperf verwendeten Mechanismus, dem Benutzerbereich zur Verfügung.

Simpleperf hat drei Hauptfunktionen: Statistik, Aufzeichnung und Bericht.

Der Befehl „Stat“ gibt eine Zusammenfassung darüber, wie viele Ereignisse in dem Prozess aufgetreten sind, der über einen bestimmten Zeitraum hinweg profiliert wird. So funktioniert das:

  1. Bei gegebenen Benutzeroptionen ermöglicht simpleperf die Profilerstellung durch die Ausführung eines Systemaufrufs an den Linux-Kernel.
  2. Der Linux-Kernel aktiviert Zähler beim Versenden an einen profilierten Prozess.
  3. Nach der Profilerstellung liest simpleperf die Zähler aus dem Kernel und meldet eine Zusammenfassung der Zähler.

Der Befehl „Aufzeichnen“ zeichnet Stichproben des profilierten Prozesses über einen bestimmten Zeitraum auf. So funktioniert das:

  1. Bei gegebenen Benutzeroptionen ermöglicht simpleperf die Profilerstellung durch die Ausführung eines Systemaufrufs an den Linux-Kernel.
  2. Simpleperf erstellt einen Zuordnungspuffer zwischen simpleperf und dem Linux-Kernel.
  3. Der Linux-Kernel aktiviert Zähler beim Versenden an einen profilierten Prozess.
  4. Jedes Mal, wenn eine bestimmte Anzahl von Ereignissen auftritt, speichert der Linux-Kernel Samples in einem zugeordneten Puffer.
  5. Simpleperf liest Beispiele aus dem Kartenpuffer und stat generiert perf.data.

Der Befehl „Report“ liest die Datei „perf.data“ und alle gemeinsam genutzten Bibliotheken, die vom Profilerstellungsprozess verwendet werden, und gibt einen Bericht aus, der zeigt, wo die Zeit aufgewendet wird.

3. Umweltanforderungen

Um Simpleperf nutzen zu können, ist die folgende Umgebung erforderlich:

  • Die zu analysierende App sollte auf Geräten mit Android 5.0 oder höher laufen.
  • USB- Anschluss des Mobiltelefons an die Bedienmaschine
  • Anwendungen sollten debuggbar sein. Aufgrund von Sicherheitsbeschränkungen können nur Anwendungen profiliert werden, bei denen android::debuggable auf true gesetzt ist. (Auf einem gerooteten Gerät können alle Apps profiliert werden.) In Android Studio bedeutet dies, dass wir den Debug-Build-Typ und nicht den Release-Build-Typ verwenden müssen.
  • Um Python-Skripte ausführen zu können , sollte der Host-Computer über Folgendes verfügen:
    • Python 2.7 oder höher
    • Die NDK-Version sollte nicht niedriger als r13b sein

Typischerweise umfasst die Profilierung der Leistung von Android-Anwendungen drei Schritte:

  1. Bewerbung vorbereiten.
  2. Profilierungsdaten aufzeichnen.
  3. Erstellen Sie Analyseberichte mit Profildaten.

Simpleperf-Erfassungspfad: https://android.googlesource.com/platform/prebuilts/simpleperf/

Auf der Seite können Sie das komprimierte Paket direkt herunterladen. Sie können die entsprechende Version von NDK (R13~N21) oder Master auswählen. Es wird empfohlen, direkt die dem NDK entsprechende Version auszuwählen. Natürlich können Sie das Repository auch direkt mit Git abrufen.

Git-Klon https://android.googlesource.com/platform/prebuilts/simpleperf

Wenn wir uns das heruntergeladene simpleperf-Verzeichnis ansehen, können wir sehen, dass sein Toolset Client und Host umfasst; der Client läuft auf dem Android-System und ist für die Erfassung von Leistungsdaten verantwortlich; der Host läuft auf dem Entwicklungscomputer und ist für die Analyse und Visualisierung von Daten verantwortlich ( Diese Ausführbare Dateien befinden sich unter Android und Win/Linux im heruntergeladenen Bin-Ordner.

Zusätzlich zum Bin-Ordner befinden sich auf der obersten Ebene viele .py-Skriptdateien. Bei diesen Skripten und Konfigurationsdateien handelt es sich hauptsächlich um narrensichere Skripte, die von Beamten geschrieben wurden. Sie müssen nur die Konfigurationsdatei konfigurieren und können das Skript direkt auf dem Entwicklungscomputer ausführen und das Endergebnis mit einem Klick generieren.

Python-Skripte sind basierend auf ihrer Funktionalität in drei Teile unterteilt:

  1. Skripte wie app_profiler.py zur Vereinfachung der Profilierungsdatenprotokollierung.
  2. Skripte, die zum Generieren von Profilierungsberichten verwendet werden, z. B. report.py, report_html.py, inferno.
  3. Skripte zum Parsen von Profilierungsdaten, z. B. simpleperf_report_lib.py.

Die Hauptskripte sind: app_profiler.py und report.py.

Die ausführbare Simpleperf-Datei und das Python-Skript sind in android-ndk\simpleperf enthalten. Ihre Funktionen sind wie folgt:

  • bin/: Enthält ausführbare Dateien und gemeinsam genutzte Bibliotheken, einschließlich Android und Windows.
  • bin/android/${arch}/simpleperf: Die statische ausführbare Simpleperf-Datei, die auf dem Gerät ausgeführt wird. Dabei ist ${arch} die CPU-Architektur des Zielgeräts, z. B. arm und arm64.
  • bin/${host}/${arch}/simpleperf: ausführbare Simpleperf-Datei für den Host, unterstützt nur die Berichtserstellung. Unter diesen ist ${host} die Betriebssystemplattform des Hosts, z. B. Linux, und ${arch} die CPU-Architektur des Hosts, z. B. x86_64.
  • bin/${host}/${arch}/libsimpleperf_report.${so/dylib/dll}: Berichtsgenerierungsbibliothek für den Host. Unter diesen bezieht sich ${host} auf die Betriebssystemplattform des Hosts und ${arch} auf die CPU-Architektur des Hosts.
  • app_profiler.py: Python-Skript zum Aufzeichnen von Profilierungsdaten.
  • binär_cache_builder.py: Python-Skript zum Erstellen eines Binärcaches für Profilierungsdaten.
  • report.py: Python-Skript zum Generieren von Profiling-Berichten und deren Ausgabe in der Standardausgabe.
  • report_html.py: Python-Skript zum Generieren von Profiling-Berichten und deren Ausgabe als HTML-Dateien.
  • inferno.sh (oder inferno.bat auf Windows-Plattform): Skripttool zum Generieren von Flammendiagrammen und deren Ausgabe als HTML-Dateien.
  • inferno/: Implementierung von inferno. Wird von inferno.sh verwendet.
  • pprof_proto_generator.py: Python-Skript, das das Format der Profilierungsdaten in das von pprof verwendete Format konvertiert.
  • report_sample.py: Python-Skript, das das Format der Profilierungsdaten in das von FlameGraph verwendete Format konvertiert.
  • simpleperf_report_lib.py: Eine Bibliothek zur Analyse von Profiling-Daten.

Der Hauptinhalt des Skripts besteht darin, die Konfigurationsdatei zu lesen und dann den Befehl adb shell ... auszuführen. Tatsächlich ist es im Wesentlichen dasselbe wie die Befehlszeileneingabe. Wenn Sie es jedoch direkt ausführen, müssen Sie nicht nur die Bedeutung jedes Konfigurationselements in der Konfigurationsdatei überprüfen, sondern es können auch viele unerwartete Fehler auftreten. Es wird nicht empfohlen, das Skript direkt zu verwenden, da es nicht das Wesentliche ist .

4. Unterstützte Befehle

debug-unwind-Befehl: Offline-Entladung basierend auf Debug/Test-Zwerg zum Debuggen von SimplePerf.

Dump-Befehl: Den Inhalt von perf.data zum Debuggen von simpleperf sichern.

Hilfebefehl: Hilfeinformationen für andere Befehle ausgeben.

kmem-Befehl: sammelt Informationen zur Kernel-Speicherzuordnung (wird durch ein Python-Skript ersetzt).

list-Befehl: Alle von Android-Geräten unterstützten Ereignistypen auflisten.

Protokollierungsbefehl: Dateiverarbeitung konfigurieren und Analysedaten in perf.data speichern.

Report-Befehl: Melden Sie die Analysedaten in perf.data.

Befehl „report-sample“: Meldet jedes Beispiel in perf.data, um die Integration von simpleperf in Android Studio zu unterstützen.

stat-Befehl: Profiliert Prozesse und druckt Zählerzusammenfassungen.

Jeder Befehl unterstützt verschiedene Optionen, die über die Hilfemeldung angezeigt werden können, wie im folgenden Beispiel:

# Alle Befehle auflisten.
$ simpleperf --help
# Hilfemeldung für Aufnahmebefehl drucken.
$ simpleperf record --help

5. Betriebsablauf

Methode 1: Verwenden Sie die ADB-Shell, um den Vorgang für mobile Seiten aufzurufen

1. Schieben Sie die simpleperf-Datei auf das Mobiltelefon

Das Verzeichnis simpleperf/bin/android enthält statische Binärdateien, die auf Android mit unterschiedlichen Architekturen ausgeführt werden. Öffnen Sie das Befehlsfenster im Arm-Verzeichnis und führen Sie den Befehl aus:

adb push simpleperf data/data/

2. Autorisieren Sie simpleperf als lesbare und beschreibbare ausführbare Datei:

ADB Shell
CD-Daten/Daten/
chmod 777 simpleperf

3. Überwachen Sie bestimmte spezifische Prozesse oder Threads

./simpleperf record -p 4281 (pid oder tid) --duration 30 (time/s)

Ich habe eine Fehlermeldung erhalten, dass die schreibgeschützte Partition perf.data nicht schreiben konnte:

simpleperf E 04-19 15:09:29 4109 4109 record_file_writer.cpp:47] Datensatzdatei „perf.data“ konnte nicht geöffnet werden: Schreibgeschützt f

4. Verwenden Sie den Parameter -o, um den Pfad zum Speichern von Datensätzen festzulegen.

simpleperf I cmd_record.cpp:729] 29,9851 Sekunden lang aufgezeichnet. Starten Sie die Nachbearbeitung.
simpleperf I cmd_record.cpp:809] Aufgenommene Samples: 1457. Verlorene Samples: 0.

5. Verwenden Sie „report“, um die Analysedaten in perf.data zu melden

simpleperf record -p 17465--duration 4 -f 1000 -o /data/local/tmp/perf.data --call-graph fp

simpleperf report -i /data/perf.data -n --sort dso
simpleperf W 04-19 15:31:17 4564 4564 dso.cpp:274] /data/local/rvdecApp enthält keine Symboltabelle
simpleperf W 04-19 15:31:17 4564 4564 dso.cpp:335] Symboladressen in /proc/kallsyms sind alle Null. `echo 0 >/proc/sys/kernel/kptr_restrict` wenn möglich.
Befehlszeile: /data/local/tmp/simpleperf record -p 4281 --duration 30 -o /data/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 125526
Ereignisanzahl: 43633757353

Overhead-Beispiel für ein freigegebenes Objekt
88,93 % 106529 /data/local/rvdecApp
8,05 % 10560 /system/lib/libc.so
3,01 % 8437 [kernel.kallsyms]

Der Parameter „–sort“ wird verwendet, um anzugeben, welche Spalten im Ergebnis angezeigt werden sollen. Wir haben hier nur ein DSO (Dynamic Shared Object) geschrieben, daher zeigt das Ergebnis nur eine Spalte von „Shared Object“ und entsprechend der DSO-Klassifizierung das Ergebnis an hat nur drei Reihen.

Wenn Sie den Parameter –sort nicht hinzufügen, werden diese Spalten standardmäßig angezeigt: Command, Pid, ​​​​Tid, Shared Object, Symbol, was äquivalent ist zu:

--sort comm,pid,tid,dso,symbol
  • Der Parameter -n wird verwendet, um die Spalte „Sample“ anzuzeigen und anzugeben, wie viele Samples in dieser Zeile getroffen wurden. Der Zusatz ist optional.
  • Wie Sie sehen, verbringen wir erwartungsgemäß 88,93 % der Zeit mit unserem getesteten Programm.

6. Schauen Sie in die App und sehen Sie den Funktionsanteil:

simpleperf report -i /data/perf.data --dsos /data/local/rvdecApp --sort Symbol
  • Das Ergebnis ist wie folgt:
impleperf W 04-19 15:57:34 5046 5046 dso.cpp:274] /data/local/rvdecApp enthält keine Symboltabelle
simpleperf W 04-19 15:57:34 5046 5046 dso.cpp:335] Symboladressen in /proc/kallsyms sind alle Null. `echo 0 >/proc/sys/kernel/kptr_restrict` wenn möglich.
Befehlszeile: /data/local/tmp/simpleperf record -p 4281 --duration 30 -o /sdcard/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 106529
Ereignisanzahl: 38804869540

Overhead-Beispielsymbol
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]
...

Der Parameter –dsos ist einer der fünf Filter von simpleperf. Dies bedeutet, dass nach den angegebenen dynamischen gemeinsam genutzten Objekten gefiltert wird und die Ergebnisse nur in dem durch den Parameter angegebenen DSO angezeigt werden. Alle 5 Filter sind:

–comms: Nach Befehl filtern, zum Beispiel: --comm rvdecApp

–pids: Drücken Sie pid, um hierher zu gelangen

–tids: Filtern nach TID (Thread-ID)

–dsos: Nach Bibliotheks-/ausführbarem Dateinamen filtern

–symbols: Nach Funktionsnamen filtern, zum Beispiel: --symbols „RVComFunc::getPUMVPredictor(RefBlockInfo*, unsigned int, int, int, unsigned int)“. Beachten Sie, dass Leerzeichen in der Funktion eingeschlossen werden müssen in doppelten Anführungszeichen.

Wie Sie sehen, enthält das Ergebnis keinen Funktionsnamen. Das liegt daran, dass es sich bei unserer rvdecApp um eine Version ohne Symboltabelle handelt. Zur Analyse können wir eine App mit Symboltabelle nutzen.

Die ausführbare App-Datei mit Symboltabelle befindet sich im obj-Verzeichnis. Schieben Sie es auf das Telefon und überschreiben Sie die ursprüngliche ausführbare Datei.

Beachten Sie, dass es nicht erforderlich ist, rvdecApp erneut auszuführen und perf.data erneut zu erfassen. Sie müssen rvdecApp nur während der Analyse mit der Symboltabelle verwenden.

Benutzen Sie jetzt auch den Befehl:

./simpleperf report -i /data/perf.data -n --dsos /data/local/rvdecApp --sort Symbol
  • Erhalten Sie die folgenden Ergebnisse:
Overhead-Beispielsymbol
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 (anonymer Namespace)::decode_gen_vlc(unsigned long const*, int, (anonymer Namespace)::VLC*, int, int)
...

Es ist ersichtlich, dass die Funktion DBFShiftedProcess8x8 die zeitaufwändigste Funktion ist und optimiert werden muss.

Methode 2: Verwenden Sie eine Linux-Umgebung und verwenden Sie für den Betrieb ein Python-Skript

1. Führen Sie app-profiler.py aus

python app_profiler.py -p com.android.settings

Wenn wir das SimplePerf-Verzeichnis betreten, können wir app-profiler.py verwenden, um Android-Anwendungen zu profilieren. Der Ausgabepfad usw. kann in der Konfigurationsdatei app_profiler.py geändert werden

14:47:33.547 [INFO] (app_profiler.py:206) Profilerstellung vorbereiten
14:47:33.730 [INFO] (app_profiler.py:208) Profilerstellung starten
14:47:33,806 [INFO] (app_profiler.py:244) adb cmd ausführen: ['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] Aufgezeichnet für 9,96625 Sekunden. Starten Sie die Nachbearbeitung.
simpleperf W dso.cpp:446] /vendor/lib64/egl/libGLES_mali.so enthält keine Symboltabelle
simpleperf W dso.cpp:446] /vendor/lib64/hw/[email protected] enthält keine Symboltabelle
simpleperf W dso.cpp:446] /data/app/~~EKnZoTKaDLH3FYfxteqUvg==/com.google.android.trichromelibrary_541411734-ozjH9V7NI4SknoCd0t2CPg==/base.apk!/lib/arm64-v8a/libmonochrome_64.so enthält kein Symbol Tisch
simpleperf W dso.cpp:446] /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/lib/arm64/libmmkv.so enthält keine Symboltabelle
simpleperf I cmd_record.cpp:771] Aufgenommene Samples: 8647. Verlorene Samples: 0.
14:47:45,689 [INFO] (app_profiler.py:211) Profilierungsdaten sammeln
14:47:46.745 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\apex\com.android.runtime\lib64\bionic\libc.so
14:47:46.770 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\vendor\lib64\libged.so
14:47:46.800 [INFO] (binary_cache_builder.py:184) aktuelle Datei im Binary_cache verwenden: Binary_cache\vendor\lib64\egl\libGLES_mali.so
14:47:46.835 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\lib64\libEGL.so
14:47:46.867 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\lib64\libhwui.so
14:47:46.888 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binär_cache\system\lib64\libutils.so
14:47:46.913 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\lib64\libgui.so
14:47:46.932 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binär_cache\system\lib64\libnativewindow.so
14:47:46.992 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\framework\arm64\boot-framework.oat
14:47:47,069 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\apex\com.android.art\lib64\libart.so
14:47:47,130 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\framework\arm64\boot.oat
14:47:47,159 [INFO] (binary_cache_builder.py:184) aktuelle Datei im Binärcache verwenden: Binärcache\system\lib64\libandroid_runtime.so
14:47:47,179 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\bin\app_process64
14:47:47,206 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\apex\com.android.vndk.v31\lib64\libhidlbase.so
14:47:47,230 [INFO] (binary_cache_builder.py:184) aktuelle Datei im Binärcache verwenden: Binär_cache\system\lib64\libhidlbase.so
14:47:47,260 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binärcache\system\lib64\[email protected]
14:47:47,301 [INFO] (binary_cache_builder.py:184) Aktuelle Datei im Binärcache verwenden: Binär_cache\system\lib64\libui.so

2. Führen Sie das Skript report_html.py aus, um den Bericht zu analysieren und auszugeben

python report_html.py

simpleperf W dso.cpp:448] konnte Symbole aus /data/app/~~3WfX5_4-OAPL17xSEBkRfg==/com.afmobi.boomplayer-yFLZq2TqjDUJV1OB-um-UQ==/lib/arm64/libmmkv.so nicht lesen: Datei nicht gefunden
Befehlszeile: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.afmobi.boomplayer
Bogen: arm64
Ereignis: task-clock:u (Typ 1, Konfiguration 1)
Proben: 8647
Ereignisanzahl: 8647000000

Overhead Shared Object 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-App-Cache] 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/libbinder.so 31183
0,75 % /apex/com.android.art/lib64/libart-compiler.so 31183
0,74 % /system/lib64/libminikin.so 31183
0,73 % /system/lib64/libz.so 31183
0,68 % /system/lib64/libsqlite.so 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/bin/linker64 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. Erstellen Sie einen Bericht des Anrufdiagramms und geben Sie ihn in der Standardausgabe aus:

Befehlszeile: /data/local/tmp/simpleperf record -o /data/local/tmp/perf.data -e task-clock:u -f 1000 -g --duration 10 --app com.afmobi.boomplayer
Bogen: arm64
Ereignis: task-clock:u (Typ 1, Konfiguration 1)
Proben: 10841
Ereignisanzahl: 10841000000

Kinder-Selbstbefehl-Pid-Tid-Symbol für gemeinsame Objekte
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 %-- [Treffer in Funktion]
               |
               |--99,96%-- android::uirenderer::WorkQueue::process()
               | |--0,03%-- [Treffer in Funktion]
               | |
               | |--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 %-- [Treffer in Funktion]
               | | |
               | | |--86.61%-- android::uirenderer::renderthread::CanvasContext::draw()
               | | | |--0,11%-- [Treffer in Funktion]
               | | | |
               | | | |--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,08%-- [Treffer in Funktion]
               | | | | |
               | | | | |--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&, bool, android::uirenderer::Rect const&, SkCanvas*, SkMatrix const&)
               | | | | | | |--0,12%-- [Treffer in Funktion]

4. Flammendiagramm anzeigen

Um das Flammendiagramm anzuzeigen, müssen wir zunächst das Anrufdiagramm aufzeichnen. Flame-Diagramme werden im Flamegraph -Tag von report_html.py angezeigt . Sie können auch direkt auf inferno.bat doppelklicken, um das Flammendiagramm anzuzeigen.

Wir können Flammendiagramme auch mit GitHub erstellen – brendangregg/FlameGraph: Stack Trace Visualizer . Bitte stellen Sie sicher, dass Sie Perl installiert haben.

$ Git-Klon 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

Sie können es mit einem Browser öffnen und das analysierte Flammendiagramm wie folgt anzeigen:

  • Aus dem Flammendiagramm oben können Sie sehen, was netd ausgeführt hat, sodass es zur weiteren Verfolgung an netd-Kollegen übergeben werden kann.

Die y-Achse stellt den Aufrufstapel dar, wobei jede Ebene eine Funktion ist. Je tiefer der Aufrufstapel ist, desto höher ist die Flamme, wobei die ausgeführte Funktion oben und ihre übergeordnete Funktion unten liegt.
Die x-Achse stellt die Anzahl der Stichproben dar. Wenn eine Funktion auf der x-Achse eine größere Breite einnimmt, bedeutet dies, dass sie häufiger abgetastet wurde, d. h. die Ausführung dauert länger. Beachten Sie, dass die x-Achse nicht die Zeit darstellt, sondern alle Aufrufstapel zusammengeführt und in alphabetischer Reihenfolge angeordnet sind.
Das Flammendiagramm dient dazu, zu sehen, welche Funktion der obersten Ebene die größte Breite einnimmt. Immer wenn ein „Plateau“ auftritt, bedeutet dies, dass die Funktion möglicherweise Leistungsprobleme hat.
Die Farben haben keine besondere Bedeutung, da die Flammengrafik anzeigt, wie ausgelastet die CPU ist, daher werden im Allgemeinen warme Farben gewählt.

Ausführliche Informationen zur Verwendung von Flammendiagrammen finden Sie unter Wie liest man Flammendiagramme? - Ruan Yifengs Blog

6. Tipps und Tricks

Wenn Sie gerade erst mit Simpleperf beginnen, finden Sie hier einige besonders nützliche Befehle, die Sie vielleicht ausprobieren möchten. Weitere Befehle und Optionen finden Sie in der Simpleperf-Befehls- und Optionsreferenz .

1. Suchen Sie die gemeinsam genutzte Bibliothek, die die längste Ausführungszeit benötigt

Sie können diesen Befehl ausführen, um zu sehen, welche .so-Dateien den größten Prozentsatz der Ausführungszeit in Anspruch nehmen (basierend auf CPU-Zyklen). Es empfiehlt sich, diesen Befehl zuerst auszuführen, wenn Sie eine Profilerstellungssitzung starten.

simpleperf report --sort dso

Beispiel:

Befehlszeile: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 3294
Ereignisanzahl: 1193555038

Overhead-Beispiel für ein freigegebenes Objekt
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.so
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/framework/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-App-Cache]
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 unbekannt
0,16 % 5 /system/lib64/libcutils.so
0,15 % 2 /apex/com.android.i18n/lib64/libicuuc.so
0,15 % 5 /system/framework/arm64/boot-core-libart.oat
...............

2. Finden Sie die Funktion mit der längsten Ausführungszeit

Sobald Sie die gemeinsam genutzte Bibliothek identifiziert haben, die die meiste Ausführungszeit benötigt, können Sie diesen Befehl ausführen, um den Prozentsatz der Zeit anzuzeigen, die für die Ausführung der Funktionen der .so-Datei aufgewendet wurde.

simpleperf-Bericht --dsos-Bibliothek.so --Sort-Symbol

Beispiel:

simpleperf E command.cpp:59] Unbekannte Option -dsos. Versuchen Sie es mit „simpleperf help report“.
1|TECNO-KI7:/ # simpleperf report -i /data/perf.data --dsos [kernel.kallsyms] --sort symbol
Befehlszeile: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 2114
Ereignisanzahl: 682442263

Overhead-Symbol
8,22 % _raw_spin_unlock_irqrestore
6,87 % __blockdev_direct_IO
6,72 % get_user_pages_fast
6,61 % dio_bio_complete
4,13 % memblock_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_delayed_work_on
1,83 % blk_crypto_submit_bio
1,79 % klare_Seite
1,68 % _mtk_btag_pidlog_set_pid
1,47 % 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. Ermitteln Sie den Prozentsatz der in einem Thread verbrachten Zeit

Die Ausführungszeit in einer .so-Datei kann auf mehrere Threads verteilt werden. Sie können diesen Befehl ausführen, um den Prozentsatz der Zeit anzuzeigen, die jeder Thread verbracht hat.

simpleperf report --sort tid,comm

Beispiel:

Befehlszeile: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 3294
Ereignisanzahl: 1193555038

Overhead-Tid-Befehl
42,01 % 12182 Thread-4
29,48 % 11834 RenderThread
16,96 % 10167 com.andromeda.androbench2
6,04 % 11853 hatte Buttermilch-Backe
2,70 % 11876 Bindemittel:10167_4
1,24 % 11854 ged-swd
0,67 % 11844 mali-mem-purge
0,62 % 12087 Bindemittel:10167_6
0,26 % 11968 Bindemittel:10167_2
0,01 % 11820 Jit-Thread-Pool
0,00 % 11824 FinalizerWatchd
0,00 % 11859 GPU-Abschluss

4. Prozentsatz der für die Suche nach Objektmodulen aufgewendeten Zeit

Nachdem Sie die Threads gefunden haben, die die meiste Ausführungszeit benötigen, können Sie mit diesem Befehl die Objektmodule isolieren, die in diesen Threads die längste Ausführungszeit benötigen.

simpleperf report --tids threadID --sort dso

Beispiel:

Befehlszeile: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 1457
Ereignisanzahl: 501433272

Overhead-gemeinsames Objekt
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. Verstehen Sie die Korrelation von Funktionsaufrufen

Das Aufrufdiagramm bietet eine visuelle Darstellung der von Simpleperf während der Profilerstellung einer Sitzung aufgezeichneten Stapelspuren.

Mit dem Befehl „report -g“ können Sie ein Aufrufdiagramm drucken, um zu sehen, welche Funktionen von anderen Funktionen aufgerufen werden. Dies kann dabei helfen, festzustellen, ob eine Funktion selbst langsam ist oder ob eine oder mehrere von ihr aufgerufene Funktionen langsam sind.

Sie können auch das Python-Skript report.py -g verwenden, um ein interaktives Tool zu starten, das Funktionen anzeigt. Sie können auf jede Funktion klicken, um die von ihren Unterfunktionen benötigte Zeit anzuzeigen.

simpleperf-Bericht -g

Beispiel:

TECNO-KI7:/ # simpleperf report -g
simpleperf E record_file_reader.cpp:83] konnte die Datensatzdatei „perf.data“ nicht öffnen: Keine solche Datei oder kein solches Verzeichnis
1|TECNO-KI7:/ # simpleperf report -i /data/perf.data -g
Befehlszeile: /system/bin/simpleperf record -p 10167 --duration 5 -o /data/perf.data
Bogen: arm64
Ereignis: CPU-Zyklen (Typ 0, Konfiguration 0)
Proben: 3294
Ereignisanzahl: 1193555038

Kinder-Selbstbefehl-Pid-Tid-Symbol für gemeinsame Objekte
3,93 % 3,93 % Thread-4 10167 12182 [kernel.kallsyms] __blockdev_direct_IO
3,84 % 3,84 % Thread-4 10167 12182 [kernel.kallsyms] get_user_pages_fast
3,78 % 3,78 % Thread-4 10167 12182 [kernel.kallsyms] dio_bio_complete
2,55 % 2,55 % mali-cmar-backe 10167 11853 [kernel.kallsyms] _raw_spin_unlock_irqrestore
2,36 % 2,36 % Thread-4 10167 12182 [kernel.kallsyms] memblock_start_of_DRAM
2,27 % 2,27 % Thread-4 10167 12182 [kernel.kallsyms] el0_da
2,12 % 2,12 % Thread-4 10167 12182 [kernel.kallsyms] blk_queue_split
1,94 % 1,94 % Thread-4 10167 12182 [kernel.kallsyms] iov_iter_fault_in_readable
1,31 % 1,31 % Thread-4 10167 12182 [kernel.kallsyms] fscrypt_mergeable_bio
1,27 % 1,27 % Thread-4 10167 12182 [kernel.kallsyms] free_unref_page_list
1,15 % 1,15 % RenderThread 10167 11834 [kernel.kallsyms] queue_work_on
1,15 % 1,15 % Thread-4 10167 12182 /apex/com.android.runtime/lib64/bionic/libc.so memset
1,13 % 1,13 % Thread-4 10167 12182 [kernel.kallsyms] mod_delayed_work_on
1,05 % 1,05 % Thread-4 10167 12182 [kernel.kallsyms] blk_crypto_submit_bio
1,02 % 1,02 % Thread-4 10167 12182 [kernel.kallsyms] clear_page
1,01 % 1,01 % RenderThread 10167 11834 [kernel.kallsyms] _raw_spin_unlock_irqrestore
0,96 % 0,96 % Thread-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 % Thread-4 10167 12182 [kernel.kallsyms] fscrypt_generate_dun
0,67 % 0,67 % Thread-4 10167 12182 [kernel.kallsyms] get_page_from_freelist
0,64 % 0,64 % RenderThread 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 % Thread-4 10167 12182 [kernel.kallsyms] __save_stack_trace
0,55 % 0,55 % Thread-4 10167 12182 [kernel.kallsyms] pagecache_get_page
0,54 % 0,54 % com.andromeda.androbench2 10167 10167 /apex/com.android.art/lib64/libart.so ExecuteNterpImpl
0,51 % 0,51 % Thread-4 10167 12182 [kernel.kallsyms] __handle_speculative_fault
0,46 % 0,46 % Thread-4 10167 12182 [kernel.kallsyms] f2fs_map_blocks
0,45 % 0,45 % RenderThread 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 % RenderThread 10167 11834 /system/lib64/libgui.so @plt
0,41 % 0,41 % Thread-4 10167 12182 [kernel.kallsyms] depot_save_stack
0,36 % 0,36 % Thread-4 10167 12182 [kernel.kallsyms] f2fs_wait_on_block_writeback
0,36 % 0,36 % Thread-4 10167 12182 [kernel.kallsyms] _raw_spin_unlock_irq
0,34 % 0,34 % Thread-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 % Thread-4 10167 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-buttermilk-backe 10167 11853 [kernel.kallsyms] el0_svc_common
0,26 % 0,26 % RenderThread 10167 11834 /apex/com.android.runtime/lib64/bionic/libc.so schreiben
0,25 % 0,25 % Thread-4 10167 12182 [kernel.kallsyms] pte_map_lock
........

6. Erhalten Sie rohe Ereigniszählerinformationen innerhalb des profilierten Programms oder Systems

simpleperf stat wird verwendet, um rohe Ereigniszählerinformationen innerhalb des profilierten Programms oder Systems zu erhalten. Durch die Übergabe von Optionen können wir auswählen, welche Ereignisse verwendet werden sollen, welcher Prozess/Thread überwacht werden soll, wie lange überwacht werden soll und welches Intervall zwischen den Ausdrucken liegen soll.

Statistiken der Leistungsindikatoren:

# count event_name # count / Laufzeit
    17.839.958.825 CPU-Zyklen # 1,758283 GHz
     6.411.685.476 Stalled-Cycles-Frontend # 632,274 M/Sek
     5.413.391.502 Stalled-Cycles-Backend # 534,113 M/Sek
    11.755.131.810 Anweisungen # 1.160 G/Sek
     1.409.829.788 Verzweigungsanweisungen # 139,262 M/Sek
       171.458.771 Zweigfehler # 16,946 M/Sek
  10070,704634 (ms) Task-Takt # 1,006817 CPU verwendet
             7.210 Kontextwechsel # 716.330 /Sek
            94.430 Seitenfehler # 9.387 K/Sek

Gesamttestzeit: 10,002513 Sekunden.

7. Referenzdokumente

[Simpleperf] Android-CPU-Analyse, Leistungsoptimierungstool_android perf_Yngz_Miaos Blog-CSDN-Blog

Profil-Tool-Serie vier: Blog von simpleperf_old_man – CSDN-Blog

Analyse der Leistung nativen Codes mit Simpleperf | WolfcsTech

Wie liest man Flammendiagramme? - Ruan Yifengs Blog

Einführung in Simpleperf | WolfcsTech

Simpleperf | Android NDK | Android-Entwickler

Referenzdokumentation zu Simpleperf-Befehlen und -Optionen | Android NDK | Android-Entwickler

Supongo que te gusta

Origin blog.csdn.net/weixin_47465999/article/details/129636331
Recomendado
Clasificación