1 / 27

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

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

patia
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. 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çã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 • 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! MEM CPU MEM Instrumentação Deadlock Deadlock CPU J P Sauvé - DSC/UFPb

  5. Vocabulá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 Primos • O programa imprime o número de primos menores que um certo número máximo • Execute o programa: • java Primo1 100001229481 milissegundos J P Sauvé - DSC/UFPb

  7. Primeira Versão public 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 Execução • Max 10000: 0,481 segundos • Max 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 Melhorar? • Vamos conseguir melhorias de pelo menos 200 vezes nesse programa • Como fazer? • Não chute ... Instrumente! J P Sauvé - DSC/UFPb

  10. Primeira versão: Profiling • Comando: • 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 Profiling • Examine o arquivo java.hprof.txt rank 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ã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 - 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 menos 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: 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 muito • Temos que melhorar primo ainda J P Sauvé - DSC/UFPb

  16. Quarta 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: 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 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 profile • Tempo 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 Leaks • 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.java • Veja aqui • 10000 objetos MemoryConsumer de 1KBytes cada são alocados • Execute o programa: • java -Xrunhprof:heap=sites,depth=10 MemoryLeak J P Sauvé - DSC/UFPb

  22. O 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 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 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 Deadlocks Java 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. Resumo • 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ções • Livros • Programming Pearls, Bentley • More Programming Pearls, Bentley • Artigo na Web • Diagnose Common Runtime Problems with Hprof, Pierce, JavaWorld, dezembro 2001 J P Sauvé - DSC/UFPb

More Related