Verwenden Sie Simpleperf, um die Leistung eines Geräts zu bewerten. Simpleperf ist ein natives Profilerstellungstool für Apps und native Prozesse unter Android. Mit dem CPU-Profiler können Sie die CPU-Nutzung und Threadaktivität der App in Echtzeit untersuchen.
Es gibt zwei für Nutzer sichtbare Leistungsindikatoren:
- Vorhersagbare, wahrnehmbare Leistung: Werden auf der Benutzeroberfläche Frames ausgelassen oder wird sie durchgehend mit 60 FPS gerendert? Wird Audio ohne Artefakte oder Knackgeräusche wiedergegeben? Wie lange dauert es, bis der Effekt auf dem Display angezeigt wird, nachdem der Nutzer das Display berührt hat?
- Dauer längerer Vorgänge, z. B. das Öffnen von Apps.
Die erste ist auffälliger als die zweite. Nutzer bemerken in der Regel Ruckeln, können aber nicht zwischen einer App-Startzeit von 500 ms und 600 ms unterscheiden, es sei denn, sie sehen sich zwei Geräte nebeneinander an. Die Berührungslatenz ist sofort spürbar und trägt erheblich zur Wahrnehmung eines Geräts bei.
Auf einem schnellen Gerät ist die UI-Pipeline daher das Wichtigste im System, abgesehen von dem, was erforderlich ist, um die UI-Pipeline funktionsfähig zu halten. Das bedeutet, dass die UI-Pipeline alle anderen Arbeiten, die für eine flüssige Benutzeroberfläche nicht erforderlich sind, unterbrechen sollte. Damit die Benutzeroberfläche flüssig bleibt, müssen die Hintergrundsynchronisierung, die Benachrichtigungsübermittlung und ähnliche Aufgaben verzögert werden, wenn Aufgaben für die Benutzeroberfläche ausgeführt werden können. Es ist akzeptabel, die Leistung längerer Vorgänge (HDR+-Laufzeit, App-Start usw.) zu beeinträchtigen, um eine flüssige Benutzeroberfläche zu erhalten.
Kapazität im Vergleich zu Jitter
Bei der Betrachtung der Geräteleistung sind Kapazität und Jitter zwei wichtige Messwerte.
Kapazität
Die Kapazität ist die Gesamtmenge einer Ressource, die das Gerät über einen bestimmten Zeitraum hinweg besitzt. Das können CPU-Ressourcen, GPU-Ressourcen, E/A-Ressourcen, Netzwerkressourcen, Speicherbandbreite oder ähnliche Messwerte sein. Bei der Untersuchung der Leistung des gesamten Systems kann es hilfreich sein, die einzelnen Komponenten zu abstrahieren und von einem einzelnen Messwert auszugehen, der die Leistung bestimmt (insbesondere beim Optimieren eines neuen Geräts, da die auf diesem Gerät ausgeführten Arbeitslasten wahrscheinlich festgelegt sind).
Die Kapazität eines Systems hängt von den verfügbaren Computing-Ressourcen ab. Die CPU-/GPU-Frequenz ist die primäre Methode zum Ändern der Kapazität. Es gibt jedoch auch andere, z. B. das Ändern der Anzahl der Online-CPU-Kerne. Die Kapazität eines Systems entspricht also dem Stromverbrauch. Eine Änderung der Kapazität führt immer zu einer ähnlichen Änderung des Stromverbrauchs.
Die zu einem bestimmten Zeitpunkt erforderliche Kapazität wird hauptsächlich durch die ausgeführte App bestimmt. Daher kann die Plattform nur wenig tun, um die für eine bestimmte Arbeitslast erforderliche Kapazität anzupassen. Die Möglichkeiten dazu sind auf Laufzeitverbesserungen (Android-Framework, ART, Bionic, GPU-Compiler/Treiber, Kernel) beschränkt.
Jitter
Die erforderliche Kapazität für eine Arbeitslast ist leicht zu erkennen, Jitter ist jedoch ein ungenauerer Begriff. Eine gute Einführung in Jitter als Hindernis für schnelle Systeme finden Sie im Artikel The Case of the Missing Supercomputer Performance: Achieving Optimal Performance on the 8,192 processors of ASCI Q. (Darin wird untersucht, warum der ASCI-Supercomputer nicht die erwartete Leistung erbracht hat. Es ist eine gute Einführung in die Optimierung großer Systeme.)
Auf dieser Seite wird der Begriff „Jitter“ verwendet, um das zu beschreiben, was im ASCI Q-Dokument als Rauschen bezeichnet wird. Jitter ist das zufällige Systemverhalten, das verhindert, dass wahrnehmbare Arbeit ausgeführt wird. Es handelt sich oft um Aufgaben, die ausgeführt werden müssen, aber möglicherweise keine strengen Zeitvorgaben haben, die dazu führen, dass sie zu einem bestimmten Zeitpunkt ausgeführt werden. Da er zufällig ist, ist es äußerst schwierig, das Vorhandensein von Jitter für eine bestimmte Arbeitslast zu widerlegen. Es ist auch äußerst schwierig, nachzuweisen, dass eine bekannte Quelle für Jitter die Ursache eines bestimmten Leistungsproblems war. Die Tools, die am häufigsten zur Diagnose von Jitter-Ursachen verwendet werden (z. B. Tracing oder Logging), können selbst Jitter verursachen.
In der Praxis können folgende Quellen für Jitter auftreten:
- Planerverzögerung
- Unterbrechungs-Handler
- Der Treibercode wird zu lange ausgeführt, während Preemption oder Interrupts deaktiviert sind.
- Softirqs mit langer Ausführungszeit
- Sperrenkonflikt (App, Framework, Kerneltreiber, Binder-Sperre, mmap-Sperre)
- Konflikte bei Dateideskriptoren, bei denen ein Thread mit niedriger Priorität die Sperre für eine Datei hält und so verhindert, dass ein Thread mit hoher Priorität ausgeführt wird
- Ausführen von UI-kritischem Code in Arbeitswarteschlangen, in denen er verzögert werden könnte
- CPU-Leerlaufübergänge
- Protokollierung
- E/A-Verzögerungen
- Unnötige Prozessgenerierung (z. B.
CONNECTIVITY_CHANGE
-Broadcasts) - Page-Cache-Thrashing aufgrund von unzureichendem kostenlosen Arbeitsspeicher
Die erforderliche Zeit für einen bestimmten Jitter-Zeitraum kann mit zunehmender Kapazität abnehmen oder nicht. Wenn ein Treiber beispielsweise Interrupts deaktiviert lässt, während er auf einen Lesevorgang über einen I2C-Bus wartet, dauert dies unabhängig davon, ob die CPU mit 384 MHz oder 2 GHz läuft, eine bestimmte Zeit. Eine Erhöhung der Kapazität ist keine praktikable Lösung zur Verbesserung der Leistung, wenn Jitter auftritt. Schnellere Prozessoren verbessern die Leistung in Situationen mit Jitter-Beschränkungen daher in der Regel nicht.
Im Gegensatz zur Kapazität liegt Jitter fast ausschließlich im Verantwortungsbereich des Systemanbieters.
Arbeitsspeicherverbrauch
Traditionell wird der Speicherverbrauch für eine schlechte Leistung verantwortlich gemacht. Der Verbrauch an sich ist kein Leistungsproblem, kann aber durch den Overhead von „lowmemorykiller“, Dienstneustarts und Page-Cache-Thrashing zu Jitter führen. Durch die Reduzierung des Arbeitsspeicherverbrauchs können die direkten Ursachen für schlechte Leistung vermieden werden. Es gibt jedoch möglicherweise andere gezielte Verbesserungen, die diese Ursachen ebenfalls vermeiden (z. B. das Anpinnen des Frameworks, um zu verhindern, dass es ausgelagert wird, wenn es kurz darauf wieder ausgelagert wird).
Erste Geräteleistung analysieren
Es ist keine gute Strategie, mit einem funktionierenden, aber schlecht funktionierenden System zu beginnen und zu versuchen, das Verhalten des Systems zu korrigieren, indem man sich einzelne Fälle von schlechter Leistung ansieht, die für Nutzer sichtbar sind. Da sich eine schlechte Leistung in der Regel nicht einfach reproduzieren lässt (z. B. Jitter) oder ein App-Problem ist, verhindern zu viele Variablen im Gesamtsystem, dass diese Strategie effektiv ist. Daher ist es sehr einfach, Ursachen falsch zu identifizieren und nur geringfügige Verbesserungen vorzunehmen, während systemische Möglichkeiten zur Leistungssteigerung im gesamten System übersehen werden.
Verwenden Sie stattdessen den folgenden allgemeinen Ansatz, wenn Sie ein neues Gerät in Betrieb nehmen:
- Sorgen Sie dafür, dass das System mit allen Treibern und einigen grundlegenden Einstellungen für den Frequenz-Governor (falls Sie die Einstellungen für den Frequenz-Governor ändern, wiederholen Sie alle Schritte unten) in der Benutzeroberfläche startet.
- Der Kernel muss den
sched_blocked_reason
-Tracepoint sowie andere Tracepoints in der Display-Pipeline unterstützen, die angeben, wann der Frame an das Display gesendet wird. - Erstelle lange Traces der gesamten UI-Pipeline (vom Empfangen der Eingabe über einen IRQ bis zum endgültigen Scanout), während eine einfache und konsistente Arbeitslast ausgeführt wird (z. B. UiBench oder der Balltest in TouchLatency).
- Behebe die Frame-Drops, die in der leichten und konsistenten Arbeitslast erkannt wurden.
- Wiederhole die Schritte 3 und 4, bis du mindestens 20 Sekunden lang ohne Frame-Drops laufen kannst.
- Fahren Sie mit anderen für Nutzer sichtbaren Quellen für Ruckeln fort.
Weitere einfache Dinge, die Sie zu Beginn der Geräteinbetriebnahme tun können, sind:
- Prüfen Sie, ob Ihr Kernel den sched_blocked_reason-Tracepoint-Patch enthält. Dieser Tracepoint wird mit der Tracekategorie „sched“ in systrace aktiviert und gibt die Funktion an, die für das Ruhen verantwortlich ist, wenn der Thread in den nicht unterbrechbaren Ruhezustand wechselt. Das ist wichtig für die Leistungsanalyse, da ununterbrochener Schlaf ein sehr häufiger Indikator für Jitter ist.
- Achten Sie darauf, dass Sie genügend Tracing für die GPU- und Display-Pipelines haben. Bei aktuellen Qualcomm-SOCs werden Tracepoints mit folgendem Befehl aktiviert:
adb shell "echo 1 > /d/tracing/events/kgsl/enable"
adb shell "echo 1 > /d/tracing/events/mdss/enable"
Diese Ereignisse bleiben aktiviert, wenn Sie systrace ausführen. So können Sie im mdss_fb0
-Abschnitt zusätzliche Informationen zur Display-Pipeline (MDSS) im Trace sehen. Auf Qualcomm-SOCs werden in der Standard-Systrace-Ansicht keine zusätzlichen Informationen zur GPU angezeigt, die Ergebnisse sind jedoch im Trace selbst vorhanden (weitere Informationen finden Sie unter Systrace verstehen).
Bei dieser Art von Display-Tracing ist ein einzelnes Ereignis erforderlich, das direkt angibt, dass ein Frame auf dem Display angezeigt wurde. Dort können Sie feststellen, ob Sie die Frame-Zeit eingehalten haben.Wenn Ereignis Xn weniger als 16,7 ms nach Ereignis Xn-1 auftritt (bei einem 60‑Hz-Display), wissen Sie, dass es nicht zu Rucklern gekommen ist. Wenn Ihr SOC solche Signale nicht bereitstellt, wenden Sie sich an Ihren Anbieter, um sie zu erhalten. Das Debuggen von Jitter ist ohne ein eindeutiges Signal für den Abschluss eines Frames äußerst schwierig.
Synthetische Benchmarks verwenden
Synthetische Benchmarks sind nützlich, um sicherzustellen, dass die grundlegenden Funktionen eines Geräts vorhanden sind. Benchmarks als Proxy für die wahrgenommene Geräteleistung zu verwenden, ist jedoch nicht sinnvoll.
Basierend auf Erfahrungen mit SOCs korrelieren Unterschiede in der Leistung synthetischer Benchmarks zwischen SOCs nicht mit einem ähnlichen Unterschied in der wahrnehmbaren UI-Leistung (Anzahl der ausgelassenen Frames, Frame-Zeit im 99. Perzentil usw.). Synthetische Benchmarks sind reine Kapazitätsbenchmarks. Jitter wirkt sich auf die gemessene Leistung dieser Benchmarks nur aus, indem er Zeit von der Bulk-Operation des Benchmarks stiehlt. Daher sind synthetische Benchmark-Werte als Messwert für die von Nutzern wahrgenommene Leistung meist irrelevant.
Stellen Sie sich zwei SOCs vor, auf denen Benchmark X ausgeführt wird. Dabei werden 1.000 UI-Frames gerendert und die gesamte Renderingzeit wird gemeldet (ein niedrigerer Wert ist besser).
- SOC 1 rendert jeden Frame von Benchmark X in 10 ms und erreicht einen Wert von 10.000.
- SOC 2 rendert 99% der Frames in 1 ms,aber 1% der Frames in 100 ms und erreicht einen Wert von 19.900, was ein deutlich besserer Wert ist.
Wenn der Benchmark die tatsächliche UI-Leistung widerspiegelt, wäre SOC 2 unbrauchbar. Bei einer Aktualisierungsrate von 60 Hz würde SOC 2 alle 1, 5 Sekunden einen ruckeligen Frame haben. SOC 1 (der laut Benchmark X langsamere SOC) wäre hingegen flüssig.
Fehlerberichte verwenden
Fehlerberichte sind manchmal für die Leistungsanalyse nützlich, aber da sie so umfangreich sind, sind sie selten für das Debugging von sporadischen Rucklern geeignet. Sie können Hinweise darauf geben, was das System zu einem bestimmten Zeitpunkt getan hat, insbesondere wenn das Ruckeln bei einem App-Übergang aufgetreten ist (was in einem Fehlerbericht protokolliert wird). Fehlerberichte können auch darauf hinweisen, wenn etwas mit dem System nicht stimmt, was seine effektive Kapazität verringern könnte (z. B. thermisches Throttling oder Speicherfragmentierung).
TouchLatency verwenden
Mehrere Beispiele für schlechtes Verhalten stammen von TouchLatency, der bevorzugten periodischen Arbeitslast für das Pixel und das Pixel XL. Das Tool ist unter frameworks/base/tests/TouchLatency
verfügbar und hat zwei Modi: „Touch-Latenz“ und „Bouncing Ball“. Wenn Sie den Modus wechseln möchten, klicken Sie auf die Schaltfläche oben rechts.
Der Bouncing-Ball-Test ist genau so einfach, wie er aussieht: Ein Ball hüpft unabhängig von der Nutzereingabe unendlich lange auf dem Bildschirm herum. Er ist in der Regel auch mit Abstand der schwierigste Test, der perfekt ausgeführt werden kann. Je näher er jedoch an der Ausführung ohne Frame-Drops liegt, desto besser ist Ihr Gerät. Der Bouncing-Ball-Test ist schwierig, da er eine triviale, aber perfekt konsistente Arbeitslast ist, die mit einer sehr niedrigen Taktfrequenz ausgeführt wird. Dies setzt voraus, dass das Gerät einen Frequenzregler hat. Wenn das Gerät stattdessen mit festen Taktfrequenzen betrieben wird, takten Sie die CPU/GPU beim ersten Ausführen des Bouncing-Ball-Tests auf nahezu das Minimum herunter. Wenn das System in den Ruhezustand wechselt und die Taktfrequenz sich dem Leerlauf nähert, steigt die erforderliche CPU-/GPU-Zeit pro Frame. Sie können den Ball beobachten und sehen, wie er ruckelt. Außerdem können Sie in Systrace auch fehlende Frames sehen.
Da die Arbeitslast so konsistent ist, lassen sich die meisten Quellen für Jitter viel leichter identifizieren als bei den meisten für Nutzer sichtbaren Arbeitslasten. Dazu wird verfolgt, was genau auf dem System während jedes ausgelassenen Frames ausgeführt wird, anstatt der UI-Pipeline. Die niedrigeren Taktfrequenzen verstärken die Auswirkungen von Jitter, da die Wahrscheinlichkeit steigt, dass Jitter zu einem Frame-Drop führt. Je näher TouchLatency an 60 fps liegt, desto geringer ist die Wahrscheinlichkeit, dass es zu schlechtem Systemverhalten kommt, das in größeren Apps zu sporadischen, schwer zu reproduzierenden Rucklern führt.
Da Jitter oft (aber nicht immer) unabhängig von der Taktfrequenz ist, sollten Sie einen Test mit sehr niedrigen Takten verwenden, um Jitter aus den folgenden Gründen zu diagnostizieren:
- Nicht aller Jitter ist taktfrequenzinvariant. Viele Quellen verbrauchen einfach CPU-Zeit.
- Der Governor sollte die durchschnittliche Frame-Zeit durch Heruntertakten an die Deadline anpassen. Die Zeit, die für die Ausführung von Nicht-UI-Aufgaben aufgewendet wird, kann dazu führen, dass ein Frame ausgelassen wird.