web-dev-qa-db-fra.com

Comment utiliser line_profiler (de Robert Kern)?

J'ai essayé d'utiliser le module line_profiler pour obtenir un profil ligne par ligne sur un fichier Python. C'est ce que j'ai fait jusqu'à présent:

1) Line_profiler installé à partir de pypi en utilisant le fichier .exe (je suis sur WinXP et Win7). Il suffit de cliquer sur l'assistant d'installation.

2) A écrit un petit morceau de code (semblable à ce qui a été demandé dans une autre question répondue ici ).

from line_profiler import LineProfiler
def do_stuff(numbers):
    print numbers

numbers = 2
profile = LineProfiler(do_stuff(numbers))
profile.print_stats()

3) Exécutez le code depuis IDLE/PyScripter. Je n'ai que le temps.

Timer unit: 4.17188e-10 s

Comment obtenir un profil complet ligne par ligne sur le code que j'exécute? Je n'ai jamais utilisé de fonctionnalités avancées Python comme les décorateurs, il est donc difficile pour moi de comprendre comment utiliser les directives fournies par plusieurs articles comme ici et - ici .

21
Alex Tereshenkov

Suivez simplement l'exemple de Dan Riti du premier link , mais utilisez votre code. Tout ce que vous avez à faire après avoir installé le line_profiler le module est ajouter un @profile décorateur juste avant chaque fonction que vous souhaitez profiler ligne par ligne et assurez-vous que chacune est appelée au moins une fois ailleurs dans le code — donc pour votre exemple de code trivial, ce serait quelque chose comme ceci:

example.py fichier:

@profile
def do_stuff(numbers):
    print numbers

numbers = 2
do_stuff(numbers)

Cela fait, exécutez votre script via le kernprof.py qui a été installé dans votre C:\Python27\Scripts répertoire. Voici la sortie réelle (pas très intéressante) de cette opération dans une session de ligne de commande Windows 7:

> python "C:\Python27\Scripts\kernprof.py" -l -v example.py
2
Wrote profile results to example.py.lprof
Timer unit: 3.2079e-07 s

File: example.py
Function: do_stuff at line 2
Total time: 0.00185256 s

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     1                                           @profile
     2                                           def do_stuff(numbers):
     3         1         5775   5775.0    100.0      print numbers

Vous devrez probablement adapter cette dernière étape: l'exécution de votre script de test avec kernprof.py au lieu de directement par l'interpréteur Python - afin de faire l'équivalent depuis IDLE ou PyScripter.

Mise à jour

Il semble que dans line_profiler v1.0, l'utilitaire kernprof est distribué en tant qu'exécutable, pas en .py fichier de script tel qu'il était lorsque j'ai écrit ce qui précède. Cela signifie que les éléments suivants doivent maintenant être utilisés pour l'invoquer à partir de la ligne de commande:

> "C:\Python27\Scripts\kernprof.exe" -l -v example.py
13
martineau

Cette réponse est une copie de ma réponse ici pour savoir comment obtenir line_profiler statistiques à partir d'un script Python (sans utiliser kernprof depuis la ligne de commande ni avoir à ajouter @profile décorateurs de fonctions et méthodes de classe). Toutes les réponses (que j'ai vues) à similaires line_profiler les questions décrivent uniquement l'utilisation de kernprof.


Le line_profiler les cas de test (trouvés sur GitHub ) ont un exemple de génération de données de profil à partir d'un script Python. Vous devez encapsuler la fonction que vous voulez profil, puis appelez l'encapsuleur en passant les arguments de fonction souhaités.

from line_profiler import LineProfiler
import random

def do_stuff(numbers):
    s = sum(numbers)
    l = [numbers[i]/43 for i in range(len(numbers))]
    m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()

Production:

Timer unit: 1e-06 s

Total time: 0.000649 s
File: <ipython-input-2-2e060b054fea>
Function: do_stuff at line 4

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     4                                           def do_stuff(numbers):
     5         1           10     10.0      1.5      s = sum(numbers)
     6         1          186    186.0     28.7      l = [numbers[i]/43 for i in range(len(numbers))]
     7         1          453    453.0     69.8      m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

Ajout de fonctions supplémentaires au profil

Vous pouvez également ajouter des fonctions supplémentaires à profiler également. Par exemple, si vous aviez une deuxième fonction appelée et que vous enveloppez uniquement la fonction appelant, vous ne verrez que les résultats du profil de la fonction appel fonction.

from line_profiler import LineProfiler
import random

def do_other_stuff(numbers):
    s = sum(numbers)

def do_stuff(numbers):
    do_other_stuff(numbers)
    l = [numbers[i]/43 for i in range(len(numbers))]
    m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()

Ce qui précède ne produirait que la sortie de profil suivante pour la fonction appel:

Timer unit: 1e-06 s

Total time: 0.000773 s
File: <ipython-input-3-ec0394d0a501>
Function: do_stuff at line 7

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     7                                           def do_stuff(numbers):
     8         1           11     11.0      1.4      do_other_stuff(numbers)
     9         1          236    236.0     30.5      l = [numbers[i]/43 for i in range(len(numbers))]
    10         1          526    526.0     68.0      m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

Dans ce cas, vous pouvez ajouter la fonction supplémentaire appelée au profil comme ceci:

from line_profiler import LineProfiler
import random

def do_other_stuff(numbers):
    s = sum(numbers)

def do_stuff(numbers):
    do_other_stuff(numbers)
    l = [numbers[i]/43 for i in range(len(numbers))]
    m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp.add_function(do_other_stuff)   # add additional function to profile
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()

Production:

Timer unit: 1e-06 s

Total time: 9e-06 s
File: <ipython-input-4-dae73707787c>
Function: do_other_stuff at line 4

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     4                                           def do_other_stuff(numbers):
     5         1            9      9.0    100.0      s = sum(numbers)

Total time: 0.000694 s
File: <ipython-input-4-dae73707787c>
Function: do_stuff at line 7

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     7                                           def do_stuff(numbers):
     8         1           12     12.0      1.7      do_other_stuff(numbers)
     9         1          208    208.0     30.0      l = [numbers[i]/43 for i in range(len(numbers))]
    10         1          474    474.0     68.3      m = ['hello'+str(numbers[i]) for i in range(len(numbers))]

REMARQUE: l'ajout de fonctions au profil de cette manière ne nécessite pas de modifications du code profilé (c'est-à-dire, pas besoin d'ajouter @profile décorateurs).

38
tdube