J P Sauvé - DSC/UFPb 1 Técnicas de Programação: Profiling de Programas Jacques Philippe Sauvé.
-
Upload
larissa-miranda-espirito-santo -
Category
Documents
-
view
229 -
download
1
Transcript of J P Sauvé - DSC/UFPb 1 Técnicas de Programação: Profiling de Programas Jacques Philippe Sauvé.
J P Sauvé - DSC/UFPb
1
Técnicas de Programação: Técnicas de Programação: Profiling de ProgramasProfiling de Programas
Jacques Philippe Sauvé
J P Sauvé - DSC/UFPb 2
Introdução Introdução Problemas freqüentes de programas:
– Lentidão devido a consumo de CPU– Alocação excessiva de memória (memory
leak)– Deadlocks entre threads
Este seminário mostra como resolver esses problemas usando ferramentas chamadas perfiladores
J P Sauvé - DSC/UFPb 3
ProgramaçãoProgramação Visão geral de profiling
– (5 minutos) Profiling para descobrir gargalos de CPU
– (45 minutos) Profiling para descobrir memory leaks
– (20 minutos) Profiling para descobrir deadlocks
– (30 (minutos)
J P Sauvé - DSC/UFPb 4
Visão geral Visão geral Os três problemas relacionados são
freqüentesNão se deve resolvê-los no chute!A chave é
instrumentar o programa para que ele mesmo nos diga o que está errado!
CPUDeadlock
Instrumentação
Deadlock
MEMMEMCPU
J P Sauvé - DSC/UFPb 5
VocabulárioVocabulárioPerfilador: programa que fornece
informação sobre os detalhes da execução de um outro programa
hprof: Perfilador da JVM padrão– java –Xrunhprof:[opções] classe
J P Sauvé - DSC/UFPb 6
Profiling de CPU – Número Profiling de CPU – Número PrimosPrimosO programa imprime o número de primos
menores que um certo número máximoExecute o programa:
– java Primo1 100001229481 milissegundos
J P Sauvé - DSC/UFPb 7
Primeira VersãoPrimeira Versãopublic class Primo1 { public static boolean primo(int n) { for(int i = 2; i < n; i++) { if(n % i == 0) { return false; } } return true; }
public static void main(String[] args) { int max = Integer.parseInt(args[0]); int númeroPrimos = 0; long horaInicial = System.currentTimeMillis(); for(int i = 2; i <= max; i++) { if(primo(i)) { númeroPrimos++; } } System.out.println(númeroPrimos); System.out.println((System.currentTimeMillis() –
horaInicial)+" milissegundos"); }}
J P Sauvé - DSC/UFPb 8
Primeira Versão: Tempo de Primeira Versão: Tempo de ExecuçãoExecuçãoMax 10000: 0,481 segundosMax 100000: 36,392 seg.Max 1000000: ?
– (não tive paciência de esperar)O programa é obviamente CPU-bound
J P Sauvé - DSC/UFPb 9
Primeira Versão: Como Primeira Versão: Como Melhorar?Melhorar?Vamos conseguir melhorias de pelo menos
200 vezes nesse programaComo fazer?Não chute ... Instrumente!
J P Sauvé - DSC/UFPb 10
Primeira versão: ProfilingPrimeira versão: ProfilingComando:
– java -Xrunhprof:cpu=times,depth=10 Primo5 100000
Cpu=times pede a contagem de chamadas de métodos
Depth=10 pede no máximo profundidade 10 no stack backtrace
J P Sauvé - DSC/UFPb 11
Resultado do ProfilingResultado do ProfilingExamine o arquivo java.hprof.txtrank self accum count trace method 1 98.44% 98.44% 99999 8 Primo1.primo 2 1.28% 99.72% 1 6 Primo1.main 3 0.03% 99.75% 1 13 java.security.Policy$1.run...
Nosso problema é obviamente tempo demais sendo gasto no método primo()
Primeira lição: Para diminuir o gargalo de primo, pode-se:– Chamar o método menos– Tornar o método mais rápido
Aqui, decidimos não “fuçar” main(): concentre-se em primo()
J P Sauvé - DSC/UFPb 12
Segunda versãoSegunda versão Como rodar primo() mais rapidamente? Que tal rodar menos no laço?
– Basta testar fatores até sqrt(n)public class Primo2 { public static int raiz(int n) { return (int)Math.sqrt((double)n); }
public static boolean primo(int n) { for(int i = 2; i <= raiz(n); i++) { if(n % i == 0) { return false; } } return true; } ...}
J P Sauvé - DSC/UFPb 13
Segunda versão - profilingSegunda versão - profiling É mais rápida que a primeira:
– P1: 10K/100K/1M: 0,481/36,392/?– P2: 10K/100K/1M: 0,060/1,132/27,189
Onde está o gargalo?rank self accum count trace method 1 57.10% 57.10% 2755286 15 Primo2.raiz 2 40.99% 98.09% 99999 17 Primo2.primo 3 1.36% 99.45% 1 12 Primo2.mainVeja quantas vezes raiz() foi chamada!
J P Sauvé - DSC/UFPb 14
Terceira versão: chame sqrt Terceira versão: chame sqrt menosmenos public static boolean primo(int n) { int limite = raiz(n); for(int i = 2; i <= limite; i++) { if(n % i == 0) { return false; } } return true; }Os tempos passam para:
– P3: 10K/100K/1M: 0,020/0,311/6,720– Já está 100 vezes mais rápido!
J P Sauvé - DSC/UFPb 15
Terceira versão: perfilTerceira versão: perfilrank self accum count trace method 1 50.02% 50.02% 99999 20 Primo3.primo 2 25.37% 75.38% 99999 14 Primo3.raiz 3 17.48% 92.86% 1 10 Primo3.mainraiz() caiu muitoTemos que melhorar primo ainda
J P Sauvé - DSC/UFPb 16
Quarta versão: tentativaQuarta versão: tentativa Com casos especiais, poderemos reduzir o tempo? public static boolean primo(int n) { if(n % 2 == 0) return false; if(n % 3 == 0) return false; if(n % 5 == 0) return false; int limite = raiz(n); for(int i = 7; i <= limite; i += 2) { if(n % i == 0) return false; } return true; }
J P Sauvé - DSC/UFPb 17
Quarta versão: bugQuarta versão: bug A saída de Primo1 10000 é
1129 A saída de Primo4 10000 é
1126 O tempo melhorou:
– P3: 10K/100K/1M: 0,020/0,311/6,720– P4: 10K/100K/1M: 0,020/0,151/2,924
Tem um bug!– Mesmo com o programa mais rápido, uma regra básica é mantê-
lo funcionando enquanto se o deixa mais rápido!– Cadê o bug?
J P Sauvé - DSC/UFPb 18
Quinta versão: outra tentativaQuinta versão: outra tentativa Consertamos o bug e retiramos sqrt() public static boolean primo(int n) { if(n % 2 == 0) return n == 2; if(n % 3 == 0) return n == 3; if(n % 5 == 0) return n == 5; for(int i = 7; i * i <= n; i += 2) { if(n % i == 0) return false; } return true; }
J P Sauvé - DSC/UFPb 19
Quinto programa: tempo e Quinto programa: tempo e profileprofileTempo não melhorou:
– P4: 10K/100K/1M: 0,020/0,151/2,924– P5: 10K/100K/1M: 0,020/0,151/3,285
Não entendi bem por quê!Último perfil:rank self accum count trace method 1 53.77% 53.77% 99999 17 Primo5.primo 2 34.67% 88.44% 1 9 Primo5.main
J P Sauvé - DSC/UFPb 20
Profiling para Achar Memory Profiling para Achar Memory LeaksLeaks
Memory Leaks são bugs de programas que esquecem de liberar memória alocada– O programa fica cada vez maior– Problema muito sério para programas servidores que
ficam sempre no ar Menos freqüente para Java do que C/C++ devido
ao garbage collection– Em Java, há memory leak se você continuar a
referenciar um objeto
J P Sauvé - DSC/UFPb 21
O Programa MemoryLeak.javaO Programa MemoryLeak.javaVeja aqui10000 objetos MemoryConsumer de
1KBytes cada são alocadosExecute o programa:
– java -Xrunhprof:heap=sites,depth=10 MemoryLeak
J P Sauvé - DSC/UFPb 22
O perfil de MemoryLeak.javaO perfil de MemoryLeak.java percent live alloc'ed stack class rank self accum bytes objs bytes objs trace name 1 88.67% 88.67% 2600000 10000 2600000 10000 185 [B 2 5.10% 93.77% 149524 157 149524 157 1 [I 3 1.36% 95.14% 40000 10000 40000 10000 175 MemoryConsumer 4 0.72% 95.86% 21140 1057 200000 10000 169 [C 5 0.66% 96.52% 19466 741 19626 754 1 [C
[B significa “Array de bytes”, etc. O que causou a alocação toda?
– Veja o trace 185: vem de main que chama o construtor de MemoryConsumer
TRACE 185:MemoryConsumer.<init>(MemoryLeak.java:36)MemoryLeak.main(MemoryLeak.java:16)
J P Sauvé - DSC/UFPb 23
Um programa de deadlockUm programa de deadlock Veja o programa de deadlock aqui Em ClassicDeadlock:
– Dois objetos equivalentes são criados (left e right)– Dois threads pegam locks nesses objetos numa ordem
particular Execute o programa
– java -Xdebug ClassicDeadlock
– Eventualmente, um deadlock vai ocorrer em que cada thread espera por um lock que o outro thread detém
– Mate o programa com CTRL-\ (UNIX) ou CTRL-BREAK (Windows)
J P Sauvé - DSC/UFPb 24
Diagnóstico de DeadlocksDiagnóstico de Deadlocks
Found one Java-level deadlock:============================="RightToLeft": waiting to lock monitor 0x8092e34 (object 0x44493a10, a
SynchronizedObject), which is held by "LeftToRight""LeftToRight": waiting to lock monitor 0x8092dfc (object 0x44493a20, a
SynchronizedObject), which is held by "RightToLeft"
O deadlock pode ser identificado, acima
J P Sauvé - DSC/UFPb 25
Diagnóstico de DeadlocksDiagnóstico de DeadlocksJava stack information for the threads listed above:==================================================="RightToLeft":
at SynchronizedObject.synchronizedMethod(ClassicDeadlock.java:30)- waiting to lock <0x44493a10> (a SynchronizedObject)at RightToLeftGrabber.grabRightToLeft(ClassicDeadlock.java:68)- locked <0x44493a20> (a SynchronizedObject)at RightToLeftGrabber.run(ClassicDeadlock.java:62)
"LeftToRight":at SynchronizedObject.synchronizedMethod(ClassicDeadlock.java:30)- waiting to lock <0x44493a20> (a SynchronizedObject)at LeftToRightGrabber.grabLeftToRight(ClassicDeadlock.java:88)- locked <0x44493a10> (a SynchronizedObject)at LeftToRightGrabber.run(ClassicDeadlock.java:82)
Found 1 deadlock.
J P Sauvé - DSC/UFPb 26
ResumoResumo Aprendemos que:
– Três problemas freqüentes de execução de programas são: Excesso de consumo de CPU Memory leak Deadlocks
– É importante usar ferramentas adequadas para diagnosticar esses problemas
– Uma boa ferramenta é um “perfilador”– Ele adquire estatísticas do programa durante sua execução e
apresenta os resultados de forma legível (mais ou menos!)
J P Sauvé - DSC/UFPb 27
Onde obter mais informaçõesOnde obter mais informaçõesLivros
– Programming Pearls, Bentley– More Programming Pearls, Bentley
Artigo na Web– Diagnose Common Runtime Problems with
Hprof, Pierce, JavaWorld, dezembro 2001