Traces prüfen

Die Trace-Ansicht im CPU-Profiler bietet mehrere Möglichkeiten zum Anzeigen von Informationen aus aufgezeichneten Traces.

Für Methoden-Traces und Funktions-Traces können Sie das Aufrufdiagramm direkt in der Threads-Zeitachse und im Bereich Analyse die Tabs Flame-Diagramm, Top-down, Bottom-up und Ereignisse anzeigen. Bei Callstack-Frames können Sie sehen, welcher Teil des Codes ausgeführt wurde und warum er aufgerufen wurde. Bei System-Traces können Sie sich die Trace-Ereignisse direkt in der Threads-Zeitachse und im Bereich Analyse die Tabs Flame-Diagramm, Top-down, Bottom-up und Ereignisse ansehen.

Für eine einfachere Navigation in Anrufdiagrammen oder Trace-Ereignissen sind Maus- und Tastenkombinationen verfügbar.

Traces mit dem Aufrufdiagramm prüfen

Im Aufrufdiagramm ist ein Methoden-Trace oder ein Funktions-Trace grafisch dargestellt. Dabei werden Zeitraum und Zeitpunkt eines Aufrufs auf der horizontalen Achse und die Aufgerufenen entlang der vertikalen Achse dargestellt. Aufrufe von System-APIs werden orange, Aufrufe der eigenen Methoden Ihrer Anwendung in Grün und Aufrufe von Drittanbieter-APIs (einschließlich Java Language APIs) dargestellt. Abbildung 4 zeigt ein Beispiel für ein Aufrufdiagramm, das das Konzept der Eigenzeit, der Unterzeit und der Gesamtzeit für eine bestimmte Methode oder Funktion veranschaulicht. Weitere Informationen zu diesen Konzepten finden Sie im Abschnitt zum Prüfen von Traces mit der Top-down- und Bottom-up-Methode.

Abbildung 1: Beispiel für ein Aufrufdiagramm, das sich selbst, die untergeordneten Elemente und die Gesamtzeit für Methode D veranschaulicht

Tipp: Wenn Sie den Quellcode einer Methode oder Funktion überspringen möchten, klicken Sie mit der rechten Maustaste darauf und wählen Sie Zur Quelle springen aus. Dies funktioniert auf allen Tabs des Analysebereichs.

Traces mit dem Tab „Flame-Diagramm“ prüfen

Der Tab Flame-Diagramm enthält ein umgekehrtes Aufrufdiagramm, das identische Aufrufstacks zusammenfasst. Identische Methoden oder Funktionen, die dieselbe Sequenz von Aufrufern verwenden, werden in einem Flame-Diagramm gesammelt und als ein längerer Balken dargestellt, anstatt sie wie in einem Aufrufdiagramm als mehrere kürzere Balken anzuzeigen. So lässt sich leichter erkennen, welche Methoden oder Funktionen am meisten Zeit verbrauchen. Dies bedeutet jedoch auch, dass die horizontale Achse keine Zeitachse darstellt. Stattdessen gibt sie die relative Zeit an, die jede Methode oder Funktion für die Ausführung benötigt.

Zur Veranschaulichung dieses Konzepts ist das Aufrufdiagramm in Abbildung 2 zu sehen. Methode D führt mehrere Aufrufe von B (B1, B2 und B3) aus. Einige dieser Aufrufe an B führen einen Aufruf an C (C1 und C3) aus.

Abbildung 2: Ein Aufrufdiagramm mit mehreren Methodenaufrufen, die eine gemeinsame Sequenz von Aufrufern haben.

Da B1, B2 und B3 die gleiche Sequenz von Aufrufen haben (A → D → B), werden sie aggregiert (siehe Abbildung 3). In ähnlicher Weise werden C1 und C3 aggregiert, weil sie die gleiche Sequenz von Aufrufern haben (A → D → B → C). C2 ist nicht enthalten, da es eine andere Sequenz von Aufrufern hat (A → D → C).

Abbildung 3: Identische Methoden mit demselben Aufrufstack aggregieren

Die aggregierten Aufrufe werden verwendet, um das Flame-Diagramm zu erstellen (siehe Abbildung 4). Beachten Sie, dass bei einem bestimmten Aufruf in einem Flame-Diagramm die Aufgerufenen, die die meiste CPU-Zeit verbrauchen, zuerst angezeigt werden.

Abbildung 4: Flammendiagramm des Aufrufdiagramms aus Abbildung 5

Traces mit Top-down und Bottom-up prüfen

Der Tab Top-down enthält eine Liste von Aufrufen, bei denen beim Maximieren eines Methoden- oder Funktionsknotens die aufgerufenen Elemente angezeigt werden. Abbildung 5 zeigt ein Diagramm von oben nach unten für das Aufrufdiagramm in Abbildung 1. Jeder Pfeil in der Grafik zeigt auf einen Anrufer auf einen Aufgerufenen.

Wie in Abbildung 5 dargestellt, werden beim Erweitern des Knotens für Methode A auf dem Tab Top-down die aufgerufenen Methoden B und D angezeigt. Danach werden beim Erweitern des Knotens für Methode D die Aufgerufenen, die Methoden B, C usw. sichtbar gemacht. Ähnlich wie auf dem Tab Flame-Diagramm aggregiert der Top-down-Baum Traceinformationen für identische Methoden, die denselben Aufrufstack teilen. Das bedeutet, dass der Tab Flame-Diagramm die grafische Darstellung des Tabs Top-down enthält.

Der Tab Top-down enthält die folgenden Informationen zur Beschreibung der für jeden Aufruf aufgewendeten CPU-Zeit (die Zeiten werden auch als Prozentsatz der Gesamtzeit des Threads über den ausgewählten Bereich dargestellt):

  • Selbst:die Zeit, die für den Methoden- oder Funktionsaufruf zur Ausführung des eigenen Codes und nicht der Ausführung der Aufgerufenen benötigt wurde, wie in Abbildung 1 für Methode D dargestellt.
  • Kinder:Die Zeit, die für den Methoden- oder Funktionsaufruf zum Ausführen der Aufgerufenen und nicht des eigenen Codes benötigt wurde, wie in Abbildung 1 für Methode D dargestellt.
  • Total (Gesamt): die Summe der Zeit von Selbst und Kindern der Methode Dies stellt die Gesamtzeit dar, die die Anwendung zum Ausführen eines Aufrufs aufgewendet hat, wie in Abbildung 1 für Methode D dargestellt.

Abbildung 5: Ein Baum von oben

Abbildung 6: Bottom-up-Baum für Methode C aus Abbildung 5

Auf dem Tab Bottom-up wird eine Liste von Aufrufen angezeigt, bei denen beim Maximieren des Knotens einer Funktion oder Methode die Aufrufer angezeigt werden. Anhand des Beispiel-Traces in Abbildung 5 zeigt Abbildung 6 einen Bottom-up-Baum für Methode C. Wenn Sie den Knoten für Methode C in der unteren Baumstruktur öffnen, werden alle eindeutigen Aufrufer, Methoden B und D, angezeigt. Obwohl B C zweimal aufruft, B wird nur einmal angezeigt, wenn der Knoten für die Methode C in der Bottom-up-Baum maximiert wird. Wenn Sie anschließend den Knoten für B maximieren, werden der Aufrufer, die Methoden A und D, angezeigt.

Der Tab Bottom-up ist nützlich, um Methoden oder Funktionen nach denen zu sortieren, die die meiste (oder die geringste) CPU-Zeit verbrauchen. Sie können jeden Knoten untersuchen, um festzustellen, welche Aufrufer die meiste CPU-Zeit zum Aufrufen dieser Methoden oder Funktionen benötigen. Im Vergleich zum Top-down-Baum beziehen sich die Zeitinformationen für jede Methode oder Funktion in einem Bottom-up-Baum auf die Methode oben in jedem Baum (oberer Knoten). Die CPU-Zeit wird auch als Prozentsatz der Gesamtzeit des Threads während dieser Aufzeichnung dargestellt. In der folgenden Tabelle wird erläutert, wie die Zeitinformationen für den obersten Knoten und seine Aufrufer (Unterknoten) interpretiert werden.

dir selbst Children Gesamt
Methode oder Funktion am Anfang des Bottom-up-Baums (oberer Knoten) Stellt die Gesamtzeit dar, die für die Ausführung ihres eigenen Codes für die Methode oder Funktion aufgewendet wurde, nicht für die Aufgerufenen. Im Vergleich zum Top-down-Baum stellen diese Zeitinformationen die Summe aller Aufrufe dieser Methode oder Funktion während der Aufzeichnung dar. Stellt die Gesamtzeit dar, die für die Ausführung der Aufgerufenen der Methode oder Funktion aufgewendet wurde, nicht des eigenen Codes. Im Vergleich zum Top-down-Baum stellen diese Zeitinformationen die Summe aller Aufrufe dieser Methode oder der Aufgerufenen dieser Funktion während der Aufzeichnung dar. Die Summe aus Selbstzeit und Zeit der untergeordneten Elemente.
Aufrufer (Unterknoten) Stellt die gesamte Eigenzeit des Aufgerufenen beim Anruf durch den Aufrufer dar. Wenn Sie den Bottom-up-Baum in Abbildung 6 als Beispiel verwenden, entspricht die Eigenzeit für Methode B der Summe der Selbstzeiten für jede Ausführung von Methode C, wenn sie von B aufgerufen wird. Stellt die Gesamtzeit der untergeordneten Elemente des Aufgerufenen dar, wenn er vom Aufrufer aufgerufen wird. Wenn Sie den Bottom-up-Baum in Abbildung 6 als Beispiel verwenden, entspricht die Zeit der untergeordneten Elemente für Methode B der Summe der untergeordneten Zeiten für jede Ausführung von Methode C, wenn sie von B aufgerufen wird. Die Summe aus Selbstzeit und Zeit der untergeordneten Elemente.

Hinweis:Android Studio erfasst für eine bestimmte Aufzeichnung keine neuen Daten mehr, wenn der Profiler die maximale Dateigröße erreicht. Die Aufzeichnung wird dadurch jedoch nicht beendet. Bei instrumentierten Traces geht dies in der Regel viel schneller vor, da bei dieser Art von Tracing im Vergleich zu einer Trace-Stichprobe mehr Daten in kürzerer Zeit erfasst werden. Wenn Sie die Inspektionszeit auf einen Zeitraum der Aufzeichnung verlängern, der nach dem Erreichen des Limits erfolgt ist, ändern sich die Zeitdaten im Trace-Bereich nicht (da keine neuen Daten verfügbar sind). Wenn Sie nur den Teil einer Aufzeichnung auswählen, für den keine Daten verfügbar sind, wird im Trace-Bereich NaN für Zeitinformationen angezeigt.

Traces mit der Ereignistabelle prüfen

In der Ereignistabelle werden alle Aufrufe im aktuell ausgewählten Thread aufgelistet. Sie können sie sortieren, indem Sie auf die Spaltenüberschriften klicken. Wenn Sie eine Zeile in der Tabelle auswählen, können Sie auf der Zeitachse zur Start- und Endzeit des ausgewählten Anrufs wechseln. So lassen sich Ereignisse auf der Zeitachse genau lokalisieren.

Abbildung 7: Aufrufen des Tabs „Ereignisse“ im Bereich „Analyse“

Aufrufstack-Frames prüfen

Mithilfe von Aufrufstacks können Sie nachvollziehen, welcher Teil des Codes ausgeführt wurde und warum er aufgerufen wurde. Wenn für ein Java-/Kotlin-Programm eine Callstack-Beispielaufnahme erfasst wird, enthält der Aufrufstack in der Regel nicht nur Java-/Kotlin-Code, sondern auch Frames aus dem JNI-nativen Code, einer Java Virtual Machine (z.B. android::AndroidRuntime::start) und den System-Kernel ([kernel.kallsyms]+offset). Dies liegt daran, dass ein Java-/Kotlin-Programm normalerweise über eine Java-VM ausgeführt wird. Nativer Code ist erforderlich, um das Programm selbst auszuführen und mit dem System und der Hardware zu kommunizieren. Der Profiler präsentiert diese Frames aus Gründen der Genauigkeit. Je nach Untersuchung können diese zusätzlichen Aufrufframes jedoch nützlich oder nicht nützlich sein. Der Profiler bietet eine Möglichkeit, Frames zu minimieren, die Sie nicht interessieren. So können Sie Informationen ausblenden, die für Ihre Untersuchung irrelevant sind.

Im folgenden Beispiel enthält der Trace unten viele Frames mit dem Label [kernel.kallsyms]+offset, die derzeit nicht für die Entwicklung nützlich sind.

Beispiel für einen Aufruf-Trace

Um diese Frames zu einem zu minimieren, klicken Sie in der Symbolleiste auf die Schaltfläche Frames minimieren, wählen Sie die zu minimierenden Pfade aus und klicken Sie auf die Schaltfläche Übernehmen, um die Änderungen zu übernehmen. In diesem Beispiel lautet der Pfad [kernel.kallsyms].

Beispiel für das Menü simpleperf

Dadurch werden die Frames minimiert, die dem ausgewählten Pfad im linken und rechten Bereich entsprechen, wie unten dargestellt.

Beispiel für minimierte Frames von simpleperf

System-Traces prüfen

Bei der Untersuchung eines System-Trace können Sie Trace-Ereignisse in der Threads-Zeitachse untersuchen, um die Details der Ereignisse anzuzeigen, die in jedem Thread auftreten. Bewegen Sie den Mauszeiger auf ein Ereignis, um den Namen des Ereignisses und die in jedem Status verbrachte Zeit zu sehen. Klicken Sie auf ein Ereignis, um weitere Informationen im Bereich Analyse aufzurufen.

Systemtraces prüfen: CPU-Kerne

Neben CPU-Planungsdaten enthalten System-Traces auch die CPU-Frequenz nach Kern. Dies zeigt die Aktivitätsmenge auf jedem Kern und kann Ihnen eine Vorstellung davon geben, welche die „großen“ oder „kleinen“ Kerne in modernen mobilen Prozessoren sind.

Abbildung 8: CPU-Aktivitäts- und Trace-Ereignisse für den Renderingthread ansehen

Im Bereich CPU-Kerne (siehe Abbildung 8) wird die auf jedem Kern geplante Thread-Aktivität angezeigt. Bewegen Sie den Mauszeiger auf eine Thread-Aktivität, um zu sehen, auf welchem Thread dieser Kern zu diesem bestimmten Zeitpunkt ausgeführt wird.

Weitere Informationen zum Untersuchen von Systemtrace-Informationen finden Sie im Abschnitt UI-Leistungsprobleme untersuchen der systrace-Dokumentation.

System-Traces prüfen: Zeitachse für das Frame-Rendering

Sie können prüfen, wie lange Ihre App benötigt, um jeden Frame im Hauptthread zu rendern, und RenderThread, um Engpässe zu untersuchen, die zu UI-Verzögerungen und niedrigen Framerates führen. Informationen zur Verwendung von System-Traces zur Untersuchung und Reduzierung von UI-Verzögerungen finden Sie unter UI-Verzögerungserkennung.

System-Traces prüfen: Prozessspeicher (RSS)

Bei Apps, die auf Geräten mit Android 9 oder höher bereitgestellt werden, wird im Abschnitt Prozessspeicher (RSS) der aktuell von der App verwendete physische Speicher angezeigt.

Abbildung 9: Anzeigen des physischen Arbeitsspeichers im Profiler.

Gesamt

Dies ist die Gesamtmenge des physischen Speichers, der derzeit von Ihrem Prozess verwendet wird. Auf Unix-basierten Systemen wird dies als „Größe des Resident-Sets“ bezeichnet. Dabei handelt es sich um die Kombination aus dem gesamten Arbeitsspeicher, der von anonymen Zuordnungen, Dateizuordnungen und Zuweisungen von gemeinsam genutztem Arbeitsspeicher verwendet wird.

Bei Windows-Entwicklern entspricht die Größe des residenten Satzes der Größe des Arbeitssatzes.

Zugewiesen

Dieser Zähler verfolgt, wie viel physischer Arbeitsspeicher derzeit von den normalen Arbeitsspeicherzuweisungen des Prozesses verwendet wird. Dies sind Zuweisungen, die anonym (nicht durch eine bestimmte Datei gesichert) und privat (nicht freigegeben) sind. In den meisten Anwendungen bestehen diese aus Heap-Zuweisungen (mit malloc oder new) und Stack-Arbeitsspeicher. Beim Auslagern aus dem physischen Arbeitsspeicher werden diese Zuweisungen in die System-Auslagerungsdatei geschrieben.

Dateizuordnungen

Dieser Zähler verfolgt die Menge an physischem Arbeitsspeicher, die der Prozess für die Dateizuordnungen verwendet, d. h. den Arbeitsspeicher, der vom Speichermanager einer Arbeitsspeicherregion von Dateien zugeordnet wird.

Freigegeben

Dieser Zähler verfolgt, wie viel physischer Arbeitsspeicher für die gemeinsame Nutzung des Arbeitsspeichers zwischen diesem Prozess und anderen Prozessen im System verwendet wird.