2. Prolage (proling)
Le prolage consiste à déterminer où mon code passe (perd ?)
du temps
De préférence sans avoir à se taper partout des
t0 = datetime . now ()
. . .
p r i n t ( datetime . now () − t0 )
L'objectif est de savoir où concentrer ses eorts pour
optimiser le code, avant de passer à la parallélisation
Bruno Goutorbe Prolage en Python
3. Cas d'usage
Pour illustrer la suite, on va se baser sur le script
similar_products.py, qui part d'une dataframe de produits :
# product_id price
0 product_0 700.10
1 product_1 500.55
. . .
et d'une matrice de similarité S :
Sij = similarité entre le produit i et le produit j
pour créer un chier qui associe à chaque produit une liste de
produit similaires (1) au moins aussi chers et (2) triés par
similarité décroissante :
product_id simproduct_ids
product_0 product_244
product_1 product_391 , product_175 , product_261
. . .
Bruno Goutorbe Prolage en Python
4. Temps d'exécution du code
Avec 100 produits : 2 s
Avec 500 produits : 15 s
Avec 1000 produits : 30 s
. . .
Estimation avec 2 millions de produits : environ 17 heures !
Un prolage s'impose
Bruno Goutorbe Prolage en Python
5. Proleur
On utilise de préférence cProfile pour proler un code Python :
soit directement dans l'interpréteur Python :
import cProfile
cProfile.run(2 + 2)
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 string :1(module )
1 0.000 0.000 0.000 0.000 {built -in method exec}
1 0.000 0.000 0.000 0.000 {method 'disable ' ...}
soit en ligne de commande :
python −m c P r o f i l e s c r i p t . py
tottime = temps passé dans la fonction (sans compter les
fonctions qu'elle appelle)
cumtime = temps passé dans la fonction (en incluant les
fonctions qu'elle appelle)
Bruno Goutorbe Prolage en Python
6. Visualisation graphique : RunSnakeRun
Comme les résultats sont imbitables on les envoie dans un
chier et on se sert d'outils pour nous sortir de belles
représentations graphiques :
python −m c P r o f i l e −o s c r i p t . prof s c r i p t . py
runsnake s c r i p t . prof
ce qui donne des boites dont la taille représente le temps
passé :
Problème : RunSnakeRun n'est pas compatible avec Python 3
Bruno Goutorbe Prolage en Python
7. Visualisation graphique : SnakeViz
Pour installer SnakeViz sur Windows, un pip install snakeviz
fonctionne bien, ensuite :
python −m c P r o f i l e −o similar_products . prof
similar_products . py
snakeviz similar_products . prof
Et le miracle
s'accomplit :
Disque interne =
fonction racine
Un arc = une
fonction appelée
(par l'arc adjacent
interne)
Longueur d'arc =
temps passé
Bruno Goutorbe Prolage en Python
8. Granularité : de la fonction à la ligne
On a trouvé que le script passe la moitié de son temps dans la
fonction get_simproducts() et l'autre moitié dans
filter_and_sort_simproducts() 1
Mais on aimerait bien avoir une vision du temps passé ligne
par ligne dans ces fonctions
cProle agrège des statistiques par fonction ; pour passer à la
ligne il faut line_profiler.
Sur Windows un pip install line_profiler a peu de
chance de marcher. Mieux vaut télécharger la libraire
précompilée
2.
1. ok ce sont les deux seules fonctions. Mais bon, vous serez bien content de
pouvoir les identier lorsque votre programme contiendra 50 fonctions réparties
dans 15 modules.
2. ici : www.lfd.uci.edu/∼gohlke/pythonlibs/#line_proler
Bruno Goutorbe Prolage en Python
9. Prolage par ligne
Avant d'utiliser line_profiler il faut décorer les fonctions
que l'on souhaite proler avec un @profile au-dessus de la
fonction, par exemple :
@profile
def filter_and_sort_simproducts (...):
...
Ensuite on tape en ligne de commande
kernprof -l -v similar_products.py
Bruno Goutorbe Prolage en Python
10. Prolage par ligne (suite)
Et ça donne :
Total time : 21.6487 s
F i l e : similar_products . py
Function : filter_and_sort_simproducts at l i n e 34
Line # Hits Time Per Hit % Time Line Contents
==============================================================
34 @ p r o f i l e
35 def filter_and_sort
36
37 removes s i m i l a r
38 s o r t s them by
39
40 500 5107 10.2 0.0 i f min_price :
41 500 6735587 13471.2 9.4 dfsimproduct
42 500 64969459 129938.9 90.6 dfsimproducts .
43 500 4408 8.8 0.0 return dfsimprod
On trouve que les lignes
dfsimproducts [ ' sim ' ] = s i m i l a r i t i e s
dfsimproducts . sort_values ( ' sim ' , ascending=False ,
i n p l a c e=True )
consomment 90% du temps.
Bruno Goutorbe Prolage en Python
11. Optimisation
Problème de la ligne
dfsimproducts . sort_values ( ' sim ' , ascending=False ,
i n p l a c e=True )
→ le tri sur place prend 10 fois plus de temps qu'un tri vers
une nouvelle dataframe !
Problème de la ligne
dfsimproducts [ ' sim ' ] = s i m i l a r i t i e s
→ l'opération ajouter une colonne force pandas à créer une
copie, alors que dfsimproducts n'était au départ qu'une vue
de dfproducts
Bruno Goutorbe Prolage en Python
12. Résumé
cProfile pour proler le code par fonction
SnakeViz pour visualiser les résultats
line_profiler pour proler le code par ligne
Un lien intéressant pour en savoir plus : nbviewer.jupyter.org
Bruno Goutorbe Prolage en Python