Usar ftrace

O ftrace é uma ferramenta de depuração para entender o que está acontecendo no kernel do Linux. As seções a seguir detalham a funcionalidade básica do ftrace, o uso do ftrace com atrace (que captura eventos do kernel) e o ftrace dinâmico.

Para detalhes sobre a funcionalidade avançada do ftrace que não está disponível no systrace, consulte a documentação do ftrace em <kernel tree>/Documentation/trace/ftrace.txt.

Capturar eventos do kernel com atrace

O atrace (frameworks/native/cmds/atrace) usa o ftrace para capturar eventos do kernel. Por sua vez, o systrace.py (ou run_systrace.py em versões mais recentes do Catapult) usa o adb para executar o atrace no dispositivo. O atrace faz o seguinte:

  • Configura o rastreamento no modo do usuário definindo uma propriedade (debug.atrace.tags.enableflags).
  • Ativa a funcionalidade ftrace desejada gravando nos nós sysfs ftrace apropriados. No entanto, como o ftrace oferece suporte a mais recursos, você pode definir alguns nós sysfs e usar o atrace.

Com exceção do rastreamento no momento da inicialização, use o atrace para definir a propriedade com o valor apropriado. A propriedade é uma máscara de bits, e não há uma boa maneira de determinar os valores corretos, a não ser consultando o cabeçalho apropriado, que pode mudar entre as versões do Android.

Ativar eventos de ftrace

Os nós do sysfs do ftrace estão em /sys/kernel/tracing, e os eventos de rastreamento são divididos em categorias em /sys/kernel/tracing/events.

Para ativar eventos por categoria, use:

echo 1 > /sys/kernel/tracing/events/irq/enable

Para ativar eventos individualmente, use:

echo 1 > /sys/kernel/tracing/events/sched/sched_wakeup/enable

Se eventos extras foram ativados pela gravação em nós sysfs, eles não serão redefinidos pelo atrace. Um padrão comum para inicialização de dispositivos Qualcomm é ativar os pontos de rastreamento kgsl (GPU) e mdss (pipeline de exibição) e usar atrace ou systrace:

adb shell "echo 1 > /sys/kernel/tracing/events/mdss/enable"
adb shell "echo 1 > /sys/kernel/tracing/events/kgsl/enable"
./systrace.py sched freq idle am wm gfx view binder_driver irq workq ss sync -t 10 -b 96000 -o full_trace.html

Você também pode usar o ftrace sem atrace ou systrace, o que é útil quando você quer apenas rastros do kernel (ou se você escreveu a propriedade de rastreamento do modo de usuário manualmente). Para executar apenas o ftrace:

  1. Defina o tamanho do buffer para um valor grande o suficiente para o rastreamento:
    echo 96000 > /sys/kernel/tracing/buffer_size_kb
    
  2. Ative o rastreamento:
    echo 1 > /sys/kernel/tracing/tracing_on
    
  3. Execute o teste e desative o rastreamento:
    echo 0 > /sys/kernel/tracing/tracing_on
    
  4. Faça o dump do rastro:
    cat /sys/kernel/tracing/trace > /data/local/tmp/trace_output
    

O trace_output fornece o rastro em formato de texto. Para visualizar usando o Catapult, acesse o repositório Catapult no GitHub e execute o trace2html:

catapult/tracing/bin/trace2html ~/path/to/trace_file

Por padrão, isso grava trace_file.html no mesmo diretório.

Correlacionar eventos

Muitas vezes, é útil analisar a visualização do Catapult e o registro ftrace simultaneamente. Por exemplo, alguns eventos ftrace (principalmente os específicos do fornecedor) não são visualizados pelo Catapult. No entanto, os carimbos de data/hora do Catapult são relativos ao primeiro evento no trace ou a um carimbo de data/hora específico dumpado por um atrace, enquanto os carimbos de data/hora brutos do ftrace são baseados em uma fonte de relógio absoluta específica no kernel do Linux.

Para encontrar um determinado evento ftrace em um evento da Catapult:

  1. Abra o registro bruto do ftrace. Os rastros em versões recentes do systrace são compactados por padrão:
    • Se você capturou o systrace com --no-compress, ele está no arquivo HTML na seção que começa com BEGIN TRACE.
    • Caso contrário, execute o html2trace na árvore Catapult (tracing/bin/html2trace) para descompactar o rastro.
  2. Encontre o carimbo de data/hora relativo na visualização do Catapult.
  3. Encontre uma linha no início do rastro que contenha tracing_mark_sync. O código será semelhante a este:
    <5134>-5134  (-----) [003] ...1    68.104349: tracing_mark_write: trace_event_clock_sync: parent_ts=68.104286
    

    Se essa linha não existir (ou se você usou o ftrace sem o atrace), os tempos serão relativos ao primeiro evento no registro do ftrace.
    1. Adicione o carimbo de data/hora relativo (em milissegundos) ao valor em parent_ts (em segundos).
    2. Procure o novo carimbo de data/hora.

Essas etapas devem levar você ao evento (ou pelo menos muito perto dele).

Usar ftrace dinâmico

Quando o systrace e o ftrace padrão não são suficientes, há um último recurso disponível: o ftrace dinâmico. O ftrace dinâmico envolve a reescrita do código do kernel após a inicialização. Por isso, ele não está disponível em kernels de produção por motivos de segurança. No entanto, cada bug de desempenho difícil em 2015 e 2016 foi causado pela raiz usando o ftrace dinâmico. Ele é especialmente poderoso para depurar suspensões ininterruptíveis, porque é possível receber um trace de pilha no kernel sempre que você atinge a função que aciona a suspensão ininterruptível. Também é possível depurar seções com interrupções e preempções desativadas, o que pode ser muito útil para provar problemas.

Para ativar o ftrace dinâmico, edite o defconfig do kernel:

  1. Remova CONFIG_STRICT_MEMORY_RWX (se estiver presente). Se você estiver usando a versão 3.18 ou mais recente e arm64, ela não estará lá.
  2. Adicione o seguinte: CONFIG_DYNAMIC_FTRACE=y, CONFIG_FUNCTION_TRACER=y, CONFIG_IRQSOFF_TRACER=y, CONFIG_FUNCTION_PROFILER=y e CONFIG_PREEMPT_TRACER=y
  3. Recrie e inicialize o novo kernel.
  4. Execute o comando a seguir para verificar se há rastreadores disponíveis:
    cat /sys/kernel/tracing/available_tracers
    
  5. Confirme se o comando retorna function, irqsoff, preemptoff e preemptirqsoff.
  6. Execute o seguinte para garantir que o ftrace dinâmico esteja funcionando:
    cat /sys/kernel/tracing/available_filter_functions | grep <a function you care about>
    

Depois de concluir essas etapas, você terá o ftrace dinâmico, o criador de perfil de função, o criador de perfil irqsoff e o criador de perfil preemptoff disponíveis. Recomendamos veemente a leitura da documentação do ftrace sobre esses tópicos antes de usá-los, porque eles são poderosos, mas complexos. irqsoff e preemptoff são principalmente úteis para confirmar que os drivers podem estar deixando interrupções ou preempções desativadas por muito tempo.

O perfilador de funções é a melhor opção para problemas de desempenho e é frequentemente usado para descobrir onde uma função está sendo chamada.


Se os dados do analisador de função não forem específicos o suficiente, você poderá combinar os pontos de rastreamento ftrace com o analisador de função. Os eventos ftrace podem ser ativados da mesma forma de sempre e serão intercalados com o rastreamento. Isso é ótimo se houver um tempo de inatividade longo e ininterruptível em uma função específica que você quer depurar: defina o filtro ftrace para a função que você quer, ative os pontos de rastreamento e faça um rastreamento. Você pode analisar o rastro resultante com trace2html, encontrar o evento que você quer e, em seguida, receber rastros de pilha próximos no rastro bruto.

Usar o lockstat

Às vezes, o ftrace não é suficiente, e você realmente precisa depurar o que parece ser uma disputa de bloqueio do kernel. Há mais uma opção de kernel que vale a pena tentar: CONFIG_LOCK_STAT. Esse é um último recurso, já que é extremamente difícil de fazer funcionar em dispositivos Android porque infla o tamanho do kernel além do que a maioria dos dispositivos pode processar.

No entanto, o lockstat usa a infraestrutura de bloqueio de depuração, que é útil para muitos outros apps. Todos que trabalham na ativação do dispositivo precisam encontrar uma maneira de fazer essa opção funcionar em todos os dispositivos, porque vai haver um momento em que você vai pensar "Se eu pudesse ativar LOCK_STAT, poderia confirmar ou refutar isso como o problema em cinco minutos em vez de cinco dias".


Se você puder inicializar um kernel com a opção de configuração, o rastreamento de bloqueio será semelhante ao ftrace:

  1. Ative o rastreamento:
    echo 1 > /proc/sys/kernel/lock_stat
    
  2. Execute o teste.
  3. Desative o rastreamento:
    echo 0 > /proc/sys/kernel/lock_stat
    
  4. Faça o dump do seu rastro:
    cat /proc/lock_stat > /data/local/tmp/lock_stat
    

Para receber ajuda para interpretar a saída resultante, consulte a documentação do lockstat em <kernel>/Documentation/locking/lockstat.txt.

Usar pontos de rastreamento do fornecedor

Use os pontos de rastreamento upstream primeiro, mas às vezes você precisará usar os pontos de rastreamento do fornecedor:

  { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
        { OPT,      "events/mdss/enable" },
        { OPT,      "events/sde/enable" },
        { OPT,      "events/mali_systrace/enable" },
    } },

Os pontos de rastreamento são extensível pelo serviço HAL, permitindo que você adicione pontos/categorias de rastreamento específicos do dispositivo. Os pontos de trace estão integrados ao perfetto, ao atrace/systrace e ao app de rastreamento do sistema no dispositivo.

As APIs para implementar pontos de rastreamento/categorias são:

  • listCategories() gera (vec<TracingCategory> categories);
  • enableCategories(vec<string> categories) gera (Status status);
  • disableAllCategories() gera (Status status);
Para mais informações, consulte a definição e a implementação padrão do HAL no AOSP: