Bulk-Trace-Analyse

Wenn Sie mehrere Traces mit ProfilingManager erfasst haben, ist es nicht mehr praktikabel, sie einzeln zu untersuchen, um Leistungsprobleme zu finden. Mit der Bulk-Analyse von Traces können Sie gleichzeitig ein Dataset mit Traces abfragen, um:

  • Gängige Leistungsabfälle erkennen
  • Statistische Verteilungen berechnen (z. B. P50-, P90- und P99-Latenz).
  • Muster in mehreren Traces finden
  • Ausreißer-Traces finden, um Leistungsprobleme zu verstehen und zu beheben.

In diesem Abschnitt wird gezeigt, wie Sie den Perfetto Python Batch Trace Processor verwenden, um Startmesswerte für eine Reihe lokal gespeicherter Traces zu analysieren und Ausreißer-Traces für eine detailliertere Analyse zu finden.

Abfrage entwerfen

Der erste Schritt zum Durchführen einer Bulk-Analyse besteht darin, eine PerfettoSQL-Abfrage zu erstellen.

In diesem Abschnitt stellen wir eine Beispielabfrage vor, mit der die App-Startlatenz gemessen wird. Sie können die Dauer von activityStart bis zum ersten gerenderten Frame (dem ersten Vorkommen des Choreographer#doFrame-Abschnitts) messen, um die Latenz beim App-Start zu ermitteln, die in Ihrer App gesteuert wird. Abbildung 1 zeigt den abzufragenden Abschnitt.

Eine Zeitachse eines Traces, auf der die Dauer vom activityStart-Ereignis bis zum ersten Choreographer#doFrame-Ereignis hervorgehoben wird.
Abbildung 1. Trace-Abschnitt von `activityStart` bis zum ersten generierten Frame.
CREATE OR REPLACE PERFETTO FUNCTION find_slices(pattern STRING) RETURNS
TABLE (name STRING, ts LONG, dur LONG) AS
SELECT name,ts,dur FROM slice WHERE name GLOB $pattern;

CREATE OR REPLACE PERFETTO FUNCTION generate_start_to_end_slices(startSlicePattern STRING, endSlicePattern STRING, inclusive BOOL) RETURNS
TABLE(name STRING, ts LONG, dur LONG) AS
SELECT name, ts, MIN(startToEndDur) as dur
FROM
  (SELECT S.name as name, S.ts as ts, E.ts + IIF($inclusive, E.dur, 0) - S.ts as startToEndDur
  FROM find_slices($startSlicePattern) as S CROSS JOIN find_slices($endSlicePattern) as E
  WHERE startToEndDur > 0)
GROUP BY name, ts;

SELECT ts,name,dur from generate_start_to_end_slices('activityStart','*Choreographer#doFrame [0-9]*', true)

Sie können die Abfrage in der Perfetto-Benutzeroberfläche ausführen und dann die Abfrageergebnisse verwenden, um einen Debug-Track zu generieren (Abbildung 2) und ihn auf der Zeitachse zu visualisieren (Abbildung 3).

Ein Screenshot der Perfetto-Benutzeroberfläche, auf dem zu sehen ist, wie ein Debug-Track für eine Startanfrage erstellt wird.
Abbildung 2. Debug-Track für eine Startup-Anfrage erstellen
Eine Zeitachse in der Perfetto-Benutzeroberfläche mit einem generierten Debug-Track für eine Startanfrage.
Abbildung 3. Generierter Debug-Track für eine Startup-Anfrage.

Python-Umgebung einrichten

Installieren Sie Python auf Ihrem lokalen Computer und die erforderlichen Bibliotheken:

pip install perfetto pandas plotly

Script für die Bulk-Trace-Analyse erstellen

Das folgende Beispielscript führt die Abfrage in mehreren Traces mit Perfetto's Python BatchTraceProcessor aus.

from perfetto.batch_trace_processor import BatchTraceProcessor
import glob
import plotly.express as px

traces = glob.glob('*.perfetto-trace')

if __name__ == '__main__':
    with BatchTraceProcessor(traces) as btp:
        query = """
        CREATE OR REPLACE PERFETTO FUNCTION find_slices(pattern STRING) RETURNS
        TABLE (name STRING, ts LONG, dur LONG) AS
        SELECT name,ts,dur FROM slice WHERE name GLOB $pattern;

        CREATE OR REPLACE PERFETTO FUNCTION generate_start_to_end_slices(startSlicePattern STRING, endSlicePattern STRING, inclusive BOOL) RETURNS
        TABLE(name STRING, ts LONG, dur LONG) AS
        SELECT name, ts, MIN(startToEndDur) as dur
        FROM
          (SELECT S.name as name, S.ts as ts, E.ts + IIF($inclusive, E.dur, 0) - S.ts as startToEndDur
          FROM find_slices($startSlicePattern) as S CROSS JOIN find_slices($endSlicePattern) as E
          WHERE startToEndDur > 0)
        GROUP BY name, ts;

        SELECT ts,name,dur / 1000000 as dur_ms from generate_start_to_end_slices('activityStart','*Choreographer#doFrame [0-9]*', true)
        """
        df = btp.query_and_flatten(query)

        violin = px.violin(df, x='dur_ms', hover_data='_path', title='startup time', points='all')
        violin.show()

Das Skript verstehen

Wenn Sie das Python-Skript ausführen, werden die folgenden Aktionen ausgeführt:

  1. Das Skript sucht in Ihrem lokalen Verzeichnis nach allen Perfetto-Traces mit dem Suffix .perfetto-trace und verwendet sie als Quell-Traces für die Analyse.
  2. Es wird eine Bulk-Trace-Abfrage ausgeführt, mit der die Teilmenge der Startzeit berechnet wird, die dem Zeitraum vom activityStart-Trace-Segment bis zum ersten von Ihrer App generierten Frame entspricht.
  3. Die Latenz wird in Millisekunden in einem Violin-Plot dargestellt, um die Verteilung der Startzeiten zu visualisieren.

Ergebnisse interpretieren

Ein Violin-Diagramm mit der Verteilung der abgefragten Startlatenzen.
Abbildung 4. Violin-Diagramm der abgefragten Startlatenzen.

Nachdem Sie das Script ausgeführt haben, wird ein Diagramm generiert. In diesem Fall zeigt das Diagramm eine bimodale Verteilung mit zwei unterschiedlichen Spitzen (Abbildung 4).

Ermitteln Sie als Nächstes den Unterschied zwischen den beiden Grundgesamtheiten. So können Sie einzelne Traces genauer untersuchen. In diesem Beispiel ist das Diagramm so eingerichtet, dass Sie beim Bewegen des Mauszeigers auf die Datenpunkte (Latenzen) die Dateinamen der Traces sehen. Anschließend können Sie einen der Traces öffnen, der zur Gruppe mit hoher Latenz gehört.

Wenn Sie einen Trace aus der Gruppe mit hoher Latenz öffnen (Abbildung 5), sehen Sie einen zusätzlichen Slice mit dem Namen MyFlaggedFeature, der während des Starts ausgeführt wird (Abbildung 6). Wenn Sie hingegen einen Trace aus der Population mit geringerer Latenz (der linke Peak) auswählen, wird bestätigt, dass dieser Slice nicht vorhanden ist (Abbildung 7). Dieser Vergleich deutet darauf hin, dass ein bestimmtes Feature-Flag, das für eine Teilmenge der Nutzer aktiviert ist, die Regression auslöst.

Ein Diagramm mit einem Trace mit hoher Latenz.
Abbildung 5. Datenpunkt mit hoher Latenz in einem Violin-Plot.
Ein Trace, der den Start mit hoher Latenz aufgrund des MyFlaggedFeature-Segments hervorhebt.
Abbildung 6. Hohe Latenz beim Starten des Traces mit einem zusätzlichen Slice „MyFlaggedFeature“
Ein Trace, der den Start mit niedriger Latenz ohne den Slice „MyFlaggedFeature“ hervorhebt.
Abbildung 7. Niedrige Latenz beim Starten von Traces.

Dieses Beispiel zeigt eine der vielen Möglichkeiten, die Bulk-Analyse von Traces zu verwenden. Weitere Anwendungsfälle sind das Extrahieren von Statistiken aus dem Feld, um die Auswirkungen zu messen, Regressionen zu erkennen und vieles mehr.