Analisar traces em massa

Depois de coletar vários traces usando ProfilingManager, analisá-los individualmente para encontrar problemas de desempenho se torna impraticável. A análise de traces em massa permite consultar um conjunto de dados de traces simultaneamente para:

  • Identificar regressões de desempenho comuns.
  • Calcular distribuições estatísticas (por exemplo, latência P50, P90, P99).
  • Encontrar padrões em vários traces.
  • Encontre traces atípicos para entender e depurar problemas de desempenho.

Nesta seção, mostramos como usar o processador de rastreamento em lote do Perfetto para Python para analisar métricas de inicialização em um conjunto de rastreamentos armazenados localmente e localizar rastreamentos atípicos para uma análise mais detalhada.

Criar a consulta

Primeiro, crie uma consulta PerfettoSQL que extraia a métrica que você quer comparar. O exemplo a seguir mede a latência de inicialização controlada pelo app, de activityStart até o primeiro frame renderizado (Choreographer#doFrame), conforme mostrado na Figura 1.

Uma visualização da linha do tempo de um trace, destacando a duração do evento activityStart até o primeiro evento Choreographer#doFrame.
Figura 1. Seção de trace de activityStart até o primeiro frame gerado.
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)

É possível executar a consulta na interface do Perfetto e usar os resultados para gerar uma faixa de depuração (Figura 2) e visualizá-la na linha do tempo (Figura 3).

Painel de resultados de consulta da interface do Perfetto mostrando como criar uma faixa de depuração para uma consulta de inicialização.
Figura 2. Criar uma faixa de depuração para uma consulta de inicialização.
Uma visualização da linha do tempo na interface do Perfetto mostrando uma faixa de depuração gerada para uma consulta de inicialização.
Figura 3. Faixa de depuração gerada para uma consulta de inicialização.

Configure o ambiente Python

Instale o Python na máquina local e as bibliotecas necessárias:

pip install perfetto pandas plotly

Criar o script de análise de trace em massa

O script de exemplo a seguir executa a consulta em vários traces usando o BatchTraceProcessor do Python do Perfetto.

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

Noções básicas sobre o script

Quando você executa o script Python, ele realiza as seguintes ações:

  1. O script pesquisa no diretório local todos os traces do Perfetto com o sufixo .perfetto-trace e os usa como traces de origem para análise.
  2. Ele executa uma consulta de rastreamento em massa que calcula o subconjunto do tempo de inicialização correspondente ao tempo entre a fração de rastreamento activityStart e o primeiro frame gerado pelo app.
  3. Ele mostra a latência em milissegundos usando um gráfico de violino para visualizar a distribuição dos tempos de inicialização.

Interprete os resultados

Um gráfico de violino que mostra a distribuição das latências de inicialização consultadas.
Figura 4. Gráfico de violino das latências de inicialização consultadas.

A execução do script gera um gráfico de violino que mostra uma distribuição bimodal com dois picos de latência distintos (Figura 4). Passe o cursor sobre pontos de dados individuais no gráfico para inspecionar o nome do arquivo _path e comparar os traces de cada pico (Figura 5):

  • Rastros de alta latência (pico à direita): abrir um rastro desse grupo na interface do Perfetto revela uma fração extra de MyFlaggedFeature em execução durante a inicialização (Figura 6).
  • Traces de baixa latência (pico esquerdo): abrir um trace do grupo mais rápido confirma que MyFlaggedFeature está ausente (Figura 7), indicando que uma flag de recurso ativada para um subconjunto de usuários causou a regressão de inicialização.
Um gráfico que destaca um trace de alta latência.
Figura 5. Ponto de dados de alta latência em um gráfico de violino.
Um trace que destaca a inicialização de alta latência devido à fração MyFlaggedFeature.
Figura 6. Inicialização de trace de alta latência com uma fração MyFlaggedFeature extra.
Um trace que destaca a inicialização de baixa latência sem a fração MyFlaggedFeature.
Figura 7. Início do trace de baixa latência.

Este exemplo demonstra uma das muitas maneiras de usar a análise de trace em massa. Outros casos de uso incluem extrair estatísticas do campo para avaliar o impacto, detectar regressões e muito mais.