Como posso fazer um perfil em Python linha a linha?
No entanto, o perfil cProfile (e a maioria dos outros profilers de Python que já vi até agora) parece ter apenas perfil no nível de chamada de funções. Isto causa confusão quando certas funções são chamadas de diferentes lugares-eu não tenho idéia se call #1 ou call #2 está tomando a maioria do tempo. Isto fica ainda pior quando o a função em questão tem seis níveis de profundidade, chamados de outros sete lugares.
Como é que consigo um perfil Linha-A-linha?em vez disto:
function #12, total time: 2.0s
Gostava de ver algo assim.
function #12 (called from somefile.py:102) 0.5s
function #12 (called from main.py:12) 1.5s
o CProfile mostra quanto do tempo total "transfers" para o pai, mas mais uma vez esta ligação perde-se quando se tem um monte de camadas e chamadas interligadas.
Idealmente, gostaria de ter uma interface gráfica que analisasse os dados e me mostrasse o meu ficheiro de código. com um tempo total dado a cada linha. Algo do género:main.py:
a = 1 # 0.0s
result = func(a) # 0.4s
c = 1000 # 0.0s
result = func(c) # 5.0s
Então eu seria capaz de clicar na segunda chamada" func(C)" para ver o que está tomando o tempo nessa chamada, separado da chamada "func (a)".
Isso faz sentido? Existe alguma biblioteca de perfis que recolha este tipo de informação? Perdi alguma ferramenta fantástica?3 answers
File: pystone.py
Function: Proc2 at line 149
Total time: 0.606656 s
Line # Hits Time Per Hit % Time Line Contents
==============================================================
149 @profile
150 def Proc2(IntParIO):
151 50000 82003 1.6 13.5 IntLoc = IntParIO + 10
152 50000 63162 1.3 10.4 while 1:
153 50000 69065 1.4 11.4 if Char1Glob == 'A':
154 50000 66354 1.3 10.9 IntLoc = IntLoc - 1
155 50000 67263 1.3 11.1 IntParIO = IntLoc - IntGlob
156 50000 65494 1.3 10.8 EnumLoc = Ident1
157 50000 68001 1.4 11.2 if EnumLoc == Ident1:
158 50000 63739 1.3 10.5 break
159 50000 61575 1.2 10.1 return IntParIO
Espero que isso ajude!
Também pode utilizar pprofile(pypi ). Se você quiser traçar o perfil de toda a execução, ela não requer modificação de código fonte. Você também pode traçar um perfil de um subconjunto de um programa maior de duas maneiras:
-
Activa ou desactiva a análise ao atingir um ponto específico do Código, tais como:
import pprofile profiler = pprofile.Profile() with profiler: some_code # Process profile content: generate a cachegrind file and send it to user.
-
Activa ou desactiva a análise assíncrona da pilha de chamadas (necessita de uma forma de activar este código na aplicação considerada, por exemplo, um manipulador de Sinais ou um (linha do trabalhador disponível) utilizando o perfil estatístico:
import pprofile profiler = pprofile.StatisticalProfile() statistical_profiler_thread = pprofile.StatisticalThread( profiler=profiler, ) with statistical_profiler_thread: sleep(n) # Likewise, process profile content
O formato de saída da anotação de código é muito parecido com o perfil de linha:
$ pprofile --threads 0 demo/threads.py
Command line: ['demo/threads.py']
Total duration: 1.00573s
File: demo/threads.py
File duration: 1.00168s (99.60%)
Line #| Hits| Time| Time per hit| %|Source code
------+----------+-------------+-------------+-------+-----------
1| 2| 3.21865e-05| 1.60933e-05| 0.00%|import threading
2| 1| 5.96046e-06| 5.96046e-06| 0.00%|import time
3| 0| 0| 0| 0.00%|
4| 2| 1.5974e-05| 7.98702e-06| 0.00%|def func():
5| 1| 1.00111| 1.00111| 99.54%| time.sleep(1)
6| 0| 0| 0| 0.00%|
7| 2| 2.00272e-05| 1.00136e-05| 0.00%|def func2():
8| 1| 1.69277e-05| 1.69277e-05| 0.00%| pass
9| 0| 0| 0| 0.00%|
10| 1| 1.81198e-05| 1.81198e-05| 0.00%|t1 = threading.Thread(target=func)
(call)| 1| 0.000610828| 0.000610828| 0.06%|# /usr/lib/python2.7/threading.py:436 __init__
11| 1| 1.52588e-05| 1.52588e-05| 0.00%|t2 = threading.Thread(target=func)
(call)| 1| 0.000438929| 0.000438929| 0.04%|# /usr/lib/python2.7/threading.py:436 __init__
12| 1| 4.79221e-05| 4.79221e-05| 0.00%|t1.start()
(call)| 1| 0.000843048| 0.000843048| 0.08%|# /usr/lib/python2.7/threading.py:485 start
13| 1| 6.48499e-05| 6.48499e-05| 0.01%|t2.start()
(call)| 1| 0.00115609| 0.00115609| 0.11%|# /usr/lib/python2.7/threading.py:485 start
14| 1| 0.000205994| 0.000205994| 0.02%|(func(), func2())
(call)| 1| 1.00112| 1.00112| 99.54%|# demo/threads.py:4 func
(call)| 1| 3.09944e-05| 3.09944e-05| 0.00%|# demo/threads.py:7 func2
15| 1| 7.62939e-05| 7.62939e-05| 0.01%|t1.join()
(call)| 1| 0.000423908| 0.000423908| 0.04%|# /usr/lib/python2.7/threading.py:653 join
16| 1| 5.26905e-05| 5.26905e-05| 0.01%|t2.join()
(call)| 1| 0.000320196| 0.000320196| 0.03%|# /usr/lib/python2.7/threading.py:653 join
Note que, como o pprofile não depende da modificação de código, pode analisar as declarações de Módulo de topo, permitindo traçar o tempo de arranque do programa (quanto tempo demora a importar módulos, inicializar globais, etc.)...).
Pode gerar uma saída formatada pelo cachegrind, por isso pode usar o kcachegrind para navegar por grandes resultados facilmente.
Disclosure: I am pprofile author.
O PyVmMonitor tem uma vista ao vivo que o pode ajudar (pode ligar-se a um programa em execução e obter estatísticas a partir dele).