Leistungstests

Android 8.0 umfasst Binder- und Hwbinder-Leistungstests für Durchsatz und Latenz. Es gibt zwar viele Szenarien für die Erkennung wahrnehmbarer Leistung ist die Ausführung solcher Szenarien zeitaufwändig und die Ergebnisse erst nach der Integration eines Systems verfügbar. Bereitgestellte Leistung wird verwendet Tests erleichtern Tests während der Entwicklung und erkennen schwerwiegende Probleme und die User Experience zu verbessern.

Leistungstests umfassen die folgenden vier Kategorien:

  • Binder-Durchsatz (verfügbar in system/libhwbinder/vts/performance/Benchmark_binder.cpp)
  • Binder-Latenz (verfügbar in frameworks/native/libs/binder/tests/schd-dbg.cpp)
  • hwbinder-Durchsatz (verfügbar in system/libhwbinder/vts/performance/Benchmark.cpp)
  • Hwbinder-Latenz (verfügbar in system/libhwbinder/vts/performance/Latency.cpp)

Über binder und hwbinder

Binder und Hwbinder sind Android Inter-Process Communication (IPC) Infrastrukturen mit demselben Linux-Treiber, aber mit den folgenden qualitative Unterschiede:

Seitenverhältnis Bindemittel HWbinder
Zweck Bereitstellung eines allgemeinen IPC-Schemas für das Framework Mit Hardware kommunizieren
Attribut Für die Nutzung des Android-Frameworks optimiert Minimaler Aufwand mit niedriger Latenz
Planungsrichtlinie für Vorder-/Hintergrund ändern Ja Nein
Übergebene Argumente Verwendet die vom Parcel-Objekt unterstützte Serialisierung Nutzt Streuzwischenspeicher und vermeidet den Aufwand beim Kopieren von Daten, die für Paketserialisierung
Prioritätsübernahme Nein Ja

Binder- und Hwbinder-Prozesse

Ein Systrace-Visualizer zeigt Transaktionen so an:

Abbildung 1: Systrace-Visualisierung von Binder Prozesse.

Im obigen Beispiel gilt Folgendes:

  • Die vier (4) schd-dbg-Prozesse sind Clientprozesse.
  • Die vier (4) Binderprozesse sind Serverprozesse (der Name beginnt mit Binder und endet mit einer Sequenznummer.
  • Ein Clientprozess ist immer mit einem Serverprozess gekoppelt, der dem an die Kundschaft.
  • Alle Client-Server-Prozesspaare werden vom Kernel unabhängig geplant .

In CPU 1 führt der Kernel des Betriebssystems den Client aus, um die Anfrage zu senden. Dann verwendet, wenn möglich, dieselbe CPU, um einen Serverprozess zu aktivieren, und der Kontext wechselt nach Abschluss der Anfrage wieder zurück.

Durchsatz und Latenz

In einer perfekten Transaktion, bei der der Client- und Serverprozess bei nahtlosem Wechsel zwischen Durchsatz- und Latenztests Nachrichten. Wenn der Kernel des Betriebssystems jedoch eine Interrupt-Anfrage (IRQ) verarbeitet, z. B. Hardware, auf Schlösser warten oder einfach festlegen, dass Nachrichten nicht verarbeitet werden sollen. kann sich eine Latenzblase bilden.

Abbildung 2: Latenzblase aufgrund von Unterschieden im Durchsatz und Latenz.

Der Durchsatztest generiert eine große Anzahl von Transaktionen mit unterschiedlichen eine gute Schätzung für die reguläre Transaktionszeit (in Best-Case-Szenarien) und den maximalen Durchsatz, den der Binder erreichen kann.

Im Gegensatz dazu führt der Latenztest keine Aktionen für die Nutzlast aus, um der regulären Transaktionszeit. Wir können die Transaktionszeit verwenden, um den Binder zu schätzen. für den schlimmsten Fall Statistiken erstellen und das Verhältnis Transaktionen, deren Latenz eine bestimmte Frist einhält.

Prioritätsumkehrungen verarbeiten

Eine Prioritätsumkehr tritt auf, wenn ein Thread mit höherer Priorität Es wird auf einen Thread mit niedrigerer Priorität gewartet. Echtzeitanwendungen haben eine Prioritätsumkehrproblem:

Abbildung 3: Prioritätsumkehr in Echtzeit Anwendungen.

Bei der CFS-Planung (Linux Completely Fair Scheduler) wird immer ein Thread ausgeführt werden kann, auch wenn andere Threads eine höhere Priorität haben. Daher Anwendungen mit CFS-Planung handhaben die Prioritätsumkehr wie erwartet und nicht als Problem. In Fällen, in denen das Android-Framework Echtzeit-Planung benötigt um die Berechtigung von Threads mit hoher Priorität zu gewährleisten. gelöst werden muss.

Beispiel für die Prioritätsumkehr während einer Binder-Transaktion (RT-Thread ist von anderen CFS-Threads logisch blockiert, wenn ein Binder-Thread Dienst):

Abbildung 4: Prioritätsumkehr, Blockierung in Echtzeit Threads.

Um Blockierungen zu vermeiden, können Sie mit der priorisierten Übernahme vorübergehend den Fall eskalieren. den Binder-Thread an einen RT-Thread, wenn er eine Anfrage von einem RT-Client verarbeitet. Denken Sie daran, dass die Echtzeit-Planung nur über begrenzte Ressourcen verfügt und daher verwendet werden sollte. vorsichtig zu sein. In einem System mit n CPUs ist die maximale Anzahl der aktuellen RTF-Systeme Threads ist auch n. müssen zusätzliche RT-Threads möglicherweise warten (und Fristen verpassen), wenn alle CPUs von anderen RT-Threads beansprucht werden.

Um alle möglichen Prioritätsumkehrungen zu beheben, können Sie die Priorität sowohl für binder als auch für hwbinder. Da Binde jedoch weit verbreitet ist, im gesamten System haben, kann das Aktivieren der Prioritätsübernahme für Binder-Transaktionen Das System wird mit mehr RT-Threads gespammt, als es verarbeiten kann.

Durchsatztests ausführen

Der Durchsatztest wird anhand des binder/hwbinder-Transaktionsdurchsatzes durchgeführt. In System ist nicht überlastet, Latenzblasen sind selten und ihre Auswirkungen eliminiert werden, solange die Anzahl der Iterationen hoch genug ist.

  • Der binder-Durchsatztest befindet sich in system/libhwbinder/vts/performance/Benchmark_binder.cpp
  • Der hwbinder-Durchsatztest befindet sich in system/libhwbinder/vts/performance/Benchmark.cpp

Testergebnisse

Beispiel für Ergebnisse von Durchsatztests für Transaktionen mit anderer Nutzlast Größen:

Benchmark                      Time          CPU           Iterations
---------------------------------------------------------------------
BM_sendVec_binderize/4         70302 ns      32820 ns      21054
BM_sendVec_binderize/8         69974 ns      32700 ns      21296
BM_sendVec_binderize/16        70079 ns      32750 ns      21365
BM_sendVec_binderize/32        69907 ns      32686 ns      21310
BM_sendVec_binderize/64        70338 ns      32810 ns      21398
BM_sendVec_binderize/128       70012 ns      32768 ns      21377
BM_sendVec_binderize/256       69836 ns      32740 ns      21329
BM_sendVec_binderize/512       69986 ns      32830 ns      21296
BM_sendVec_binderize/1024      69714 ns      32757 ns      21319
BM_sendVec_binderize/2k        75002 ns      34520 ns      20305
BM_sendVec_binderize/4k        81955 ns      39116 ns      17895
BM_sendVec_binderize/8k        95316 ns      45710 ns      15350
BM_sendVec_binderize/16k      112751 ns      54417 ns      12679
BM_sendVec_binderize/32k      146642 ns      71339 ns       9901
BM_sendVec_binderize/64k      214796 ns     104665 ns       6495
  • Zeit gibt die in Echtzeit gemessene Umlaufzeit an.
  • CPU gibt die akkumulierte Zeit an, wenn CPUs geplant werden. für den Test.
  • Iterationen gibt an, wie oft die Testfunktion ausgeführt haben.

Für eine 8-Byte-Nutzlast gilt beispielsweise Folgendes:

BM_sendVec_binderize/8         69974 ns      32700 ns      21296

...der maximale Durchsatz, den der Binder erreichen kann, wie folgt berechnet wird:

MAX-Durchsatz mit 8-Byte-Nutzlast = (8 * 21296)/69974 ~= 2,423 b/ns ~= 2,268 Gbit/s

Testoptionen

Um Ergebnisse im JSON-Format zu erhalten, führen Sie den Test mit der Argument --benchmark_format=json:

libhwbinder_benchmark --benchmark_format=json
{
  "context": {
    "date": "2017-05-17 08:32:47",
    "num_cpus": 4,
    "mhz_per_cpu": 19,
    "cpu_scaling_enabled": true,
    "library_build_type": "release"
  },
  "benchmarks": [
    {
      "name": "BM_sendVec_binderize/4",
      "iterations": 32342,
      "real_time": 47809,
      "cpu_time": 21906,
      "time_unit": "ns"
    },
   ….
}

Latenztests ausführen

Der Latenztest misst die Zeit, die der Client benötigt, um zu beginnen Initialisierung der Transaktion, Wechsel zum Serverprozess für die Verarbeitung und das Ergebnis erhalten. Außerdem wird nach bekannten fehlerhaften Planerverhaltensweisen gesucht, sich negativ auf die Transaktionslatenz auswirken kann, z. B. durch einen Planer, der keine Prioritätsübernahme unterstützen oder das Synchronisierungs-Flag berücksichtigen.

  • Der Binder-Latenztest ist in frameworks/native/libs/binder/tests/schd-dbg.cpp
  • Der hwbinder-Latenztest läuft system/libhwbinder/vts/performance/Latency.cpp

Testergebnisse

Die Ergebnisse (im JSON-Format) enthalten Statistiken für die durchschnittliche/beste/schlechteste Latenz sowie den die Anzahl der verpassten Fristen.

Testoptionen

Latenztests haben folgende Optionen:

Befehl Beschreibung
-i value Geben Sie die Anzahl der Iterationen an.
-pair value Geben Sie die Anzahl der Prozesspaare an.
-deadline_us 2500 Gib die Frist in uns an.
-v Ausführliche Ausgabe (Debuggen)
-trace Stoppt den Trace bei einem Deadline-Treffer.

In den folgenden Abschnitten werden die einzelnen Optionen beschrieben, die Nutzung beschrieben und Beispielergebnisse.

Iterationen angeben

Beispiel mit einer großen Anzahl von Iterationen und deaktivierter ausführlicher Ausgabe:

libhwbinder_latency -i 5000 -pair 3
{
"cfg":{"pair":3,"iterations":5000,"deadline_us":2500},
"P0":{"SYNC":"GOOD","S":9352,"I":10000,"R":0.9352,
  "other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
},
"P1":{"SYNC":"GOOD","S":9334,"I":10000,"R":0.9334,
  "other_ms":{ "avg":0.19, "wst":2.9 , "bst":0.055, "miss":2, "meetR":0.9996},
  "fifo_ms": { "avg":0.16, "wst":3.1 , "bst":0.066, "miss":1, "meetR":0.9998}
},
"P2":{"SYNC":"GOOD","S":9369,"I":10000,"R":0.9369,
  "other_ms":{ "avg":0.19, "wst":4.8 , "bst":0.055, "miss":6, "meetR":0.9988},
  "fifo_ms": { "avg":0.15, "wst":1.8 , "bst":0.067, "miss":0, "meetR":1}
},
"inheritance": "PASS"
}

Diese Testergebnisse zeigen Folgendes:

"pair":3
Erstellt ein Client-Server-Paar.
"iterations": 5000
Umfasst 5.000 Iterationen.
"deadline_us":2500
Die Frist beträgt 2.500 Sekunden (2,5 ms); bei den meisten Transaktionen diese Wert.
"I": 10000
Ein Testdurchlauf umfasst zwei (2) Transaktionen: <ph type="x-smartling-placeholder">
    </ph>
  • Eine Transaktion mit normaler Priorität (CFS other)
  • Eine Transaktion nach Echtzeitpriorität (RT-fifo)
5.000 Iterationen entsprechen insgesamt 10.000 Transaktionen.
"S": 9352
9.352 der Transaktionen werden in derselben CPU synchronisiert.
"R": 0.9352
Gibt das Verhältnis an, mit dem Client und Server in dieselbe CPU.
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
Der Durchschnitt (avg), die schlechtesten (wst) und die besten (bst)-Fall für alle Transaktionen, die von einem Aufrufer mit normaler Priorität ausgeführt werden. Zwei Transaktionen miss die Frist, wodurch die Erfüllungsrate erreicht wird (meetR) 0,9996.
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
Ähnlich wie other_ms, aber für Transaktionen, die von einem Kunden mit Priorität rt_fifo. Es ist wahrscheinlich (aber nicht erforderlich), fifo_ms hat ein besseres Ergebnis als other_ms mit niedrigeren Werten Werte für avg und wst sowie einen höheren Wert für meetR Bei einer Auslastung im Hintergrund kann der Unterschied sogar noch größer sein.

Hinweis:Die Hintergrundlast kann sich auf den Durchsatz auswirken. und dem Tupel other_ms im Latenztest. Nur die fifo_ms zeigt möglicherweise ähnliche Ergebnisse an, solange die Hintergrundlast eine niedrigere Priorität als RT-fifo hat.

Paarwerte angeben

Jeder Clientprozess ist mit einem Serverprozess verbunden, der speziell für den Client vorgesehen ist. Jedes Paar kann für jede CPU unabhängig geplant werden. Die CPU Die Migration sollte nicht während einer Transaktion stattfinden, solange das SYNC-Flag honor

Das System darf nicht überlastet sein. Während hohe Latenz bei einer Überlastung erwartet wird, liefern Testergebnisse für ein überlastetes System keine nützlichen Informationen. Wenn du ein System mit höherem Druck testen möchtest, verwende -pair #cpu-1 (oder -pair #cpu mit Vorsicht). Testen mit -pair n mit n > #cpu überlädt das und generiert nutzlose Informationen.

Werte für Frist angeben

Nach umfassenden Tests von Nutzerszenarien (durch Ausführen des Latenztests qualifiziert ist, haben wir eine Frist von 2,5 ms als Frist festgelegt. Für neue Anwendungen mit höheren Anforderungen (z. B. 1.000 Fotos/Sekunde) ändert sich der Wert für die Frist.

Ausführliche Ausgabe angeben

Mit der Option -v wird eine ausführliche Ausgabe angezeigt. Beispiel:

libhwbinder_latency -i 1 -v

-------------------------------------------------- service pid: 8674 tid: 8674 cpu: 1 SCHED_OTHER 0
-------------------------------------------------- main pid: 8673 tid: 8673 cpu: 1 -------------------------------------------------- client pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0
-------------------------------------------------- fifo-caller pid: 8677 tid: 8678 cpu: 0 SCHED_FIFO 99 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 ??? 99
-------------------------------------------------- other-caller pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 SCHED_OTHER 0
  • Der Dienstthread wird mit einem SCHED_OTHER und führen sie in CPU:1 mit pid 8674 aus.
  • Die erste Transaktion wird dann durch einen fifo-caller Für diese Transaktion aktualisiert der Hwbinder das Priorität des Servers (pid: 8674 tid: 8676) auf 99 gesetzt. mit einer vorübergehenden Planungsklasse (ausgedruckt als ???). Der Planer führt den Serverprozess in CPU:0 aus und synchronisiert ihn mit dem dieselbe CPU mit seinem Client.
  • Der Aufrufer der zweiten Transaktion hat eine Priorität SCHED_OTHER. Der Server führt ein Downgrade selbst aus und Anrufer mit Priorität SCHED_OTHER.

Trace zur Fehlerbehebung verwenden

Sie können die Option -trace angeben, um Latenzprobleme zu beheben. Wann? stoppt der Latenztest die Tracelog-Aufzeichnung in dem Moment, in dem ein Fehler Latenz erkannt. Beispiel:

atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq
libhwbinder_latency -deadline_us 50000 -trace -i 50000 -pair 3
deadline triggered: halt ∓ stop trace
log:/sys/kernel/debug/tracing/trace

Die folgenden Komponenten können die Latenz beeinflussen:

  • Android-Build-Modus Der Entwicklungsmodus ist in der Regel langsamer als Debug-Modus.
  • Framework. Wie nutzt der Framework-Dienst ioctl für die Konfiguration für den Binder?
  • Binder-Treiber: Unterstützt der Treiber detaillierte Sperren? Enthält es alle Patches zur Leistungsumwandlung?
  • Kernel-Version Je besser der Kernel in Echtzeit ist, desto besser sind die Ergebnisse.
  • Kernel-Konfiguration Enthält die Kernel-Konfiguration DEBUG-Konfigurationen wie DEBUG_PREEMPT und DEBUG_SPIN_LOCK?
  • Kernel-Planer Hat der Kernel einen energiebewussten Planer (EAS) oder Heterogenes Multi-Processing-(HMP)-Planer? Kernel ausführen Fahrer (cpu-freq Fahrer, cpu-idle Fahrer, cpu-hotplug usw.) sich auf den Planer auswirken?