Técnicas de Programação: Profiling de Programas

27
J P Sauvé - DSC/UFPb 1 Técnicas de Técnicas de Programação: Profiling Programação: Profiling de Programas de Programas Jacques Philippe Sauvé

description

Técnicas de Programação: Profiling de Programas. Jacques Philippe Sauvé. 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 - PowerPoint PPT Presentation

Transcript of Técnicas de Programação: Profiling de Programas

Page 1: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb

1

Técnicas de Programação: Técnicas de Programação: Profiling de ProgramasProfiling de Programas

Jacques Philippe Sauvé

Page 2: Técnicas de Programação: Profiling de Programas

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

Page 3: Técnicas de Programação: Profiling de Programas

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)

Page 4: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb 4

Visão geral Visão geral

Os três problemas relacionados são freqüentes

Nã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

Page 5: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb 5

VocabulárioVocabulário

Perfilador: 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

Page 6: Técnicas de Programação: Profiling de Programas

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

Page 7: Técnicas de Programação: Profiling de Programas

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"); }}

Page 8: Técnicas de Programação: Profiling de Programas

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

Page 9: Técnicas de Programação: Profiling de Programas

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!

Page 10: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb 10

Primeira versão: ProfilingPrimeira versão: Profiling

Comando:– java -Xrunhprof:cpu=times,depth=10 Primo5

100000Cpu=times pede a contagem de chamadas

de métodosDepth=10 pede no máximo profundidade

10 no stack backtrace

Page 11: Técnicas de Programação: Profiling de Programas

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

Page 12: Técnicas de Programação: Profiling de Programas

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; } ...}

Page 13: Técnicas de Programação: Profiling de Programas

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.main

Veja quantas vezes raiz() foi chamada!

Page 14: Técnicas de Programação: Profiling de Programas

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!

Page 15: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb 15

Terceira versão: perfilTerceira versão: perfil

rank 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.main

raiz() caiu muitoTemos que melhorar primo ainda

Page 16: Técnicas de Programação: Profiling de Programas

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; }

Page 17: Técnicas de Programação: Profiling de Programas

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?

Page 18: Técnicas de Programação: Profiling de Programas

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; }

Page 19: Técnicas de Programação: Profiling de Programas

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

Page 20: Técnicas de Programação: Profiling de Programas

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

Page 21: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb 21

O Programa MemoryLeak.javaO Programa MemoryLeak.java

Veja aqui10000 objetos MemoryConsumer de

1KBytes cada são alocadosExecute o programa:

– java -Xrunhprof:heap=sites,depth=10 MemoryLeak

Page 22: Técnicas de Programação: Profiling de Programas

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)

Page 23: Técnicas de Programação: Profiling de Programas

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)

Page 24: Técnicas de Programação: Profiling de Programas

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

Page 25: Técnicas de Programação: Profiling de Programas

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.

Page 26: Técnicas de Programação: Profiling de Programas

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

Page 27: Técnicas de Programação: Profiling de Programas

J P Sauvé - DSC/UFPb 27

Onde obter mais informaçõesOnde obter mais informações

Livros– Programming Pearls, Bentley– More Programming Pearls, Bentley

Artigo na Web– Diagnose Common Runtime Problems with

Hprof, Pierce, JavaWorld, dezembro 2001