Bewertung der Leistung

Verwenden Sie Simpleperf, um die Leistung eines Geräts zu bewerten. Simpleperf ist ein natives Profilierungstool für Anwendungen und native Prozesse auf Android. Verwenden Sie CPU Profiler , um die CPU-Auslastung und Thread-Aktivität der App in Echtzeit zu überprüfen.

Es gibt zwei für den Benutzer sichtbare Leistungsindikatoren:

  • Vorhersehbare, spürbare Leistung . Lässt die Benutzeroberfläche (UI) Frames fallen oder wird sie konstant mit 60 FPS gerendert? Lässt sich der Ton ohne Artefakte oder Knackgeräusche abspielen? Wie lang ist die Verzögerung zwischen der Berührung des Bildschirms durch den Benutzer und dem auf dem Display angezeigten Effekt?
  • Zeitaufwand für längere Vorgänge (z. B. Öffnen von Anträgen).

Das erste ist auffälliger als das zweite. Benutzer bemerken normalerweise ein Ruckeln, können jedoch nicht zwischen 500 ms und 600 ms Anwendungsstartzeit unterscheiden, es sei denn, sie betrachten zwei Geräte nebeneinander. Die Touch-Latenz ist sofort spürbar und trägt wesentlich zur Wahrnehmung eines Geräts bei.

Daher ist in einem schnellen Gerät die UI-Pipeline 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 Benutzeroberfläche nicht erforderlich sind. Um eine flüssige Benutzeroberfläche aufrechtzuerhalten, müssen die Hintergrundsynchronisierung, die Zustellung von Benachrichtigungen und ähnliche Arbeiten verzögert werden, wenn UI-Arbeiten ausgeführt werden können. Es ist akzeptabel, die Leistung längerer Vorgänge (HDR+-Laufzeit, Anwendungsstart usw.) zu beeinträchtigen, um eine flüssige Benutzeroberfläche aufrechtzuerhalten.

Kapazität vs. Jitter

Bei der Betrachtung der Geräteleistung sind Kapazität und Jitter zwei aussagekräftige Messgrößen.

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, I/O-Ressourcen, Netzwerkressourcen, Speicherbandbreite oder jede ähnliche Metrik sein. Bei der Untersuchung der Gesamtsystemleistung kann es hilfreich sein, die einzelnen Komponenten zu abstrahieren und eine einzige Metrik anzunehmen, die die Leistung bestimmt (insbesondere bei der Optimierung eines neuen Geräts, da die auf diesem Gerät ausgeführten Arbeitslasten wahrscheinlich festgelegt sind).

Die Kapazität eines Systems variiert je nach den verfügbaren Rechenressourcen. Die Änderung der CPU-/GPU-Frequenz ist das wichtigste Mittel zur Änderung der Kapazität, es gibt jedoch auch andere Möglichkeiten, wie beispielsweise die Änderung der Anzahl der CPU-Kerne online. Dementsprechend entspricht die Kapazität eines Systems 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 maßgeblich von der laufenden Anwendung bestimmt. Daher kann die Plattform wenig tun, um die für eine bestimmte Arbeitslast erforderliche Kapazität anzupassen, und die Mittel dazu beschränken sich auf Laufzeitverbesserungen (Android-Framework, ART, Bionic, GPU-Compiler/-Treiber, Kernel).

Nervosität

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 in 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 die erwartete Leistung erreichte, und ist eine großartige Einführung in die Optimierung großer Systeme.)

Auf dieser Seite wird der Begriff Jitter verwendet, um das 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 Arbeiten, die ausgeführt werden müssen, für die jedoch möglicherweise keine strengen Zeitvorgaben gelten, die dazu führen, dass sie zu einem bestimmten Zeitpunkt ausgeführt werden. Da es zufällig ist, ist es äußerst schwierig, die Existenz von Jitter für eine bestimmte Arbeitslast zu widerlegen. Es ist außerdem äußerst schwierig nachzuweisen, dass eine bekannte Jitterquelle die Ursache für ein bestimmtes Leistungsproblem war. Die am häufigsten zur Diagnose von Jitter-Ursachen verwendeten Tools (z. B. Ablaufverfolgung oder Protokollierung) können ihren eigenen Jitter verursachen.

Zu den Jitterquellen, die bei realen Android-Implementierungen auftreten, gehören:

  • Verzögerung des Planers
  • Interrupt-Handler
  • Treibercode läuft zu lange mit deaktivierter Vorbelegung oder Interrupts
  • Lang laufende Softirqs
  • Sperrkonflikt (Anwendung, Framework, Kernel-Treiber, Binder-Sperre, MMAP-Sperre)
  • Dateideskriptorkonflikt, bei dem ein Thread mit niedriger Priorität die Sperre für eine Datei hält und so die Ausführung eines Threads mit hoher Priorität verhindert
  • Ausführen von UI-kritischem Code in Arbeitswarteschlangen, wo es zu Verzögerungen kommen kann
  • CPU-Leerlaufübergänge
  • Protokollierung
  • E/A-Verzögerungen
  • Unnötige Prozesserstellung (z. B. CONNECTIVITY_CHANGE-Broadcasts)
  • Überlastung des Seiten-Cache durch unzureichenden freien Speicher

Die erforderliche Zeitspanne für eine bestimmte Jitter-Periode kann mit zunehmender Kapazität abnehmen oder auch nicht. Wenn ein Treiber beispielsweise 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 mit 384 MHz oder 2 GHz arbeitet. Eine Erhöhung der Kapazität ist keine praktikable Lösung zur Verbesserung der Leistung, wenn Jitter im Spiel ist. Daher verbessern schnellere Prozessoren die Leistung in Situationen mit eingeschränktem Jitter 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 geringen Speicheraufwand, Dienstneustarts und Überlastung des Seitencaches zu Jitter führen. Durch die Reduzierung des Speicherverbrauchs können die direkten Ursachen einer schlechten Leistung vermieden werden. Möglicherweise gibt es aber auch andere gezielte Verbesserungen, die diese Ursachen vermeiden (z. B. das Anheften des Frameworks, um zu verhindern, dass es ausgelagert wird, wenn es kurz darauf ausgelagert wird).

Analysieren der anfänglichen Geräteleistung

Von einem funktionsfähigen, aber schlecht funktionierenden System auszugehen und zu versuchen, das Verhalten des Systems durch die Betrachtung einzelner Fälle von für den Benutzer sichtbar schlechter Leistung zu korrigieren, ist keine vernünftige Strategie. Da eine schlechte Leistung normalerweise nicht leicht reproduzierbar ist (z. B. Jitter) oder ein Anwendungsproblem darstellt, verhindern zu viele Variablen im gesamten System, dass diese Strategie effektiv ist. Daher ist es sehr leicht, Ursachen falsch zu identifizieren und geringfügige Verbesserungen vorzunehmen, während gleichzeitig systemische Möglichkeiten zur Verbesserung der Leistung im gesamten System verpasst werden.

Verwenden Sie stattdessen den folgenden allgemeinen Ansatz, wenn Sie ein neues Gerät starten:

  1. Starten Sie das System über die Benutzeroberfläche mit allen laufenden Treibern und einigen grundlegenden Einstellungen des Frequenzreglers (wenn Sie die Einstellungen des Frequenzreglers ändern, wiederholen Sie alle Schritte unten).
  2. Stellen Sie sicher, dass der Kernel den Tracepoint sched_blocked_reason sowie andere Tracepoints in der Anzeigepipeline unterstützt, die angeben, wann der Frame an die Anzeige übermittelt wird.
  3. Erstellen Sie lange Spuren der gesamten UI-Pipeline (vom Eingang der Eingabe über einen IRQ bis zum endgültigen Scanout), während Sie eine leichte und konsistente Arbeitslast ausführen (z. B. UiBench oder den Balltest in TouchLatency) .
  4. Beheben Sie die Frame-Drops, die bei der leichten und konsistenten Arbeitslast erkannt wurden.
  5. Wiederholen Sie die Schritte 3 und 4, bis Sie mehr als 20 Sekunden am Stück ohne ausgelassene Frames laufen können.
  6. Gehen Sie weiter zu anderen für den Benutzer sichtbaren Quellen von Jank.

Weitere einfache Dinge, die Sie zu Beginn des Geräteaufbaus 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 ununterbrochenen Ruhezustand wechselt. Dies ist für die Leistungsanalyse von entscheidender Bedeutung, da ununterbrochener Schlaf ein sehr häufiger Indikator für Nervosität ist.
  • Stellen Sie sicher, dass Sie über ausreichende Ablaufverfolgung für die GPU- und Anzeigepipelines verfügen. Auf neueren Qualcomm-SOCs werden Tracepoints 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 in der Ablaufverfolgung zusätzliche Informationen über die Anzeigepipeline (MDSS) im Abschnitt mdss_fb0 sehen können. Auf Qualcomm-SOCs werden in der Standard-Systrace-Ansicht keine zusätzlichen Informationen zur GPU angezeigt, die Ergebnisse sind jedoch im Trace selbst vorhanden (Einzelheiten finden Sie unter „Grundlegendes zu Systrace“ ).

    Was Sie von dieser Art der Anzeigeverfolgung erwarten, ist ein einzelnes Ereignis, das direkt angibt, dass ein Frame an die Anzeige übermittelt wurde. Von dort aus können Sie feststellen, ob Sie Ihre Frametime erfolgreich erreicht haben. Wenn Ereignis X n weniger als 16,7 ms nach Ereignis 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-Fertigstellung äußerst schwierig.

Verwendung synthetischer Benchmarks

Synthetische Benchmarks sind nützlich, um sicherzustellen, dass die Grundfunktionalität eines Geräts vorhanden ist. Es ist jedoch nicht sinnvoll, Benchmarks als Stellvertreter für die wahrgenommene Geräteleistung zu betrachten.

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 der ausgelassenen Frames, 99. Perzentil-Frame-Zeit usw.). Bei synthetischen Benchmarks handelt es sich um reine Kapazitäts-Benchmarks. Jitter wirkt sich nur dadurch auf die gemessene Leistung dieser Benchmarks aus, dass er dem Massenbetrieb des Benchmarks Zeit raubt. Daher sind synthetische Benchmark-Scores als Maß für die vom Benutzer wahrgenommene Leistung meist irrelevant.

Stellen Sie sich zwei SOCs vor, auf denen Benchmark

  • 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 Punkte, ein deutlich besseres Ergebnis.

Wenn der Benchmark Aufschluss über die tatsächliche UI-Leistung gibt, wäre SOC 2 unbrauchbar. Unter der Annahme einer Bildwiederholfrequenz von 60 Hz hätte SOC 2 alle 1,5 Sekunden einen ruckelnden Frame. Währenddessen wäre SOC 1 (der langsamere SOC laut Benchmark X) vollkommen flüssig.

Verwenden von Fehlerberichten

Fehlerberichte sind manchmal für die Leistungsanalyse nützlich, aber weil sie so umfangreich sind, sind sie selten für die Fehlerbehebung bei sporadischen Jank-Problemen nützlich. Sie können einige Hinweise darauf geben, was das System zu einem bestimmten Zeitpunkt getan hat, insbesondere wenn der Fehler im Zusammenhang mit einem Anwendungsübergang aufgetreten ist (der in einem Fehlerbericht protokolliert wird). Fehlerberichte können auch darauf hinweisen, dass mit dem System ein allgemeiner Fehler vorliegt, der seine effektive Kapazität verringern 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 verfügbar und verfügt über zwei Modi: Touch-Latenz und springender Ball (um den Modus zu wechseln, klicken Sie auf die Schaltfläche in der oberen rechten Ecke).

Der Hüpfballtest ist genau so einfach, wie er scheint: Ein Ball hüpft ewig über den Bildschirm, unabhängig von der Benutzereingabe. Es ist in der Regel auch der mit Abstand schwierigste Test, perfekt zu laufen, aber je näher es kommt, ohne Bildausfälle zu laufen, desto besser wird Ihr Gerät sein. Der Hüpfballtest 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 über einen Frequenzregler verfügt; wenn das Gerät stattdessen mit festen Takten läuft, takten Sie die CPU/GPU auf nahezu das Minimum herunter beim erstmaligen Durchführen des Hüpfballtests). Wenn das System in den Ruhezustand wechselt und die Takte näher an den Leerlauf heransinken, 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 Arbeitslast so konsistent ist, können Sie die meisten Jitter-Quellen viel einfacher identifizieren als bei den meisten für den Benutzer sichtbaren Arbeitslasten, indem Sie verfolgen, was während jedes verpassten Frames genau auf dem System und nicht in der UI-Pipeline ausgeführt wird. Die niedrigeren Takte verstärken die Auswirkungen von Jitter, indem sie die Wahrscheinlichkeit erhöhen, dass Jitter einen Frame-Ausfall verursacht. Je näher die TouchLatency an 60 FPS liegt, desto unwahrscheinlicher ist es daher, dass es zu fehlerhaftem Systemverhalten kommt, das in größeren Anwendungen zu sporadischen, schwer reproduzierbaren Störungen führt.

Da Jitter oft (aber nicht immer) taktgeschwindigkeitsinvariant ist, verwenden Sie aus folgenden Gründen einen Test, der bei sehr niedrigen Taktraten ausgeführt wird, um Jitter zu diagnostizieren:

  • Nicht jeder Jitter ist taktgeschwindigkeitsinvariant; Viele Quellen verbrauchen nur CPU-Zeit.
  • Der Gouverneur sollte die durchschnittliche Frame-Zeit durch Heruntertakten nahe am Stichtag erreichen, sodass die Zeit, die er mit der Ausführung von Nicht-UI-Arbeiten verbringt, zu einem Frame-Ausfall führen kann.