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:

$gcc -pg -o main.out main.c

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.

$ ./main.out

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

$ gprof ./main.out

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

$ gprof ./main.out gmon.out > report.txt

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:

#include <stdio.h>


static unsigned int decrement_25mi( unsigned int i); // Decrement 25000000x
static unsigned int decrement_50mi( unsigned int i); // Decrement 50000000x
static unsigned int decrement_100mi( unsigned int i); // Decrement 100000000x


int main(void)
{
       unsigned int j, i=0;
       for( j=0; j<100000000; j++) // Increment 100000000x
               i++;
       i = decrement_100mi(i); // Decrement 100000000x
       printf("Counter = %u\n", i); // Print value
       return 0;
}



static unsigned int decrement_25mi( unsigned int i)
{
       unsigned int j;
       for( j=0; j<25000000; j++)
               i--;
       return i;
}


static unsigned int decrement_50mi( unsigned int i)
{
       i = decrement_25mi(i);
       i = decrement_25mi(i);
       return i;
}


static unsigned int decrement_100mi( unsigned int i)
{
       i = decrement_50mi(i);
       i = decrement_25mi(i);
       i = decrement_25mi(i);
       return i;
}

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

$ git clone https://github.com/igorTavares/gprof_example.git
$ cd gprof_example
$ ./test standard

Resultados na Beaglebone Black

Flat profile:

Figura 1: Resultado do teste – Flat profile

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:

# Compila
$ gcc -pg -o main.out main.c
# Executa
$ ./main.out

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.

# Caso não tenha Python e seu sistema for Debian, Ubuntu ou Mint
$ apt-get install python
# Caso não tenha Graphviz e seu sistema for Debian, Ubuntu ou Mint
$ apt-get install graphviz
# Gera o arquivo de report
$ gprof ./main.out gmon.out > report.txt
# Converte o report em dot graph
$ ./gprof2dot.py report.txt > report.dot
# Converte o dot graph em uma imagem
$ dot -Tpng -o profile.png report.dot

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

$ ./test full

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:

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://embarcados.com.br/beaglebone-black-gravando-uma-nova-imagem/
https://github.com/igorTavares/gprof_example.git
https://code.google.com/p/jrfonseca/wiki/Gprof2Dot
https://www.graphviz.org/doc/info/lang.html
https://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.
Comentários:
Notificações
Notificar
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.

Home » Hardware » Ferramentas de Desenvolvimento » Análise de desempenho com GNU Profiler gprof

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: