Analisi collettiva delle tracce

Dopo aver raccolto più tracce utilizzando ProfilingManager, diventa poco pratico esplorarle singolarmente per trovare problemi di prestazioni. L'analisi delle tracce in blocco ti consente di eseguire query su un set di dati di tracce contemporaneamente per:

  • Identificare le regressioni delle prestazioni comuni.
  • Calcolare le distribuzioni statistiche (ad esempio, latenza P50, P90, P99).
  • Trovare pattern in più tracce.
  • Trovare tracce anomale per comprendere ed eseguire il debug dei problemi di prestazioni.

Questa sezione mostra come utilizzare il Perfetto Python Batch Trace Processor per analizzare le metriche di avvio in un insieme di tracce archiviate localmente e individuare le tracce anomale per un'analisi più approfondita.

Progettare la query

Il primo passaggio per eseguire un'analisi in blocco consiste nel creare una query PerfettoSQL.

In questa sezione presentiamo una query di esempio che misura la latenza di avvio dell'app. In particolare, puoi misurare la durata da activityStart al primo frame generato (la prima occorrenza della slice Choreographer#doFrame) per misurare la latenza di avvio dell'app che rientra nel controllo della tua app. La Figura 1 mostra la sezione su cui eseguire la query.

Una visualizzazione cronologica di una traccia, che evidenzia la durata dall'evento activityStart al primo evento Choreographer#doFrame.
Figura 1. Sezione di traccia da `activityStart` al primo frame generato.
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)

Puoi eseguire la query nell'interfaccia utente di Perfetto e poi utilizzare i risultati della query per generare una traccia di debug (Figura 2) e visualizzarla nella sequenza temporale (Figura 3).

Uno screenshot della UI di Perfetto che mostra come creare una traccia di debug per una query di avvio.
Figura 2. Crea una traccia di debug per una query di avvio.
Una visualizzazione cronologica nell'interfaccia utente di Perfetto che mostra una traccia di debug generata per una query di avvio.
Figura 3. Traccia di debug generata per una query di avvio.

Configurare l'ambiente Python

Installa Python sulla tua macchina locale e le librerie richieste:

pip install perfetto pandas plotly

Creare lo script di analisi delle tracce in blocco

Il seguente script di esempio esegue la query in più tracce utilizzando Perfetto's Python BatchTraceProcessor.

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()

Comprendere lo script

Quando esegui lo script Python, vengono eseguite le seguenti azioni:

  1. Lo script cerca nella directory locale tutte le tracce Perfetto con suffisso .perfetto-trace e le utilizza come tracce di origine per l'analisi.
  2. Esegue una query di traccia in blocco che calcola il sottoinsieme del tempo di avvio corrispondente al tempo dalla slice di traccia activityStart al primo frame generato dalla tua app.
  3. Traccia la latenza in millisecondi utilizzando un grafico a violino per visualizzare la distribuzione dei tempi di avvio.

Interpretare i risultati

Un grafico a violino che mostra la distribuzione delle latenze di avvio delle query.
Figura 4. Grafico a violino delle latenze di avvio sottoposte a query.

Dopo aver eseguito lo script, viene generato un grafico. In questo caso, il grafico mostra una distribuzione bimodale con due picchi distinti (Figura 4).

Poi, trova la differenza tra le due popolazioni. In questo modo puoi esaminare le singole tracce in modo più dettagliato. In questo esempio, il grafico è configurato in modo che, quando passi il mouse sopra i punti dati (latenze), puoi identificare i nomi dei file di traccia. Puoi quindi aprire una delle tracce che fa parte del gruppo con latenza elevata.

Quando apri una traccia dal gruppo con latenza elevata (Figura 5), troverai una slice aggiuntiva denominata MyFlaggedFeature in esecuzione durante l'avvio (Figura 6). Al contrario, la selezione di una traccia dalla popolazione con latenza inferiore (il picco più a sinistra) conferma l'assenza della stessa slice (Figura 7). Questo confronto indica che un flag di funzionalità specifico, abilitato per un sottoinsieme di utenti, attiva la regressione.

Un grafico che evidenzia la traccia con latenza elevata.
Figura 5. Punto dati con latenza elevata in un grafico a violino.
Una traccia che evidenzia l'avvio con latenza elevata a causa della sezione MyFlaggedFeature.
Figura 6. Avvio della traccia con latenza elevata con una slice `MyFlaggedFeature` aggiuntiva.
Una traccia che evidenzia l'avvio a bassa latenza senza la sezione MyFlaggedFeature.
Figura 7. Avvio della traccia con latenza bassa.

Questo esempio mostra uno dei tanti modi in cui puoi utilizzare l'analisi delle tracce in blocco. Altri casi d'uso includono l'estrazione di statistiche dal campo per valutare l'impatto, il rilevamento delle regressioni e altro ancora.