Come puoi profilare uno script Python?


1283

Project Euler e altri concorsi di codifica spesso hanno un tempo massimo di esecuzione o le persone si vantano della velocità con cui viene eseguita la loro particolare soluzione. Con Python, a volte gli approcci sono in qualche modo kludgey, vale a dire l'aggiunta di un codice temporale a __main__.

Qual è un buon modo per profilare quanto tempo richiede l'esecuzione di un programma Python?


113
I programmi di euler del progetto non dovrebbero richiedere la profilazione. O hai un algoritmo che funziona in meno di un minuto o hai completamente l'algoritmo sbagliato. "Accordare" è raramente appropriato. In genere devi adottare un nuovo approccio.
S. Lott,

105
S.Lott: la profilazione è spesso un modo utile per determinare quali subroutine sono lente. Le subroutine che richiedono molto tempo sono ottime candidate per il miglioramento algoritmico.
stalepretzel,

Risposte:


1370

Python include un profiler chiamato cProfile . Non solo fornisce il tempo totale di esecuzione, ma anche ogni volta separatamente ciascuna funzione e ti dice quante volte ogni funzione è stata chiamata, facilitando la determinazione di dove dovresti effettuare le ottimizzazioni.

Puoi chiamarlo dal tuo codice o dall'interprete, in questo modo:

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

Ancora più utile, puoi invocare cProfile quando esegui uno script:

python -m cProfile myscript.py

Per renderlo ancora più semplice, ho creato un piccolo file batch chiamato 'profile.bat':

python -m cProfile %1

Quindi tutto ciò che devo fare è eseguire:

profile euler048.py

E ottengo questo:

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 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    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: collegamento aggiornato a una buona risorsa video di PyCon 2013 intitolata Python Profiling
anche tramite YouTube .


251
Inoltre è utile ordinare i risultati, che può essere fatto tramite l'opzione -s, ad esempio: '-s time'. È possibile utilizzare le opzioni di ordinamento cumulativo / nome / ora / file.
Jiri,

19
Vale anche la pena notare che è possibile utilizzare il modulo cProfile da ipython utilizzando la funzione magica% prun (esecuzione profilo). Prima importa il tuo modulo e poi chiama la funzione principale con% prun: import euler048; % prun euler048.main ()
RussellStewart

53
Per visualizzare i dump di cProfile (creati da python -m cProfile -o <out.profile> <script>), RunSnakeRun , invocato come runsnake <out.profile>è inestimabile.
Lily Chung,

13
@NeilG anche per Python 3, cprofileè ancora raccomandato sopra profile.
trichoplax,

17
Per visualizzare i dump di cProfile, RunSnakeRun non è stato aggiornato dal 2011 e non supporta python3. Si dovrebbe usare snakeviz invece
Giacomo Tecya Pigani

424

Qualche tempo fa ho creato ciò pycallgraphche genera una visualizzazione dal tuo codice Python. Modifica: ho aggiornato l'esempio per lavorare con 3.3, l'ultima versione al momento della stesura di questo documento.

Dopo aver pip install pycallgraphinstallato GraphViz e puoi eseguirlo dalla riga di comando:

pycallgraph graphviz -- ./mypythonscript.py

Oppure puoi profilare parti particolari del tuo codice:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

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

Uno di questi genererà un pycallgraph.pngfile simile all'immagine seguente:

inserisci qui la descrizione dell'immagine


43
Stai colorando in base alla quantità di chiamate? In tal caso, dovresti colorare in base al tempo perché la funzione con il maggior numero di chiamate non è sempre quella che richiede più tempo.
rosso

21
@red Puoi personalizzare i colori come preferisci e anche in modo indipendente per ogni misurazione. Ad esempio rosso per le chiamate, blu per l'ora, verde per l'utilizzo della memoria.
GAK

2
ottenere questo erroreTraceback (most recent call last): /pycallgraph.py", line 90, in generate output.done() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 94, in done source = self.generate() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 143, in generate indent_join.join(self.generate_attributes()), File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 169, in generate_attributes section, self.attrs_from_dict(attrs), ValueError: zero length field name in format
Ciasto piekarz il

3
Ho aggiornato questo per menzionare che è necessario installare GraphViz affinché le cose funzionino come descritto. Su Ubuntu questo è giusto sudo apt-get install graphviz.
mlissner,

2
Ciò richiede un po 'di lavoro per l'installazione qui è di 3 passaggi per aiutare. 1. Installa tramite pip, 2. Installa GraphViz tramite exe 3. Imposta le variabili del percorso nella directory GraphViz 4. Scopri come correggere tutti gli altri errori. 5. Capire dove salva il file png?
palude

199

Vale la pena sottolineare che l'utilizzo del profiler funziona solo (per impostazione predefinita) sul thread principale e non otterrai alcuna informazione dagli altri thread se li usi. Questo può essere un po 'un gotcha poiché è completamente non menzionato nella documentazione del profiler .

Se vuoi anche profilare i thread, ti consigliamo di guardare la threading.setprofile()funzione nei documenti.

Puoi anche creare la tua threading.Threadsottoclasse per farlo:

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,))

e usa quella ProfiledThreadclasse invece di quella standard. Potrebbe darti maggiore flessibilità, ma non sono sicuro che ne valga la pena, soprattutto se stai usando un codice di terze parti che non userebbe la tua classe.


1
Non vedo alcun riferimento a Runcall nella documentazione. Dando un'occhiata a cProfile.py, non sono sicuro del motivo per cui usi la funzione threading.Thread.run né auto come argomento. Mi sarei aspettato di vedere un riferimento al metodo di esecuzione di un altro thread qui.
PypeBros,

Non è nella documentazione, ma è nel modulo. Vedi hg.python.org/cpython/file/6bf07db23445/Lib/cProfile.py#l140 . Ciò ti consente di profilare una chiamata di funzione specifica e nel nostro caso vogliamo profilare la targetfunzione del thread , che è ciò threading.Thread.run()che esegue la chiamata. Ma come ho detto nella risposta, probabilmente non vale la pena sottoclassare Thread, dal momento che qualsiasi codice di terze parti non lo utilizzerà, e invece lo utilizzerà threading.setprofile().
Joe Shaw,

9
anche il wrapping del codice con profiler.enable () e profiler.disable () sembra funzionare abbastanza bene. Questo è fondamentalmente ciò che fanno Runcall e non impone alcun numero di argomenti o cose simili.
PypeBros,


1
Joe, sai come gioca il profiler con asyncio in Python 3.4?
Nick Chammas,

149

Il wiki di Python è un'ottima pagina per le risorse di profilazione: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

come è la documentazione di Python: http://docs.python.org/library/profile.html

come mostrato da Chris Lawlor cProfile è un ottimo strumento e può essere facilmente utilizzato per stampare sullo schermo:

python -m cProfile -s time mine.py <args>

o per archiviare:

python -m cProfile -o output.file mine.py <args>

PS> Se stai usando Ubuntu, assicurati di installare python-profile

apt-get install python-profiler 

Se si esegue l'output su file, è possibile ottenere visualizzazioni piacevoli utilizzando i seguenti strumenti

PyCallGraph: uno strumento per creare immagini di grafici di chiamata
installa:

 pip install pycallgraph

correre:

 pycallgraph mine.py args

Visualizza:

 gimp pycallgraph.png

Puoi usare quello che ti piace per visualizzare il file png, ho usato gimp
Sfortunatamente spesso lo capisco

punto: il grafico è troppo grande per le bitmap di cairo-renderer. Ridimensionamento di 0,257079 per adattarsi

il che rende le mie immagini insolitamente piccole. Quindi generalmente creo file svg:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS> assicurati di installare graphviz (che fornisce il programma dot):

pip install graphviz

Rappresentazione grafica alternativa utilizzando gprof2dot tramite @maxy / @quodlibetor:

pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg

12
gprof2dot può fare anche quei grafici. Penso che l'output sia un po 'più bello ( esempio ).
maxy,

2
graphviz è richiesto anche se si utilizza OSX
Vaibhav Mishra il

134

Il commento di Maxy su questa risposta mi ha aiutato abbastanza da pensare che meriti la sua stessa risposta: avevo già file .pstats generati da cProfile e non volevo rieseguire le cose con il pycallgraph, quindi ho usato gprof2dot e sono diventato piuttosto SVG:

$ 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

e BLAM!

Usa il punto (la stessa cosa che usa il pycallgraph) quindi l'output è simile. Ho l'impressione che gprof2dot perda meno informazioni:

Esempio di output di gprof2dot


1
Buon approccio, funziona davvero bene poiché puoi visualizzare SVG in Chrome ecc. E ridimensionarlo su / giù. La terza riga ha un refuso, dovrebbe essere: ln -s pwd/gprof2dot/gprof2dot.py $ HOME / bin (o usa ln -s $ PWD / gprof2dot / gprof2dot.py ~ / bin nella maggior parte delle shell - l'accento grave è preso come formattazione in primo luogo versione).
RichVel

2
Ah, buon punto. Ho lnsbagliato l'ordine delle discussioni quasi ogni volta.
quodlibetor,

7
il trucco è ricordare che ln e cp hanno lo stesso ordine degli argomenti - pensateci come 'copiare file1 in file2 o dir2, ma facendo un collegamento'
RichVel

Questo ha senso, penso che l'uso di "TARGET" nella manpage mi faccia perdere.
quodlibetor,

Per favore, come hai ottenuto gli angoli arrotondati? Sento che migliora la leggibilità. Ottengo solo brutti spigoli vivi che non è bello in presenza di molti bordi attorno alle scatole.
Hibou57,

78

Mi sono imbattuto in uno strumento utile chiamato SnakeViz durante la ricerca di questo argomento. SnakeViz è uno strumento di visualizzazione del profilo basato sul web. È molto facile da installare e utilizzare. Il solito modo in cui lo uso è generare un file stat con%prun e quindi eseguire analisi in SnakeViz.

La principale tecnica utilizzata è la tabella Sunburst come mostrato di seguito, in cui la gerarchia delle chiamate di funzioni è organizzata come strati di archi e informazioni temporali codificate nelle loro larghezze angolari.

La cosa migliore è che puoi interagire con il grafico. Ad esempio, per ingrandire è possibile fare clic su un arco e l'arco e i suoi discendenti verranno ingranditi come un nuovo sprazzo di sole per visualizzare più dettagli.

inserisci qui la descrizione dell'immagine


1
La risposta di CodeCabbie include le (brevi) istruzioni di installazione e mostra come (facilmente) usare SnakeViz.
Oren Milman,

Qui ho letto la buona guida dell'IMHO su come usare il profiling per Python su notebook jupyter
Alexei Martianov

73

Il modo più semplice e veloce per trovare dove sta andando tutto il tempo.

1. pip install snakeviz

2. python -m cProfile -o temp.dat <PROGRAM>.py

3. snakeviz temp.dat

Disegna un grafico a torta in un browser. Il pezzo più grande è la funzione problema. Molto semplice.


1
Questo è stato molto utile. Grazie.
jippyjoe4,

55

Penso che cProfilesia ottimo per la profilazione, mentre kcachegrindè ottimo per visualizzare i risultati. In pyprof2calltreemezzo gestisce la conversione del file.

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

Per installare gli strumenti richiesti (almeno su Ubuntu):

apt-get install kcachegrind
pip install pyprof2calltree

Il risultato:

Schermata del risultato


9
Gli utenti Mac installano brew install qcachegrinde sostituiscono ciascuno kcachegrind con qcachegrind nella descrizione per una profilazione corretta.
Kevin Katzke il

Ho dovuto farlo per farlo funzionare:export QT_X11_NO_MITSHM=1
Yonatan Simson il

41

Degno di menzione è l'interfaccia grafica Cprofile spettatore discarica RunSnakeRun . Ti consente di ordinare e selezionare, ingrandendo in tal modo le parti pertinenti del programma. Le dimensioni dei rettangoli nella foto sono proporzionali al tempo impiegato. Se passi il mouse su un rettangolo, evidenzia quella chiamata nella tabella e ovunque sulla mappa. Quando fai doppio clic su un rettangolo, lo zoom su quella porzione. Ti mostrerà chi chiama quella parte e cosa chiama quella parte.

Le informazioni descrittive sono molto utili. Ti mostra il codice per quel bit che può essere utile quando hai a che fare con chiamate in libreria integrate. Ti dice quale file e quale riga trovare il codice.

Voglio anche sottolineare che l'OP ha detto "profilazione" ma sembra che intendesse "tempistica". Tieni presente che i programmi funzioneranno più lentamente quando vengono profilati.

inserisci qui la descrizione dell'immagine


34

Di recente ho creato il tonno per visualizzare il runtime di Python e importare i profili; questo può essere utile qui.

inserisci qui la descrizione dell'immagine

Installa con

pip install tuna

Crea un profilo di runtime

python3 -m cProfile -o program.prof yourfile.py

o un profilo di importazione (richiesto Python 3.7+)

python3 -X importprofile yourfile.py 2> import.log

Quindi esegui tonno sul file

tuna program.prof

33

Un bel modulo di profilazione è il line_profiler (chiamato usando lo script kernprof.py). Può essere scaricato qui .

La mia comprensione è che cProfile fornisce solo informazioni sul tempo totale trascorso in ciascuna funzione. Quindi le singole righe di codice non sono cronometrate. Questo è un problema nell'informatica scientifica poiché spesso una singola linea può richiedere molto tempo. Inoltre, come ricordo, cProfile non ha colto il tempo che stavo impiegando a dire numpy.dot.


33

pProfile

line_profiler(già presentato qui) anche ispirato pprofile, che è descritto come:

Profilatore di puro-pitone deterministico e statistico consapevole del filo, granularità di linea

Fornisce granularità di linea in quanto line_profiler, è puro Python, può essere utilizzato come comando autonomo o modulo e può persino generare file in formato callgrind che possono essere facilmente analizzati [k|q]cachegrind.

vprof

C'è anche vprof , un pacchetto Python descritto come:

[...] fornendo visualizzazioni ricche e interattive per varie caratteristiche del programma Python come il tempo di esecuzione e l'utilizzo della memoria.

mappa di calore


14

Ci sono molte risposte fantastiche, ma usano la riga di comando o qualche programma esterno per profilare e / o ordinare i risultati.

Mi mancava davvero un modo per poter usare il mio IDE (eclipse-PyDev) senza toccare la riga di comando o installare nulla. Quindi eccolo qui.

Profilatura senza riga di comando

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)

Vedi documenti o altre risposte per maggiori informazioni.


ad esempio, il profilo stampa {map} o {xxx}. come faccio a sapere da quale file viene chiamato il metodo {xxx}? il mio profilo stampa {metodo 'compress' degli oggetti 'zlib.Compress'} richiede la maggior parte del tempo, ma non uso alcun zlib, quindi immagino che alcune funzioni di chiamata numpy possano usarlo. Come faccio a sapere qual è esattamente il file e la riga richiede molto tempo?
machen,

12

Seguendo la risposta di Joe Shaw sul codice multi-thread che non funziona come previsto, ho capito che il runcallmetodo in cProfile sta semplicemente facendo self.enable()e self.disable()chiama attorno alla chiamata di funzione profilata, quindi puoi semplicemente farlo tu stesso e avere tutto il codice che vuoi in mezzo minima interferenza con il codice esistente.


3
Consiglio eccellente! Una rapida occhiata al cprofile.pycodice sorgente rivela che è esattamente ciò che runcall()fa. Essere più specifici, dopo aver creato un'istanza del profilo con prof = cprofile.Profile(), chiamare immediatamente prof.disable(), quindi aggiungere prof.enable()e prof.disable()chiamare solo la sezione di codice che si desidera profilare.
martineau,

Questo è molto utile, ma sembra che il codice che è effettivamente tra abilita e disabilita non sia profilato - solo le funzioni che chiama. Ho questo diritto? Dovrei racchiudere quel codice in una funzione per fare in modo che conti per uno qualsiasi dei numeri in print_stats ().
Bob Stein,

10

Nella fonte di Virtaal c'è una classe e un decoratore molto utili che possono rendere molto semplice la profilazione (anche per metodi / funzioni specifici). L'output può quindi essere visualizzato comodamente in KCacheGrind.


1
Grazie per questo gioiello. Cordiali saluti: Questo può essere utilizzato come modulo autonomo con qualsiasi codice, la base di codice Virtaal non è richiesta. Basta salvare il file in profiling.py e importare profile_func (). Usa @profile_func () come decoratore per qualsiasi funzione di cui hai bisogno per creare profili e viola. :)
Amjith,

9

cProfile è ottimo per la profilazione rapida, ma la maggior parte delle volte stava finendo per me con gli errori. La funzione runctx risolve questo problema inizializzando correttamente l'ambiente e le variabili, spero che possa essere utile per qualcuno:

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

7

Se si desidera creare un profiler cumulativo, ovvero eseguire la funzione più volte di seguito e osservare la somma dei risultati.

puoi usare questo cumulative_profilerdecoratore:

è python> = 3.6 specifico, ma puoi rimuoverlo nonlocalperché funziona su versioni precedenti.

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

Esempio

profilazione della funzione baz

import time

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

baz()

baz eseguito 5 volte e stampato questo:

         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 <ipython-input-9-c89afe010372>:3(baz)
        5    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

specificando la quantità di volte

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

7

La soluzione solo terminale (e la più semplice), nel caso in cui tutte quelle fantasiose UI non vengano installate o eseguite:
ignorare cProfilecompletamente e sostituirlo con pyinstrument, che raccoglierà e visualizzerà l'albero delle chiamate subito dopo l'esecuzione.

Installare:

$ pip install pyinstrument

Profilo e risultati di visualizzazione:

$ python -m pyinstrument ./prog.py

Funziona con python2 e 3.

[EDIT] La documentazione dell'API, per la profilazione di solo una parte del codice, è disponibile qui .


6

Il mio modo è usare yappi ( https://github.com/sumerc/yappi ). È particolarmente utile combinato con un server RPC in cui (anche solo per il debug) si registra il metodo per avviare, arrestare e stampare informazioni di profilazione, ad esempio in questo modo:

@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)

Quindi, quando il programma funziona, è possibile avviare il profiler in qualsiasi momento chiamando il startProfilermetodo RPC e scaricare le informazioni di profiling in un file di registro chiamando printProfiler(o modificare il metodo rpc per restituirlo al chiamante) e ottenere tale output:

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
<string>.__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
<string>.__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 

Potrebbe non essere molto utile per gli script brevi, ma aiuta a ottimizzare i processi di tipo server in particolare dato che il printProfilermetodo può essere chiamato più volte nel tempo per profilare e confrontare, ad esempio, diversi scenari di utilizzo del programma.

Nelle versioni più recenti di yappi, funzionerà il seguente codice:

@staticmethod
def printProfile():
    yappi.get_func_stats().print_all()

Non dovrebbe essere chiamato Stupendo Yappi?
Therealstubot,

Sfortunatamente il codice sopra funziona solo con la versione 0.62 che non è disponibile su pypy. Il modulo deve essere compilato da 0,62 fonti disponibili qui: github.com/nirs/yappi/releases o utilizzare la build che ho creato per Windows in repository a tale scopo github.com/Girgitt/yappi/releases
Mr. Girgitt

la compatibilità con la versione 1.0 può essere facilmente fornita - almeno per l'output di stampa - modificando la funzione printProfiler: def printProfiler(): if not yappi_available: return stats = yappi.get_func_stats() stats.print_all(columns={0:("name",90), 1:("ncall", 5), 2:("tsub", 8), 3:("ttot", 8), 4:("tavg",8)}) (OK dopo aver provato un paio di volte a inserire il blocco di codice nel commento che ho rinunciato. Ciò è incredibilmente difficile per un sito di domande e risposte orientato alla programmazione. )
Mr. Girgitt,

4

Un nuovo strumento per gestire la profilazione in Python è PyVmMonitor: http://www.pyvmmonitor.com/

Ha alcune caratteristiche uniche come

  • Collega il profiler a un programma in esecuzione (CPython)
  • Profilazione su richiesta con integrazione Yappi
  • Profilo su un'altra macchina
  • Supporto di processi multipli (multiprocessing, django ...)
  • Campionamento live / vista CPU (con selezione intervallo di tempo)
  • Profilazione deterministica attraverso l'integrazione di cProfile / profilo
  • Analizza i risultati PStats esistenti
  • Apri file DOT
  • Accesso programmatico alle API
  • Raggruppa i campioni per metodo o linea
  • Integrazione con PyDev
  • Integrazione con PyCharm

Nota: è commerciale, ma gratuito per l'open source.


4

gprof2dot_magic

Funzione magica per gprof2dotprofilare qualsiasi istruzione Python come grafico DOT in JupyterLab o Jupyter Notebook.

inserisci qui la descrizione dell'immagine

Repository GitHub: https://github.com/mattijn/gprof2dot_magic

installazione

Assicurati di avere il pacchetto Python gprof2dot_magic.

pip install gprof2dot_magic

Le sue dipendenze gprof2dote graphvizverranno installate pure

uso

Per abilitare la funzione magica, caricare prima il gprof2dot_magicmodulo

%load_ext gprof2dot_magic

e quindi profilare qualsiasi istruzione di riga come grafico DOT in quanto tale:

%gprof2dot print('hello world')

inserisci qui la descrizione dell'immagine


3

Hai mai desiderato sapere cosa diavolo sta facendo lo script Python? Immettere Inspect Shell. Inspect Shell ti consente di stampare / modificare i globi ed eseguire le funzioni senza interrompere lo script in esecuzione. Ora con completamento automatico e cronologia dei comandi (solo su Linux).

Inspect Shell non è un debugger in stile pdb.

https://github.com/amoffat/Inspect-Shell

Potresti usarlo (e il tuo orologio da polso).



3

Dipenderebbe da cosa vuoi vedere dalla profilazione. Metriche temporali semplici possono essere fornite da (bash).

time python python_prog.py

Anche '/ usr / bin / time' può generare metriche dettagliate usando il flag '--verbose'.

Per controllare le metriche del tempo fornite da ciascuna funzione e capire meglio quanto tempo viene dedicato alle funzioni, è possibile utilizzare il cProfile integrato in Python.

Entrando in metriche più dettagliate come le prestazioni, il tempo non è l'unica metrica. Puoi preoccuparti di memoria, thread, ecc.
Opzioni di profilatura:
1. line_profiler è un altro profiler usato comunemente per scoprire le metriche dei tempi riga per riga.
2. memory_profiler è uno strumento per profilare l'utilizzo della memoria.
3. heapy (dal progetto Guppy) Descrive come vengono utilizzati gli oggetti nell'heap.

Questi sono alcuni dei più comuni che tendo a usare. Ma se vuoi saperne di più, prova a leggere questo libro. È un buon libro per iniziare pensando alle prestazioni. È possibile passare ad argomenti avanzati sull'utilizzo di Python compilato Cython e JIT (Just-in-time).


2

Con un profiler statistico come austin , non è necessaria alcuna strumentazione, il che significa che è possibile ottenere dati di profilazione da un'applicazione Python semplicemente con

austin python3 my_script.py

L'output non elaborato non è molto utile, ma è possibile reindirizzarlo a flamegraph.pl per ottenere una rappresentazione del grafico a fiamma di quei dati che ti fornisce una ripartizione del tempo trascorso (misurato in microsecondi di tempo reale).

austin python3 my_script.py | flamegraph.pl > my_script_profile.svg

2

Per ottenere statistiche rapide del profilo su un notebook IPython. Si può incorporare line_profiler e memory_profiler direttamente nei loro notebook.

Un altro pacchetto utile è Pympler . È un potente pacchetto di profilazione in grado di tracciare classi, oggetti, funzioni, perdite di memoria ecc. Esempi di seguito, Documenti allegati.

Prendilo!

!pip install line_profiler
!pip install memory_profiler
!pip install pympler

Caricalo!

%load_ext line_profiler
%load_ext memory_profiler

Usalo!


%tempo

%time print('Outputs CPU time,Wall Clock time') 
#CPU times: user 2 µs, sys: 0 ns, total: 2 µs Wall time: 5.96 µs

dà:

  • Tempi CPU: tempo di esecuzione a livello di CPU
  • sys times: tempo di esecuzione a livello di sistema
  • totale: tempo CPU + tempo di sistema
  • Tempo della parete: orologio della parete

% timeit

%timeit -r 7 -n 1000 print('Outputs execution time of the snippet') 
#1000 loops, best of 7: 7.46 ns per loop
  • Fornisce il miglior tempo per il dato numero di corse (r) in loop (n) volte.
  • Visualizza i dettagli sulla memorizzazione nella cache del sistema:
    • Quando gli snippet di codice vengono eseguiti più volte, il sistema memorizza nella cache alcune opzioni e non le esegue di nuovo, il che può ostacolare l'accuratezza dei report del profilo.

% Prun

%prun -s cumulative 'Code to profile' 

dà:

  • numero di chiamate di funzione (chiamate)
  • ha voci per chiamata di funzione (distinto)
  • tempo impiegato per chiamata (percall)
  • tempo trascorso fino a quella chiamata di funzione (cumtime)
  • nome del modulo / funzione chiamato ecc ...

Profilo cumulativo


% MEMIT

%memit 'Code to profile'
#peak memory: 199.45 MiB, increment: 0.00 MiB

dà:

  • Utilizzo della memoria

% lprun

#Example function
def fun():
  for i in range(10):
    print(i)

#Usage: %lprun <name_of_the_function> function
%lprun -f fun fun()

dà:

  • Statistiche sagge

LineProfile


sys.getsizeof

sys.getsizeof('code to profile')
# 64 bytes

Restituisce la dimensione di un oggetto in byte.


asizeof () dal pympler

from pympler import asizeof
obj = [1,2,("hey","ha"),3]
print(asizeof.asizeof(obj,stats=4))

pympler.asizeof può essere usato per studiare quanta memoria consumano determinati oggetti Python. A differenza di sys.getsizeof, asizeof ridimensiona gli oggetti in modo ricorsivo

pympler.asizeof


tracker dal pympler

from pympler import tracker
tr = tracker.SummaryTracker()
def fun():
  li = [1,2,3]
  di = {"ha":"haha","duh":"Umm"}
fun()
tr.print_diff()

Tiene traccia della durata di una funzione.

uscita tracker

Il pacchetto Pympler è costituito da un numero enorme di funzioni di utilità elevata per la profilatura del codice. Tutto ciò non può essere trattato qui. Vedere la documentazione allegata per implementazioni di profili dettagliati.

Pympler doc


1

C'è anche un profiler statistico chiamato statprof . È un profiler di campionamento, quindi aggiunge un sovraccarico minimo al codice e fornisce tempistiche basate sulla linea (non solo basate sulle funzioni). È più adatto ad applicazioni soft in tempo reale come i giochi, ma potrebbe avere meno precisione di cProfile.

La versione in pypi è un po 'vecchia, quindi puoi installarla pipspecificando il repository git :

pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01

Puoi eseguirlo in questo modo:

import statprof

with statprof.profile():
    my_questionable_function()

Vedi anche https://stackoverflow.com/a/10333592/320036


1

Ho appena sviluppato il mio profiler ispirato a pypref_time:

https://github.com/modaresimr/auto_profiler

Aggiungendo un decoratore mostrerà un albero di funzioni che richiedono tempo

@Profiler(depth=4, on_disable=show)

Install by: pip install auto_profiler

Esempio

import time # line number 1
import random

from auto_profiler import Profiler, Tree

def f1():
    mysleep(.6+random.random())

def mysleep(t):
    time.sleep(t)

def fact(i):
    f1()
    if(i==1):
        return 1
    return i*fact(i-1)


def show(p):
    print('Time   [Hits * PerHit] Function name [Called from] [Function Location]\n'+\
          '-----------------------------------------------------------------------')
    print(Tree(p.root, threshold=0.5))

@Profiler(depth=4, on_disable=show)
def main():
    for i in range(5):
        f1()

    fact(3)


if __name__ == '__main__':
    main()

Esempio di output


Time   [Hits * PerHit] Function name [Called from] [function location]
-----------------------------------------------------------------------
8.974s [1 * 8.974]  main  [auto-profiler/profiler.py:267]  [/test/t2.py:30]
├── 5.954s [5 * 1.191]  f1  [/test/t2.py:34]  [/test/t2.py:14]
   └── 5.954s [5 * 1.191]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
       └── 5.954s [5 * 1.191]  <time.sleep>
|
|
|   # The rest is for the example recursive function call fact
└── 3.020s [1 * 3.020]  fact  [/test/t2.py:36]  [/test/t2.py:20]
    ├── 0.849s [1 * 0.849]  f1  [/test/t2.py:21]  [/test/t2.py:14]
       └── 0.849s [1 * 0.849]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
           └── 0.849s [1 * 0.849]  <time.sleep>
    └── 2.171s [1 * 2.171]  fact  [/test/t2.py:24]  [/test/t2.py:20]
        ├── 1.552s [1 * 1.552]  f1  [/test/t2.py:21]  [/test/t2.py:14]
           └── 1.552s [1 * 1.552]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
        └── 0.619s [1 * 0.619]  fact  [/test/t2.py:24]  [/test/t2.py:20]
            └── 0.619s [1 * 0.619]  f1  [/test/t2.py:21]  [/test/t2.py:14]

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.