Análise de rastreamento em massa

Depois de coletar vários rastreamentos usando ProfilingManager, fica impraticável analisar cada um deles para encontrar problemas de desempenho. Com a análise de rastreamento em massa, é possível consultar um conjunto de dados de rastreamentos simultaneamente para:

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

Esta seção demonstra como usar o Processador de rastreamento em lote do Perfetto Python para analisar métricas de inicialização em um conjunto de rastreamentos armazenados localmente e localizar rastreamentos outliers para uma análise mais detalhada.

Projetar a consulta

A primeira etapa para realizar uma análise em massa é criar uma consulta do PerfettoSQL.

Nesta seção, apresentamos um exemplo de consulta que mede a latência de inicialização do app. Especificamente, é possível medir a duração de activityStart até o primeiro frame gerado (a primeira ocorrência da fração Choreographer#doFrame) para medir a latência de inicialização do app que está sob o controle dele. A Figura 1 mostra a seção para consultar.

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

Execute a consulta na interface do Perfetto e use os resultados para gerar uma faixa de depuração (Figura 2) e visualizar na linha do tempo (Figura 3).

Uma captura de tela da interface do Perfetto mostrando como criar uma faixa de depuração para uma consulta de inicialização.
Figura 2. Crie uma faixa de depuração para uma consulta de inicialização.
Uma visualização de 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.

Configurar o ambiente Python

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

pip install perfetto pandas plotly

Criar o script de análise de rastreamento em massa

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

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

Entender o script

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

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

Interpretar os resultados

Um gráfico de violino mostrando a distribuição das latências de inicialização consultadas.
Figura 4. Diagrama de caixa das latências de inicialização consultadas.

Depois de executar o script, ele vai gerar um gráfico. Nesse caso, o gráfico mostra uma distribuição bimodal com dois picos distintos (Figura 4).

Em seguida, encontre a diferença entre as duas populações. Isso ajuda você a examinar traces individuais com mais detalhes. Neste exemplo, o gráfico é configurado para que, ao passar o cursor sobre os pontos de dados (latências), seja possível identificar os nomes de arquivos de rastreamento. Em seguida, abra um dos rastreamentos que fazem parte do grupo de alta latência.

Ao abrir um rastreamento do grupo de alta latência (Figura 5), você vai encontrar um intervalo extra chamado MyFlaggedFeature em execução durante a inicialização (Figura 6). Por outro lado, selecionar um rastreamento da população de menor latência (o pico mais à esquerda) confirma a ausência dessa mesma fração (Figura 7). Essa comparação indica que uma flag de recurso específica, ativada para um subconjunto de usuários, aciona a regressão.

Um gráfico destacou um rastreamento de alta latência.
Figura 5. Ponto de dados de alta latência em um diagrama de caixa de violino.
Um trace destacando a inicialização de alta latência devido à fração MyFlaggedFeature.
Figura 6. Inicialização de rastreamento de alta latência com uma fração adicional "MyFlaggedFeature".
Um rastreamento que destaca a inicialização de baixa latência sem a fração MyFlaggedFeature.
Figura 7. Inicialização de rastreamento de baixa latência.

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