Verwenden Sie Simpleperf , um die Leistung eines Geräts zu bewerten. Simpleperf ist ein natives Profiling-Tool für Anwendungen und native Prozesse auf Android. Verwenden Sie den CPU-Profiler , um die CPU-Auslastung der App und die Thread-Aktivität in Echtzeit zu überprüfen.
Es gibt zwei für den Benutzer sichtbare Leistungsindikatoren:
- Vorhersehbare, wahrnehmbare Leistung . Lässt die Benutzeroberfläche (UI) Frames fallen oder wird sie durchgehend mit 60 FPS gerendert? Wird Audio ohne Artefakte oder Knackgeräusche abgespielt? Wie lang ist die Verzögerung zwischen dem Berühren des Bildschirms durch den Benutzer und dem Anzeigen des Effekts auf dem Display?
- Benötigte Zeit für längere Vorgänge (z. B. das Öffnen von Anwendungen).
Das erste ist auffälliger als das zweite. Benutzer bemerken in der Regel einen Jank, aber sie können 500 ms gegenüber 600 ms Anwendungsstartzeit nicht erkennen, es sei denn, sie betrachten zwei Geräte nebeneinander. Die Berührungslatenz ist sofort spürbar und trägt maßgeblich zur Wahrnehmung eines Geräts bei.
Folglich ist die UI-Pipeline in einem schnellen Gerät das Wichtigste im System, abgesehen von dem, was notwendig ist, um die UI-Pipeline funktionsfähig zu halten. Dies bedeutet, dass die UI-Pipeline alle anderen Arbeiten vorwegnehmen sollte, die für eine flüssige UI nicht erforderlich sind. Um eine reibungslose Benutzeroberfläche aufrechtzuerhalten, müssen die Hintergrundsynchronisierung, die Benachrichtigungszustellung und ähnliche Arbeiten verzögert werden, wenn die Benutzeroberflächenarbeit ausgeführt werden kann. Es ist akzeptabel, die Leistung längerer Vorgänge (HDR+-Laufzeit, Anwendungsstart usw.) zu opfern, um eine flüssige Benutzeroberfläche beizubehalten.
Kapazität vs. Jitter
Bei der Betrachtung der Geräteleistung sind Kapazität und Jitter zwei aussagekräftige Metriken.
Kapazität
Die Kapazität ist die Gesamtmenge einer Ressource, die das Gerät über einen bestimmten Zeitraum besitzt. Dies können CPU-Ressourcen, GPU-Ressourcen, E/A-Ressourcen, Netzwerkressourcen, Speicherbandbreite oder eine ähnliche Metrik sein. Bei der Untersuchung der Gesamtsystemleistung kann es hilfreich sein, die einzelnen Komponenten zu abstrahieren und eine einzelne Metrik anzunehmen, die die Leistung bestimmt (insbesondere beim Optimieren eines neuen Geräts, da die auf diesem Gerät ausgeführten Workloads wahrscheinlich festgelegt sind).
Die Kapazität eines Systems hängt von den Online-Rechenressourcen ab. Das Ändern der CPU/GPU-Frequenz ist das primäre Mittel zum Ändern der Kapazität, aber es gibt noch andere, wie z. B. das Ändern der Anzahl der CPU-Kerne online. Dementsprechend entspricht die Kapazität eines Systems der Leistungsaufnahme; Eine Änderung der Kapazität führt immer zu einer ähnlichen Änderung des Stromverbrauchs.
Die jeweils benötigte Kapazität wird maßgeblich von der laufenden Anwendung bestimmt. Infolgedessen kann die Plattform wenig tun, um die erforderliche Kapazität für eine bestimmte Arbeitslast anzupassen, und die Mittel dazu beschränken sich auf Laufzeitverbesserungen (Android-Framework, ART, Bionic, GPU-Compiler/-Treiber, Kernel).
Zittern
Während die erforderliche Kapazität für eine Arbeitslast leicht zu erkennen ist, ist Jitter ein eher nebulöses Konzept. Eine gute Einführung in Jitter als Hindernis für schnelle Systeme finden Sie unter THE CASE OF THE MISSING SUPERCOMPUTER PERFORMANCE: ACHIEVING OPTIMAL PERFORMANCE ON THE 8.192 PROCESSORS OF ASCl Q . (Es handelt sich um eine Untersuchung, warum der ASCI-Q-Supercomputer nicht seine erwartete Leistung erzielt hat, und ist eine großartige Einführung in die Optimierung großer Systeme.)
Auf dieser Seite wird der Begriff Jitter verwendet, um zu beschreiben, was das ASCI Q-Papier als Rauschen bezeichnet. Jitter ist das zufällige Systemverhalten, das die Ausführung wahrnehmbarer Arbeit verhindert. Es handelt sich häufig um Arbeit, die ausgeführt werden muss, aber es gibt möglicherweise keine strengen zeitlichen Anforderungen, die dazu führen, dass sie zu einem bestimmten Zeitpunkt ausgeführt werden. Da es 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 von Jitter die Ursache für ein bestimmtes Leistungsproblem war. Die am häufigsten verwendeten Werkzeuge zur Diagnose von Jitter-Ursachen (z. B. Ablaufverfolgung oder Protokollierung) können ihren eigenen Jitter einführen.
Quellen von Jitter, die in realen Implementierungen von Android auftreten, umfassen:
- Scheduler-Verzögerung
- Interrupt-Handler
- Treibercode wird zu lange ausgeführt, wobei Preemption oder Interrupts deaktiviert sind
- Langlaufende Softirqs
- Sperrkonflikte (Anwendung, Framework, Kernel-Treiber, Bindersperre, mmap-Sperre)
- Dateideskriptorkonflikt, bei dem ein Thread mit niedriger Priorität die Sperre für eine Datei hält und verhindert, dass ein Thread mit hoher Priorität ausgeführt wird
- Ausführen von UI-kritischem Code in Arbeitswarteschlangen, wo er verzögert werden könnte
- CPU-Leerlaufübergänge
- Protokollierung
- E/A-Verzögerungen
- Unnötige Prozesserstellung (z. B. CONNECTIVITY_CHANGE-Broadcasts)
- Seiten-Cache-Thrashing, verursacht durch unzureichenden freien Speicher
Die erforderliche Zeitdauer für eine gegebene Jitter-Periode kann mit zunehmender Kapazität abnehmen oder nicht. Wenn beispielsweise ein Treiber Interrupts deaktiviert lässt, während er auf einen Lesevorgang über einen i2c-Bus wartet, dauert dies eine festgelegte Zeitspanne, unabhängig davon, ob die CPU auf 384 MHz oder 2 GHz läuft. Das Erhöhen der Kapazität ist keine praktikable Lösung, um die Leistung zu verbessern, wenn Jitter im Spiel ist. Infolgedessen verbessern schnellere Prozessoren die Leistung in Jitter-beschränkten Situationen normalerweise nicht.
Schließlich liegt Jitter im Gegensatz zur Kapazität fast ausschließlich in der Domäne des Systemanbieters.
Speicherverbrauch
Der Speicherverbrauch wird traditionell für schlechte Leistung verantwortlich gemacht. Obwohl der Verbrauch selbst kein Leistungsproblem darstellt, kann er durch Low-Memorykiller-Overhead, Dienstneustarts und Seiten-Cache-Thrashing zu Jitter führen. Das Reduzieren des Speicherverbrauchs kann die direkten Ursachen für eine schlechte Leistung vermeiden, aber es kann auch andere gezielte Verbesserungen geben, die diese Ursachen vermeiden (z. B. das Fixieren des Frameworks, um zu verhindern, dass es ausgelagert wird, wenn es bald darauf ausgelagert wird).
Analysieren der anfänglichen Geräteleistung
Von einem funktionierenden, aber schlecht funktionierenden System auszugehen und zu versuchen, das Verhalten des Systems zu korrigieren, indem man einzelne Fälle von für den Benutzer sichtbar schlechter Leistung betrachtet, ist keine vernünftige Strategie. Da eine schlechte Leistung normalerweise nicht leicht reproduzierbar ist (z. B. Jitter) oder ein Anwendungsproblem ist, verhindern zu viele Variablen im gesamten System, dass diese Strategie effektiv ist. Infolgedessen ist es sehr einfach, Ursachen falsch zu identifizieren und geringfügige Verbesserungen vorzunehmen, während systemische Möglichkeiten zur Behebung der Leistung im gesamten System verpasst werden.
Verwenden Sie stattdessen den folgenden allgemeinen Ansatz, wenn Sie ein neues Gerät aufrufen:
- Bringen Sie das System dazu, mit allen Treibern und einigen grundlegenden Einstellungen des Frequenzreglers über die Benutzeroberfläche zu booten (wenn Sie die Einstellungen des Frequenzreglers ändern, wiederholen Sie alle nachstehenden Schritte).
- Stellen Sie sicher, dass der Kernel den
sched_blocked_reason
sched_blocked_reason sowie andere Ablaufverfolgungspunkte in der Anzeigepipeline unterstützt, die angeben, wann der Frame an die Anzeige geliefert wird. - Machen Sie lange Spuren der gesamten UI-Pipeline (vom Empfangen von Eingaben über einen IRQ bis zum endgültigen Scanout), während Sie eine leichte und konsistente Arbeitslast ausführen (z. B. UiBench oder den Ball-Test in TouchLatency) .
- Korrigieren Sie die Frame-Drops, die in der leichten und konsistenten Arbeitslast erkannt wurden.
- Wiederholen Sie die Schritte 3-4, bis Sie mehr als 20 Sekunden lang ohne ausgelassene Frames laufen können.
- Fahren Sie mit anderen für den Benutzer sichtbaren Jank-Quellen fort.
Andere einfache Dinge, die Sie schon früh beim Geräteaufruf tun können, sind:
- Stellen Sie sicher, dass Ihr Kernel über den Tracepoint-Patch sched_blocked_reason verfügt . Dieser Tracepoint wird mit der Trace-Kategorie „sched“ in systrace aktiviert und stellt die Funktion bereit, die für den Ruhezustand verantwortlich ist, wenn dieser Thread in den unterbrechungsfreien Ruhezustand wechselt. Dies ist für die Leistungsanalyse von entscheidender Bedeutung, da ein unterbrechungsfreier Ruhezustand ein sehr häufiger Indikator für Jitter ist.
- Stellen Sie sicher, dass Sie über ausreichende Ablaufverfolgung für die GPU- und Anzeigepipelines verfügen. Bei aktuellen Qualcomm SOCs werden Ablaufverfolgungspunkte aktiviert mit:
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, sodass Sie zusätzliche Informationen in der Ablaufverfolgung über die Anzeigepipeline (MDSS) im Abschnitt mdss_fb0
. Auf Qualcomm SOCs sehen Sie keine zusätzlichen Informationen über die GPU in der standardmäßigen Systrace-Ansicht, aber die Ergebnisse sind in der Ablaufverfolgung selbst vorhanden (Einzelheiten finden Sie unter Grundlegendes zu Systrace ).
Was Sie von dieser Art der Anzeigeverfolgung erwarten, ist ein einzelnes Ereignis, das direkt anzeigt, dass ein Frame an die Anzeige geliefert wurde. Von dort aus können Sie feststellen, ob Sie Ihre Frame-Zeit erfolgreich erreicht haben. Wenn das Ereignis X n weniger als 16,7 ms nach dem Ereignis X n-1 auftritt (unter der Annahme einer 60-Hz-Anzeige), dann wissen Sie, dass Sie nicht gesprungen sind. Wenn Ihr SOC solche Signale nicht bereitstellt, arbeiten Sie mit Ihrem Anbieter zusammen, um sie zu erhalten. Das Debuggen von Jitter ist ohne ein definitives Signal der Frame-Vervollständigung extrem schwierig.
Verwendung synthetischer Benchmarks
Synthetische Benchmarks sind nützlich, um sicherzustellen, dass die grundlegende Funktionalität eines Geräts vorhanden ist. Es ist jedoch nicht sinnvoll, Benchmarks als Proxy für die wahrgenommene Geräteleistung zu behandeln.
Basierend auf Erfahrungen mit SOCs korrelieren Unterschiede in der synthetischen Benchmark-Leistung zwischen SOCs nicht mit einem ähnlichen Unterschied in der wahrnehmbaren UI-Leistung (Anzahl ausgelassener Frames, 99. Perzentil-Frame-Zeit usw.). Synthetische Benchmarks sind reine Kapazitäts-Benchmarks; Jitter wirkt sich nur auf die gemessene Leistung dieser Benchmarks aus, indem er Zeit aus der Massenoperation des Benchmarks stiehlt. Infolgedessen sind synthetische Benchmark-Ergebnisse als Maß für die vom Benutzer wahrgenommene Leistung meist irrelevant.
Stellen Sie sich zwei SOCs vor, auf denen Benchmark X ausgeführt wird, das 1000 Frames der Benutzeroberfläche rendert und die gesamte Renderzeit meldet (ein niedrigerer Wert ist besser).
- SOC 1 rendert jeden Frame von Benchmark X in 10 ms und erzielt 10.000 Punkte.
- SOC 2 rendert 99 % der Frames in 1 ms, aber 1 % der Frames in 100 ms und erzielt 19.900, eine dramatisch bessere Punktzahl.
Wenn der Benchmark die tatsächliche UI-Leistung anzeigt, wäre SOC 2 unbrauchbar. Unter der Annahme einer Bildwiederholfrequenz von 60 Hz würde SOC 2 alle 1,5 Sekunden des Betriebs einen ruckartigen Frame aufweisen. Währenddessen wäre SOC 1 (der langsamere SOC gemäß Benchmark X) vollkommen flüssig.
Verwenden von Fehlerberichten
Fehlerberichte sind manchmal nützlich für die Leistungsanalyse, aber weil sie so schwergewichtig sind, sind sie selten nützlich, um sporadische Jank-Probleme zu debuggen. Sie können einige Hinweise darauf geben, was das System zu einem bestimmten Zeitpunkt getan hat, insbesondere wenn der Jank um einen Anwendungsübergang herum war (der in einem Fehlerbericht protokolliert wird). Fehlerberichte können auch darauf hinweisen, wenn etwas allgemeineres mit dem System nicht stimmt, was seine effektive Kapazität reduzieren könnte (z. B. thermische Drosselung oder Speicherfragmentierung).
Verwenden von TouchLatency
Mehrere Beispiele für schlechtes Verhalten stammen von TouchLatency, der bevorzugten periodischen Arbeitslast, die für Pixel und Pixel XL verwendet wird. Es ist unter frameworks/base/tests/TouchLatency
und hat zwei Modi: Berührungslatenz und springender Ball (um zwischen den Modi zu wechseln, klicken Sie auf die Schaltfläche in der oberen rechten Ecke).
Der Hüpfball-Test ist genau so einfach, wie es scheint: Ein Ball hüpft für immer über den Bildschirm, unabhängig von Benutzereingaben. Es ist normalerweise auch bei weitem der schwierigste Test, perfekt zu laufen, aber je näher er dem Laufen ohne Dropped Frames kommt, desto besser wird Ihr Gerät sein. Der Bouncing-Ball-Test ist schwierig, da es sich um eine triviale, aber vollkommen konsistente Arbeitslast handelt, die mit einem sehr niedrigen Takt läuft (dies setzt voraus, dass das Gerät einen Frequenzregler hat; wenn das Gerät stattdessen mit festen Takten läuft, takten Sie die CPU/GPU auf nahezu das Minimum herunter beim ersten Durchführen des Prellball-Tests). Wenn das System in den Ruhezustand versetzt wird und die Takte näher an den Leerlauf herankommen, erhöht sich die erforderliche CPU/GPU-Zeit pro Frame. Sie können den Ball beobachten und sehen, wie die Dinge ruckeln, und Sie können auch verpasste Frames in Systrace sehen.
Da die Workload so konsistent ist, können Sie die meisten Quellen von Jitter viel einfacher identifizieren als bei den meisten für den Benutzer sichtbaren Workloads, indem Sie nachverfolgen, was genau während jedes verpassten Frames auf dem System ausgeführt wird, anstatt der UI-Pipeline. Die niedrigeren Takte verstärken die Auswirkungen von Jitter, indem sie es wahrscheinlicher machen, dass Jitter einen ausgelassenen Frame verursacht. Je näher die TouchLatency an 60 FPS liegt, desto unwahrscheinlicher ist es, dass Sie ein schlechtes Systemverhalten haben, das in größeren Anwendungen sporadischen, schwer reproduzierbaren Ruckeln verursacht.
Da Jitter häufig (aber nicht immer) taktinvariant ist, verwenden Sie einen Test, der bei sehr niedrigen Taktraten ausgeführt wird, um Jitter aus folgenden Gründen zu diagnostizieren:
- Nicht jeder Jitter ist taktinvariant; Viele Quellen verbrauchen nur CPU-Zeit.
- Der Governor sollte die durchschnittliche Frame-Zeit in die Nähe der Deadline bringen, indem er heruntertaktet, sodass die Zeit, die mit der Ausführung von Nicht-UI-Arbeiten verbracht wird, ihn über den Rand bringen kann, um einen Frame zu löschen.