Análise de desempenho com GNU Profiler gprof

gprof

Existem inúmeras maneiras de se analisar o desempenho de um programa em um sistema operacional GNU/Linux. Neste texto vou falar um pouco sobre uma ferramenta bastante conveniente para sistemas embarcados, que você provavelmente já possui instalada no seu ambiente, e pode começar a utilizar a partir de agora sem ter que alterar nenhuma linha de código do seu programa.

O GNU profiler (gprof), faz parte do conjunto de ferramentas GNU Binary Utilities (binutils), e tem como principal funcionalidade apontar quanto tempo está sendo gasto em cada parte do seu programa, assim como uma série de estatísticas respectivas a chamadas de função no código.

O compilador utilizado precisa ser compatível com o gprof, e para isso nada melhor do que utilizar o GNU Compiler Collection, o famoso GCC, em nossos testes. Os passos para utilização da ferramenta são muito simples, e serão citados abaixo:

1) Compile e link seu programa utilizando a opção (flag) “pg”. No nosso exemplo o script vai ficar assim:

2) Execute o binário do seu programa. Isso fará com que ele insira no arquivo gmon.out as informações que serão utilizadas no nosso próximo passo.

3) Utilize o gprof para analisar o arquivo gerado no passo anterior e nos reportar as informações desejadas:

Caso você prefira direcionar a saída para uma arquivo de texto, também pode ser feito:

OBS: Como nosso objetivo é utilizar o profiler para analisarmos aplicações embarcadas, pode ser de interesse de muitos saber que essa etapa pode ser executada em seu computador de desenvolvimento. Basta que para isso os arquivos main.out e gmon.out sejam copiados para o ambiente desejado.

O relatório gerado pelo terceiro passo tem vários formatos de saída, que podem ser configurados a partir de outras flags. Mas vou dar uma breve explicação de como interpretar a saída padrão do gprof, que é dividida em duas partes:

  1. Flat profile: Mostra quanto tempo foi gasto em cada função, quais funções foram chamadas e quantas vezes;
  2. Call graph: Mostra, para cada função, quais funções a chamaram, e quais funções ela chamou, e a percentagem de tempo gasta em cada uma dessas chamadas.

Agora vamos para a prática, e como eu disse anteriormente essa é uma boa ferramenta para se usar em um ambiente embarcado por usar poucos recursos computacionais e por já vir instalado na maioria dos sistemas. Então, nada melhor do que testarmos essa ferramenta em uma das mais famosas placas de desenvolvimento para Linux embarcado atualmente: Beaglebone Black.

A placa que vou utilizar é da revisão C e está com o Debian 7.5, a mesma versão que já veio gravada nela. Caso você queira saber como trocar a imagem que roda na sua Beaglebone Black leia meu artigo que trata o assunto.

Para nosso exemplo preparei um repositório no GitHub, contendo um programa em C muito simples, que faz uso de funções diferentes para que possamos analisá-las com o gprof. Também escrevi um pequeno script que vai conter os comandos citados nos três passos que descrevi acima, entre outros que explicarei mais adiante.

A aplicação que iremos compilar e rodar é um programa que simplesmente incrementa uma variável 100 milhões de vezes, e depois chama uma função que, por meio da chamada de outras funções, acaba por decrementar a variável 100 milhões de vezes, fazendo com que seu valor retorne a zero, como no começo.

Segue o código:

Então, para testarmos o exemplo, basta clonar o repositório e rodar o script na sua Beaglebone Black:

Resultados na Beaglebone Black

Flat profile:

flat_profile

Figura 1: Resultado do teste – Flat profile

Call graph:

call_graph

Figura 2: Resultado do teste – Call graph

Representação visual do call graph

Para conseguirmos visualizar de forma gráfica o resultado do profiler podemos utilizar um script em Python chamado gprof2dot.py na nossa Beaglebone Black. Esse script transforma a nossa saída do profiler em um dot graph.

E para finalizar utilizamos o comando dot do pacote Graphviz para convertermos o dot graph em uma imagem. Logo a sequência de comandos ficará assim:

PRIMEIRA PARTE: PRECISA rodar na BeagleBone Black:

SEGUNDA PARTE: NÃO PRECISA rodar na BeagleBone Black, pode ser em seu computador de desenvolvimento, apenas copie os arquivos gmon.out e main.out gerados nos passos anteriores para sua máquina.

Ou caso você tenha clonado o repositório na BeagleBone Black, basta executar:

Para visualizar a imagem profile.png sem precisar ligar um monitor na BeagleBone Black, basta transferi-la para o seu computador de desenvolvimento e abri-la. Ou melhor ainda, rode a segunda parte dos comandos em seu computador de desenvolvimento e abra a imagem.

A imagem obtida do nosso exemplo foi:

call_image

Figura 3: Imagem profile.png, representação visual do call grapgh

A primeira impressão que esse fluxograma passa é de que tem muita informação “jogada” e que vai ser difícil digerir tudo isso. Mas é tranquilo de entender, e vou explicar o que significa tudo isso.

  • Cada retângulo representa uma função do seu programa, e tem o seu respectivo nome escrito na primeira linha de cada elemento;
  • Na segunda linha temos a porcentagem do tempo que a função levou para ser executada por completa em relação ao tempo que o programa demorou pra ser executado por inteiro. A cor dos retângulos é definida justamente por esse valor, onde as funções que gastam o maior tempo possuem cores mais próximas do vermelho, e quanto menos tempo mais perto do azul escuro;
  • Na terceira linha, entre parenteses, temos a percentagem do tempo gasto pela função propriamente dita (sem contar o tempo gasto nas chamadas de funções) em relação ao tempo que o programa demorou pra ser executado por inteiro;
  • Na última linha temos o número de vezes que a determinada função foi chamada por qualquer outra função;
  • Nas setas temos a quantidade de vezes que uma função chamou a outra, além da porcentagem do tempo total de execução do  programa que foi gasto nessas chamadas.

Referências

https://sourceware.org/binutils/docs-2.20/gprof/index.html#Top
https://sourceware.org/binutils/docs-2.20/gprof/Invoking.html#Invoking
https://www.embarcados.com.br/beaglebone-black-gravando-uma-nova-imagem/
https://github.com/igorTavares/gprof_example.git
https://code.google.com/p/jrfonseca/wiki/Gprof2Dot
http://www.graphviz.org/doc/info/lang.html
http://www.graphviz.org/Download.php
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Comentários:
Notificações
Notificar
guest
3 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
Vinicius
Vinicius
26/10/2019 16:11

Muito bom cara, parabéns!

Plinio
Plinio
28/06/2018 09:37

Oi, muito bom o artigo! Parabéns.

Por favor atualiza o link do gprof2dot.py. Ainda está apontando pro finado googlecode.

Willian Henrique
Willian Henrique
17/12/2014 16:54

Realmente muito bom artigo.
Já utilizei o profiler da TI no eclipse, essa ferramenta é muito útil.

Talvez você goste:

Séries

Menu