Cum poți profil un script Python?

Proiect Euler și alte codificare concursuri de multe ori au un timp maxim pentru a rula sau oameni lăuda cât de repede le anumită soluție se execută. Cu python, uneori abordări sunt oarecum kludgey - de exemplu, adăugarea de distribuție cod pentru __principal__.

Ce este o modalitate buna de a profil cât timp un program in python nevoie pentru a rula?

Comentarii la întrebare (4)
Soluția

Python include un psiholog numit cProfile. Acesta oferă nu numai timpul total de funcționare, dar, de asemenea, ori fiecare funcție separat, și vă spune cât de multe ori fiecare funcție a fost numit, făcându-l ușor pentru a determina în cazul în care ar trebui să facă optimizări.

Puteți apela direct din cod, sau de interpret, astfel:

import cProfile
cProfile.run('foo()')

Chiar mai util, puteți invoca cProfile atunci când rulează un script:

python -m cProfile myscript.py

Pentru a face chiar mai ușor, am făcut un mic lot fișier numit 'profil.bat':

python -m cProfile %1

Deci, tot ce trebuie să faceți este să rulați:

profile euler048.py

Și văd asta:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 :1()
 1000    0.051    0.000    0.051    0.000 euler048.py:2()
    1    0.005    0.005    0.061    0.061 euler048.py:2()
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

EDIT: Actualizat link-ul de la un film bun de resurse de PyCon 2013 intitulat Python Profiling [De asemenea, prin intermediul YouTube](https://www.youtube.com/watch?v=QJwVYlDzAXs).

Comentarii (13)

Un timp în urmă am făcut pycallgraph, care generează o vizualizare din codul Python. Edit: am'am actualizat, de exemplu pentru a lucra cu 3.3, cea mai recentă versiune ca din acest scris.

După un pip instala pycallgraph și instalarea GraphViz puteți să-l rula din linia de comandă:

pycallgraph graphviz -- ./mypythonscript.py

Sau, puteți profil special piese de cod:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

Oricare dintre acestea va genera un pycallgraph.png fișier similar cu imaginea de mai jos:

Comentarii (10)

L's remarcat faptul că utilizarea profiler funcționează numai (implicit) pe firul principal, și nu te vei't obține informații de la alte fire, dacă le folosesc. Acest lucru poate fi un pic te-am prins ca este complet trecută sub tăcere în profiler documentația.

Dacă doriți, de asemenea, la profilul fire, te'll doresc să se uite la filetare.setprofile() funcția în docs.

Ai putea, de asemenea, de a crea propriul dvs. de filetare.Fir subclasă a face acest lucru:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

și de a folosi că ProfiledThread de clasă în loc de cea standard. S-ar putea oferi mai multă flexibilitate, dar am'nu sunt sigur că-l's valoare de ea, mai ales dacă sunteți folosind codul terț care nu't folosi clasa ta.

Comentarii (6)

Python wiki este o pagină de mare pentru profilare resurse: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

cum este python-docs: http://docs.python.org/library/profile.html

așa cum se arată de către Chris Lawlor cProfile este un instrument de mare și poate fi folosit cu ușurință pentru a imprima pe ecran:

python -m cProfile -s time mine.py 

sau într-un fișier:

python -m cProfile -o output.file mine.py 

PS> Dacă utilizați Ubuntu, asigurați-vă că pentru a instala python-profil

sudo apt-get install python-profiler 

Dacă de ieșire pentru fișiere puteți obține frumos vizualizări utilizând următoarele instrumente

PyCallGraph : un instrument pentru a crea graficul de apel imagini
instalare:

 sudo pip install pycallgraph

run:

 pycallgraph mine.py args

vedere:

 gimp pycallgraph.png

Puteți folosi orice doriți pentru a vedea png, am folosit gimp
Din păcate, de multe ori am

dot: grafic este prea mare pentru cairo-renderer bitmaps. Scalarea de 0.257079 pentru a se potrivi

ceea ce face ca imaginile mele unusably mici. Așa că, în general, de a crea fișierele svg:

pycallgraph -f svg -o pycallgraph.svg mine.py 

PS> asigurați-vă că pentru a instala graphviz (care oferă dot program):

sudo pip install graphviz

Alternative Grafice folosind gprof2dot via @maxy / @quodlibetor :

sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
Comentarii (2)

@Maxy's comenteze acest răspuns m-a ajutat destul că eu cred că merită să aibă propriul răspuns: am avut deja cProfile-a generat .pstats fișiere și eu am't doriți să re-rula lucruri cu pycallgraph, asa ca am folosit gprof2dot, și a fost destul svg s:

$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

și BAM!

Se foloseste dot (același lucru pe care pycallgraph foloseste) deci ieșire arată similar. Am impresia că gprof2dot pierde mai puțin însă informații:

Comentarii (9)

Am fugit într-un instrument la îndemână numit SnakeViz atunci când cercetarea pe acest subiect. SnakeViz este un web bazate pe crearea de profiluri instrument de vizualizare. Este foarte ușor de a instala și de a folosi. De obicei nu folosesc este de a genera un fișier stat cu %p și apoi face o analiză în SnakeViz.

Principalele viz tehnica utilizată este Sunburst diagramă după cum se arată mai jos, în care ierarhia de apeluri de funcții este amenajat ca straturi de arce și informații în timp codificat în unghiulare lățimi.

Cel mai bun lucru este că puteți interacționa cu graficul. De exemplu, pentru a mări într-un singur clic pe un arc de cerc, și arcul și descendenții săi vor fi extinsă ca un nou sunburst pentru a afișa mai multe detalii.

Comentarii (2)

Cred că cProfile este mare pentru crearea de profiluri, în timp ce kcachegrind este mare pentru vizualizarea rezultatelor. A pyprof2calltree între mânere de fișiere de conversie.

python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree

Pentru a instala instrumentele necesare (pe Ubuntu, cel putin):

apt-get install kcachegrind
pip install pyprof2calltree

Rezultatul:

Comentarii (1)

De asemenea, demn de menționat este GUI cProfile basculante viewer RunSnakeRun. Acesta vă permite să sortați și selectați, astfel zoom pe părțile relevante ale programului. Dimensiunile dreptunghiurilor în imagine este proporțională cu timpul necesar. Dacă mouse-ul peste un dreptunghi se evidențiază în masă și peste tot pe hartă. Atunci când faceți dublu-clic pe un dreptunghi se mărește pe acea parte. Acesta vă va arăta care solicită acea parte și ce porțiune de apeluri.

Informațiile descriptive este de foarte mare ajutor. Acesta vă arată un cod pentru acel puțin care poate fi de ajutor atunci când ai de-a face cu built-in biblioteca de apeluri. Aceasta vă spune ce fișiere și ce linie pentru a găsi codul.

Doresc, de asemenea, la punctul de la care OPERAȚIUNEA a spus 'profilare' dar se pare că a însemnat 'sincronizare'. Păstrați în minte, programele vor rula mai lent atunci când profilate.

Comentarii (0)

Simplă și rapid modalitate de a găsi în cazul în care tot timpul se întâmplă.

1. pip install snakeviz

2. python -m cProfile -o temp.dat .py

3. snakeviz temp.dat

Atrage o diagramă într-un browser. Cea mai mare bucata este problema funcție. Foarte simplu.

Comentarii (1)

Un frumos profilare modulul este line_profiler (numit folosind script-ul kernprof.py). Acesta poate fi descărcat de aici.

Înțelegerea mea este că cProfile numai că vă oferă informații despre timpul total petrecut în fiecare funcție. Atât individuale de linii de cod nu sunt cronometrate. Aceasta este o problemă în calcul științific, deoarece de multe ori o singură linie poate lua o mulțime de timp. De asemenea, după cum îmi amintesc, cProfile n't timp l-am petrecut în numpy.dot.

Comentarii (0)

pprofile

line_profiler (prezentat deja aici), de asemenea, inspirat pprofile, care este descris ca:

Line-granularitate, fir-conștient deterministe și statistică pură-python profiler

Acesta oferă line-granularitate ca line_profiler, este pur Python, poate fi folosit ca un independent de comandă sau un modul, și poate genera chiar callgrind-fișiere în format care poate fi ușor de analizat cu[k|q]cachegrind`.

vprof

Există, de asemenea, vprof, un pachet Python descris ca:

[...] furnizarea de bogat și vizualizări interactive pentru diverse programe Python caracteristici, cum ar fi timpul de funcționare și de utilizare de memorie.

Comentarii (0)

Recent am creat ton pentru vizualizarea Python execuție și importa profiluri; aceasta poate fi de ajutor aici.

Instala cu pip3 instala ton A crea un profil de execuție python-mcProfile -o program.prof yourfile.py sau un profil de import (Python 3.7+ necesar) python-X importprofile yourfile.py 2> import.jurnal Apoi executați doar ton pe fișier ton program.prof

Comentarii (0)

Nu's o mulțime de răspunsuri, dar ei fie utilizați linia de comandă sau un program extern pentru crearea de profiluri și/sau sortarea rezultatelor.

Am pierdut într-adevăr un fel am putea folosi în IDE (eclipse-PyDev), fără a atinge linia de comandă sau instalarea nimic. Deci, aici este.

Profilare fără linie de comandă

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

A se vedea documente sau alte răspunsuri pentru mai multe informații.

Comentarii (1)

Următoarele Joe Shaw's a răspunde despre multi-threaded cod să nu lucreze cum era de așteptat, m-am gândit că runcallmetoda în cProfile este doar de a face de sine.enable () " și " auto.disable() apeluri jurul profilate apel de funcție, astfel încât să puteți face pur și simplu tu însuți și să ai tot ce cod vrei în-între, cu interferență minimă cu cod existent.

Comentarii (2)

În Virtaal's sursa's un foarte util clasă și decorator care pot face profilare (chiar și pentru anumite metode/functii) foarte ușor. De ieșire poate fi apoi vizualizate foarte confortabil în KCacheGrind.

Comentarii (1)

cProfile este mare pentru rapid profilare dar cele mai multe ori totul se termina cu erori. Funcția runctx rezolvă această problemă prin inițializarea corectă a mediului și a variabilelor, sper că poate fi util pentru cineva:

import cProfile
cProfile.runctx('foo()', None, locals())
Comentarii (0)

Calea mea este de a folosi yappi (https://code.google.com/p/yappi/). L's util mai ales combinat cu un RPC server unde (chiar și doar pentru depanare) tine registrul metodă pentru a porni, opri și de imprimare profilare informații, de exemplu, în acest fel:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

Atunci când programul dvs. de lucru, puteți începe profiler în orice moment, prin apel la startProfiler RPC metodă și basculante profilare informații într-un fișier jurnal de asteptare printProfiler (sau modifica rpc metoda de a reveni la apelant) și a obține astfel de ieșire:

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
.__new__:8                                                                                                                        220         0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
.__new__:8                                                                                                                        4           0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

Aceasta nu poate fi foarte util pentru script-uri scurte, dar ajută la optimizarea de tip server procesele având în vedere mai ales printProfiler metodă poate fi numit de mai multe ori de-a lungul timpului la profil și compara, de exemplu, programe diferite scenarii de utilizare.

Comentarii (2)

Dacă doriți pentru a face un cumulative profiler, sensul de a rula funcția de mai multe ori într-un rând și urmăriți suma rezultatelor.

puteți folosi acest cumulative_profiler decorator:

l's python >= 3.6 specifice, dar puteți elimina `nelocale pentru a lucra la versiuni mai vechi.

import cProfile, pstats

class _ProfileFunc:
    def __init__(self, func, sort_stats_by):
        self.func =  func
        self.profile_runs = []
        self.sort_stats_by = sort_stats_by

    def __call__(self, *args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()  # this is the profiling section
        retval = self.func(*args, **kwargs)
        pr.disable()

        self.profile_runs.append(pr)
        ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
        return retval, ps

def cumulative_profiler(amount_of_times, sort_stats_by='time'):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            nonlocal function, amount_of_times, sort_stats_by  # for python 2.x remove this row

            profiled_func = _ProfileFunc(function, sort_stats_by)
            for i in range(amount_of_times):
                retval, ps = profiled_func(*args, **kwargs)
            ps.print_stats()
            return retval  # returns the results of the function
        return wrapper

    if callable(amount_of_times):  # incase you don't want to specify the amount of times
        func = amount_of_times  # amount_of_times is the function in here
        amount_of_times = 5  # the default amount
        return real_decorator(func)
    return real_decorator

Exemplu

profilare funcția "baz"

import time

@cumulative_profiler
def baz():
    time.sleep(1)
    time.sleep(2)
    return 1

baz()

"baz" a fugit de 5 ori și tipărite asta:

         20 function calls in 15.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   15.003    1.500   15.003    1.500 {built-in method time.sleep}
        5    0.000    0.000   15.003    3.001 :3(baz)
        5    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

specificarea sumei de ori

@cumulative_profiler(3)
def baz():
    ...
Comentarii (0)

Pentru a adăuga la https://stackoverflow.com/a/582337/1070617,

Am scris acest modul care vă permite să utilizați cProfile și a vedea de ieșire cu ușurință. Mai multe aici: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

Vezi, de asemenea: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html privire la modul de a face sens din statisticile colectate.

Comentarii (0)

Un nou instrument pentru a gestiona profiluri în Python este PyVmMonitor: http://www.pyvmmonitor.com/

Ea are unele caracteristici unice, cum ar fi

  • Atașați profiler pentru o funcționare (CPython) program
  • La cerere profilare cu Yappi integrare
  • Profil de pe alta masina
  • Mai multe procese suport (multiprocesare, django...)
  • Live sampling/CPU vedere (cu interval de timp de selecție)
  • Deterministe profilare prin cProfile/profil de integrare
  • Analiza existente PStats rezultate
  • Deschide fișiere DOT
  • Programatic acces API
  • Grupa probelor de metoda sau linie
  • PyDev integrare
  • PyCharm integrare

Notă:'s comercială, dar gratuit pentru open source.

Comentarii (0)