Rodrigopex

Pois bem, depois de um longo período sem escrever; motivo -> graduação. Hoje reativo o meu blog..

Desenvolvo sistemas em Python a três anos. Já participei de alguns projetos interessantes, como o HCT-Librix da Itautec, Lampejo (sem referência ainda), meu TG (TCC – trabalho de conclusão de curso) que foi um compilador que gera testbench para Verilog (VUTG), entre outros. Percebi que em alguns momentos o desempenho dos aplicativos não era satisfatório. A muito tempo já procuro desenvolver meus módulos seguindo uma linha mais veloz e sempre procuro otimizações (mania de engenheiro…). Um bom guia é Performance Tips. Um dia desses (na PyConBrasil2008) eu ouvi um cara falar: “Python só é lento pra quem não sabe desenvolver…”. Não lembro o nome do autor dessa frase, mas fui mais profundamente em busca desse “saber desenvolver” para melhorar a performance dos meus aplicativos.

De cara vi logo algumas coisas interessantes. Um post muito legal sobre PerformancePython onde são relatadas algumas técnicas e ferramentas de melhoria de performance. Obs.: É interessante a leitura do post PerformancePython para obter um melhor entendimento do resto deste. Pra mim, a mais fácil de usar com melhorias padrão, sem mexer em quase nada do código é Psyco. Segundo suas intenções dá uma turbinada praticamente sem custos de codificação. É um ótimo caso a se estudar. Basta embutir as seguintes linhas dentro do código a ser “tunnado”:

[...]
import psyco
psyco.full() #Tunning on!
[...] Resto do código

Psyco é um mundo, tem muitas variações de uso dá pra tirar leite de pedra, mas já dá um trabalhinho. Outra coisa que vi foi o weave da biblioteca SciPy que possibilita o uso de C nas entrelinhas de Python (fantástico!!!). Outra, Cython (em cima do pyrex) que faz um mix entre C/C++ e Python atingindo um ótimo desempenho. Cython pra mim é a sacada! Faćil de usar, com um custo benefício fantástico. Mas vamos à real idéia desse post.

Já temos uma boa gama de ferramentas e técnicas que nos possibilitam melhorar a performance do código, mas onde iremos aplicar esse arsenal? Lembre-se que “tunnar” de verdade um app não é fácil. Com psyco é de graça, porém o ganho normal não é tão significativo, por exemplo um código que roda em 5 segundos com Python puro leva 4 ou 4,5 com Psyco. Realmente é interessante termos um ganho de 25% na performance com duas linhas de código. Mas em alguns momentos isso não é o suficiente. Eu já tive melhorias de 40x no desempenho de códigos meus usando Cython.

Se formos fazer melhorias em todo o código do sistema teremos um trabalho cansativo e custoso. Dependendo da técnica teremos um custo maior com um ganho maior. Mas essa escala tem uma hora que pára, então as vezes não vale a pena otimizar alguns trechos de código. O que faremos para saber onde fazer melhorias?

Aí entra a grande jogada. Existem ferramentas de análise de performance também conhecidas como logging profilers que permitem a análise de custo computacional por linha de código. What he..?!?! Pois é… traduzindo, com essas ferramentas podemos verificar qual trecho de código consome mais tempo durante a execução de um software. Em Python (até onde eu sei…) temos três dessas: Profile, cProfile e hotshot. A mais indicada, por onde eu li, para uso comum é a cProfile. Abaixo temos um exemplo de análise de performance do compilador vutg usando a biblioteca cProfile.


import sys
import cProfile
from pstats import Stats
#importando o módulo em teste - - - - - -
sys.path.append("../..")
import vutg
#- - - - - - - - - - - - - - - - - - - - - - - - - - -
CPROF_FILE = 'vutg.cprof' #arquivo onde serão guardados os resultados do profiling
sys.argv = ["stub","gen=makefile,skeleton","vut_file=fulladder.vut"]
cProfile.run('vutg.main()', filename=CPROF_FILE)
stats = Stats(CPROF_FILE) #recuperando informações do arquivo de profiling
stats.sort_stats('time').print_stats() #imprimindo em ordenado pelo tempo

Os resultados do profiling estão dispostos em linhas e colunas onde as linhas são as ocorrências de funções e as colunas são as métricas temporais para cada uma. Então explicando rapidamente cada uma delas temos:
* ncalls: número de vezes que a função foi executada;
* tottime: tempo total gasto com a função
* percall: tempo por chamada da função
* cumtime: tempo acumulativo das chamadas, nesse caso conta-se também o tempo gasto com funções filhas. Abaixo está o resultado da execução do cProfiler.


Sun Nov 2 16:24:14 2008 vutg.cprof
16146319 function calls (16142745 primitive calls) in 95.629 CPU seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 14.549 14.549 20.097 20.097 ../../utils.py:133(resolve_reference_functions)
2000000 12.281 0.000 20.749 0.000 ../../utils.py:110()
1 12.185 12.185 32.121 32.121 /home/rodrigopex/Projects/vutg_eclipse/vutg/src/vut_parser.py:127(parse_signal_values)
1 11.801 11.801 32.551 32.551 ../../utils.py:105(gen_random_values)
2000000 10.368 0.000 13.501 0.000 /usr/lib/python2.5/random.py:147(randrange)
1 6.846 6.846 10.304 10.304 /home/rodrigopex/Projects/vutg_eclipse/vutg/src/plot_coverage.py:45(plot_cover)
[...] tem muito mais, porém o tottime é muito baixo, ou seja o gargalo está por aqui!!!

Analisando os dados vemos que aproximadamente 35 segundos (conte o tottime, tempo gasto realmente com a função) dos 95s estão em apenas um módulo o utils.py. Supõe-se que o módulo util.py é o gargalo do sistema já que o resto do tempo é bem distribuído pelas outras funções e módulos. Ele seria um bom alvo para as melhorias de desempenho. Seguindo esse modelo poderemos achar “sempre” o famigerado gargalo do sistema. Atacando-o diretamente poderemos ter uma melhoria significativa de performance com menos esforço. Observe também que o módulo random.py é dono de 10.368s do tempo de execução, talvez seja mais interessante usar o random.h diretamente de C. Modificações como essa são estratégicas e direcionadas o que torna muito mais eficiente o processo de tunning de módulos Python.

Realmente, descobrindo essas coisas vemos que o dono da frase citada no início do artigo tinha razão. “Python só é lento pra quem não sabe desenvolver…”. Aproveite o conhecimento adquirido e turbine seus projetos!

Este artigo é sobre uma das mais recentes façanhas da minha equipe de desenvolvimento: fazer com que um computador consiga se comunicar com um FPGA via serial utilizando uma uart (escrita em Verilog) muito simples. continua… caso tenha interessado a você este assunto e eu ainda não tiver terminado este artigo, entre em contato. Estou arrumando aos poucos a casa.

Em breve estarei postando algo sobre: linux, python, gentoo, blender, inkscape, robótica, entre outros temas que são rotina.
botao_brasil.png


  • Nenhum
  • russoz: Python: [...] Aplicativos Python lentos. Onde está o gargalo? [...]
  • Luciano Pacheco: Vale lembrar que o Rudá Moura apresentou uma palestra na segunda PyConBrasil (em Brasília), eu pelo menos assisti e gostei. :-) Segue o link dos
  • yguaratã: Aê Rodrigo, massa esse post sobre optimização e profiling. Ainda não tive necessidade de optimizar nada em Python, mas quando precisar já sei ond

Categorias

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.