Bonjour. Dans ce cours je vais vous montrer comment on
peut faire du profilage d'application en Pharo.
Ça veut dire comment on va mesurer l'exécution de
certaines expressions et pour savoir si on peut les
remplacer par d'autres pour gagner du temps, lors de l'exécution
d'un programme.
En gros ce que disent les gens, c'est que quand on n'a
jamais fait de profilage d'une application, on a
potentiellement un gain entre 40 et 50 %.
Moi, je n'en suis pas convaincu ou je ne le sais pas, je
n'ai pas la preuve de ce genre de choses.
Par contre, je vais vous montrer quels sont les outils
qui existent en Pharo pour faire ce profilage.
La première expression qui existe en Pharo, c'est timeToRun.
C'est un message qu'on va envoyer à un block qui va nous
dire le temps d'exécution d'une expression.
Là par exemple sur factoriel 1 000, je veux mesurer le
temps d'exécution de factoriel 1 000, je le mets dans un
bloc et j'envoie le message timeTo Run.
Une fois qu'on a timeToRun, c'est très facile de comparer 2 exécutions.
Là, je vous propose un petit exercice qui est de dire
est-ce que si je fais un select suivi d'un collect, c'est
plus lent ou pas qu'un select puis collect.
Sachant que là, ça implique qu'il y aurait 2 passages
dans le premier cas et un passage dans le deuxième cas.
Je pense que ce sera plus lent mais on va le vérifier.
Je créé ma collection dans les 2 cas de figure avec 10
éléments, c'est une petite collection.
Je vais faire une
boucle pour pouvoir exécuter un certain nombre de fois les 2 expressions.
Ce que vous voyez, c'est que dans la première partie, là
j'ai ma collection et je dis que je veux sélectionner
tous les éléments qui sont plus grands que 5 et après,
ces éléments que j'aurais sélectionnés, je veux les élever au carré.
Et dans la deuxième expression, je vais dire que je veux
sélectionner ceux qui sont plus grands que 5 et les élever au carré.
On voit que le système me dit que là c'est 500
millisecondes et là c'est 368 millisecondes. Finalement,
il vaut mieux utiliser la deuxième expression.
Vous voyez un petit peu comment ça fonctionne.
Après, c'est à vous de le faire.
Ce qu'il faut voir, c'est qu'effectivement on doit
parfois mettre de très grandes boucles à l'intérieur pour
amplifier la mesure.
Il faut le faire dans les 2 cas pareil, évidemment.
Sinon, il y a un autre message qui s'appelle bench qui
va nous dire combien de fois le code,
qui est étudié, a été exécuté durant 5 secondes.
Là je reprends mon exemple factoriel 1 000, bench, là je
vois que je peux l'exécuter 110000 fois par seconde.
Dans ce cas de figure, ce qu'on veut c'est que le chiffre soit le plus haut.
Il y a une variante de bench qui s'appelle bench for où
vous pouvez spécifier la taille.
Là ce qui est sympa, c'est de voir que 2 secondes, c'est
vraiment le message secondes qui est envoyé au message 2,
ça va nous donner sûrement une duration, une instance de
la classe duration qui va contrôler combien de temps le
système va tourner.
Vous voyez, ça c'est encore une illustration que tout est
objet dans Pharo, donc spécifier les secondes, je fais 2
secondes, j'envoie le message secondes à l'objet 2.
Il y a aussi ce qu'on appelle un profiler qui est basé
sur des techniques de sample. Vous allez exécuter votre
programme et lui, il va aller à intervalles réguliers
inspecter la pile d'exécution et voir ce qui est sur
cette pile d'exécution et collecter l'information.
Comment est-ce qu'on l'invoque ?
On fait TimeProfiler, spyOn et on va lui passer un block.
Là je dis que je veux répéter 20 fois que je vais
afficher sur le Transcript factoriel 100 que je convertis
en chaîne, c'est ça qui coûte le plus cher en général.
Et après, le profiler va nous donner ce genre de
résultats avec un arbre qui va nous montrer les branches
parmi lesquelles on a passé le plus de temps.
Là par exemple, il nous montre qu'on a passé 63 % du
temps dans la méthode printOn by base.
C'est juste pour vous montrer que ça existe, il y a un
profiler comme ça, vous pouvez jouer avec si vous êtes intéressé.
En résumé, dans une première approche, vous pouvez
utiliser timeToRun, bench et le profiler, il y a un
chapitre dans le livre "Deep into Pharo" qui montre ce
genre de techniques d'optimisation.
Maintenant, je voulais juste faire une petite remarque.
C'est que vous voyez que dans ces 3 exemples à chaque
fois on utilise des blocks, ça veut dire que là ici c'est
un block, là aussi c'est un block.
Pourquoi? Parce que ce que vous avez vu dans le cours
sur les blocks, c'est que la définition du block
n'exécute pas et donne la possibilité à bench de
contrôler le nombre d'exécutions, ou de décider quand on
commence l'exécution du programme.
L'autre remarque que j'ai à vous faire, c'est soyez
curieux, allez voir comment timeToRun est implémenté et
comment bench est implémenté. Pour ça, vous n'avez qu'à
cliquer sur l'expression, et faire browse ou implementer
dessus et vous allez voir le code.