técnicas de programação: profiling de programas

Post on 13-Jan-2016

27 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

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

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ü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

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

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

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

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

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

Veja 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ções

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

Artigo na Web– Diagnose Common Runtime Problems with

Hprof, Pierce, JavaWorld, dezembro 2001

top related