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-Trace-Analyse können Sie ein Dataset von Traces gleichzeitig abfragen, um:

  • Häufige Leistungsregressionen identifizieren
  • Berechnen Sie statistische Verteilungen (z. B. P50-, P90-, 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 mit dem Perfetto Python Batch Trace Processor Startmesswerte für eine Reihe lokal gespeicherter Traces analysieren und Ausreißer-Traces für eine genauere Analyse finden.

Abfrage entwerfen

Der erste Schritt für eine Bulk-Analyse ist das Erstellen einer PerfettoSQL-Abfrage.

In diesem Abschnitt finden Sie eine Beispielabfrage, mit der die Latenz beim Starten der App gemessen wird. Konkret können Sie die Dauer von activityStart bis zum ersten generierten Frame (dem ersten Auftreten des Choreographer#doFrame-Slice) messen, um die Latenz beim Starten der App zu messen, die von Ihrer App gesteuert wird. Abbildung 1 zeigt den Abschnitt, der abgefragt werden soll.

Eine Zeitachsenansicht eines Trace, in der die Dauer vom „activityStart“-Ereignis bis zum ersten „Choreographer#doFrame“-Ereignis hervorgehoben ist.
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 (Abbildung 2) zu generieren und in der Zeitachse (Abbildung 3) zu visualisieren.

Ein Screenshot der Perfetto-Benutzeroberfläche, auf dem zu sehen ist, wie ein Debug-Track für eine Startabfrage erstellt wird.
Abbildung 2. Erstellen Sie einen Debug-Track für eine Startabfrage.
Eine Zeitachsenansicht in der Perfetto-Benutzeroberfläche, die einen generierten Debug-Track für eine Startabfrage zeigt.
Abbildung 3. Generierter Debug-Track für eine Startabfrage.

Python-Umgebung einrichten

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

pip install perfetto pandas plotly

Skript für die Bulk-Trace-Analyse erstellen

Im folgenden Beispielskript wird die Abfrage in mehreren Traces mit BatchTraceProcessor von Perfetto ausgeführt.

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

# Collect all trace files in the local directory
traces = glob.glob('*.perfetto-trace')

if not traces:
    print("No .perfetto-trace files found in the current directory.")
    exit(1)

if __name__ == '__main__':
    # Process all traces in parallel to aggregate metrics across runs
    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)
        # Plot the distribution of startup times, tracking trace file paths on
        # hover
        violin = px.violin(df, x='dur_ms', hover_data='_path', title='startup time', points='all')
        violin.show()

Grundlegendes zum Script

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, die den Teil der Startzeit berechnet, der der Zeit vom Trace-Slice activityStart bis zum ersten von Ihrer App generierten Frame entspricht.
  3. Die Latenz in Millisekunden wird in einem Violinendiagramm dargestellt, um die Verteilung der Startzeiten zu visualisieren.

Ergebnisse interpretieren

Ein Violinendiagramm, das die Verteilung der abgefragten Startlatenzen zeigt.
Abbildung 4. Violindiagramm 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 die Differenz zwischen den beiden Bevölkerungszahlen. So können Sie einzelne Traces genauer untersuchen. In diesem Beispiel ist das Diagramm so eingerichtet, dass Sie die Trace-Dateinamen sehen, wenn Sie den Mauszeiger auf die Datenpunkte (Latenzen) bewegen. Sie können dann einen der Traces öffnen, die zur Gruppe mit hoher Latenz gehören.

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 dagegen einen Trace aus der Population mit niedrigerer Latenz (der Peak ganz links) auswählen, wird das Fehlen dieses Slices bestätigt (Abbildung 7). Dieser Vergleich zeigt, dass ein bestimmtes Funktions-Flag, das für eine Teilmenge von Nutzern aktiviert ist, die Regression auslöst.

Ein Diagramm, das einen Trace mit hoher Latenz hervorhebt.
Abbildung 5. Datenpunkt mit hoher Latenz in einem Violin-Plot.
Ein Trace, der eine hohe Latenz beim Start aufgrund des MyFlaggedFeature-Slice hervorhebt.
Abbildung 6. Trace-Start mit hoher Latenz und einem zusätzlichen „MyFlaggedFeature“-Slice.
Ein Trace, der den Start mit niedriger Latenz ohne den Slice „MyFlaggedFeature“ hervorhebt.
Abbildung 7. Trace-Start mit niedriger Latenz.

Dieses Beispiel zeigt eine der vielen Möglichkeiten, wie Sie die Bulk-Trace-Analyse verwenden können. Weitere Anwendungsfälle sind das Extrahieren von Statistiken aus dem Feld, um die Auswirkungen zu messen, das Erkennen von Regressionen und mehr.