2023-09-22 13:33:14 +00:00
|
|
|
|
# Les performances en Python
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
par
|
|
|
|
|
|
2023-06-15 12:42:33 +00:00
|
|
|
|
<!-- .slide: data-background="static/background.jpg" -->
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
Julien Palard <julien@palard.fr>
|
|
|
|
|
|
|
|
|
|
https://mdk.fr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Bien choisir sa structure de donnée
|
|
|
|
|
|
|
|
|
|
C'est bien choisir l'algorihtme qu'on va utiliser.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Comparaison asymptotique
|
|
|
|
|
|
2022-09-15 14:16:10 +00:00
|
|
|
|
Les notations les plus utilisées :
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
O(1) Constant
|
2022-09-15 14:16:10 +00:00
|
|
|
|
O(log n) Logarithmique
|
2022-06-23 14:10:37 +00:00
|
|
|
|
O(n) Linéaire
|
2022-09-15 14:16:10 +00:00
|
|
|
|
O(n log n) Parfois appelée « linéarithmique »
|
2022-06-23 14:10:37 +00:00
|
|
|
|
O(n²) Quadratique
|
|
|
|
|
O(nᶜ) Polynomiale
|
|
|
|
|
O(cⁿ) Exponentielle
|
|
|
|
|
O(n!) Factorielle
|
|
|
|
|
```
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
Il faut les grapher pour s'en rendre compte : cf. examples/big.o.py
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2022-09-15 14:16:10 +00:00
|
|
|
|
## Comparaison asymptotique
|
|
|
|
|
|
|
|
|
|
Exemples.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## O(1)
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def get_item(a_list: list, an_idx):
|
|
|
|
|
return a_list[an_idx]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
ou
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
def is_in(a_set: set, a_value):
|
|
|
|
|
return a_value in a_set
|
|
|
|
|
```
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
|
|
|
|
Peu importe la taille de la liste, accéder à un élément prend le même temps.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## O(log n)
|
|
|
|
|
|
|
|
|
|
Attention c'est toujours en base deux.
|
|
|
|
|
|
|
|
|
|
Exemple typique : chercher dans un annuaire.
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
|
|
|
|
Un annuaire deux fois plus gros ne vous demandera pas deux fois plus
|
|
|
|
|
de temps mais peut-être une opération de plus.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## O(log n)
|
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '/def index/,/raise ValueError/p' examples/find_in_list.py
|
2022-09-15 14:16:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## O(n)
|
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '/def dumb_index/,/raise ValueError/p' examples/find_in_list.py
|
2022-09-15 14:16:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## O(n log n)
|
|
|
|
|
|
|
|
|
|
C'est `n` fois un `log n`, par exemple rayer `n` personnes dans un annuaire.
|
|
|
|
|
|
|
|
|
|
Typique d'algorithmes de tris.
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
## Les mesures de complexité
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
- De temps (CPU consommé).
|
2023-09-22 13:33:14 +00:00
|
|
|
|
- D'espace (mémoire consommée).
|
2023-06-22 09:50:58 +00:00
|
|
|
|
- Dans le meilleur des cas.
|
|
|
|
|
- Dans le pire des cas.
|
|
|
|
|
- Dans le cas moyen.
|
|
|
|
|
- Amorti.
|
2022-06-23 14:10:37 +00:00
|
|
|
|
- ...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Les mesures de complexité
|
|
|
|
|
|
|
|
|
|
Il n'est pas forcément nécessaire d'apprendre par cœur toutes les complexités de chaque opération.
|
|
|
|
|
|
|
|
|
|
Pas toute suite.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Les bases
|
|
|
|
|
|
|
|
|
|
Mais retenir par cœur la complexité de quelques structures
|
|
|
|
|
élémentaires permet d'éviter les « erreurs de débutants ».
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Rappel des unités de temps
|
|
|
|
|
|
|
|
|
|
- 1 milliseconde (1 ms) c'est un millième de seconde.
|
|
|
|
|
- 1 microseconde (1 μs) c'est un millionième de seconde.
|
|
|
|
|
- 1 nanoseconde (1 ns) c'est un milliardième de seconde.
|
|
|
|
|
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
## Rappel des unités de temps
|
|
|
|
|
|
|
|
|
|
- milli c'est `10 ** -3`, c'est `0.001`.
|
|
|
|
|
- micro c'est `10 ** -6`, c'est `0.000_001`.
|
|
|
|
|
- nano c'est `10 ** -9`, c'est `0.000_000_001`.
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
## Le cas typique
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
```shell
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cache python -m pyperf timeit --setup 'container = list(range(10_000_000))' '10_000_001 in container'
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cache python -m pyperf timeit --setup 'container = set(range(10_000_000))' '10_000_001 in container'
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Pourquoi une si grande différence !?
|
|
|
|
|
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
C'est l'heure du live coding !
|
|
|
|
|
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
# À vous !
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Simulez un tas de sable, moi je calcule le nombre l'or.
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
|
|
|
|
Ne vous souciez pas des perfs, on s'en occupera.
|
|
|
|
|
|
|
|
|
|
notes:
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Leur laisser ~15mn.
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
voir sandpile.py
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
# Les outils
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Je mesure mes perfs, puis ils mesurent leurs perfs.
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## `pyperf command`
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf command python examples/phi1.py 3
|
|
|
|
|
|
|
|
|
|
#!cache pyperf command python examples/phi1.py 6
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf command python examples/phi1.py 9
|
|
|
|
|
```
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
## Petite parenthèse
|
|
|
|
|
|
|
|
|
|
Mais attention, démarrer un processus Python n'est pas gratuit :
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf command python -c pass
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
|
|
|
|
N'essayez pas de retenir les chiffres, retenez les faits.
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
## Petite parenthèse
|
|
|
|
|
|
|
|
|
|
Et puis il peut dépendre de la version de Python, des options de compilation, ... :
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
$ pyperf command ~/.local/bin/python3.10 -c pass
|
|
|
|
|
.....................
|
|
|
|
|
command: Mean +- std dev: 37.6 ms +- 0.6 ms
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
$ pyperf command /usr/bin/python3.10 -c pass
|
|
|
|
|
.....................
|
|
|
|
|
command: Mean +- std dev: 14.4 ms +- 0.4 ms
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
Leur parler de `--enable-optimizations` (PGO).
|
|
|
|
|
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## `pyperf timeit`
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Il existe aussi `timeit` dans la stdlib, mais je préfère `pyperf timeit` :
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.phi1 import approx_phi_up_to' 'approx_phi_up_to(3)'
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## Les outils — À vous !
|
|
|
|
|
|
|
|
|
|
Effectuez quelques mesures sur votre implémentation.
|
|
|
|
|
|
|
|
|
|
Tentez d'en déterminer la complexité en fonction du nombre de grains.
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Explorez les limites de vos implémentations.
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
# Profilage
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
`pyperf` c'est bien pour mesurer, comparer.
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Le profilage peut nous aider à trouver la fonction coupable.
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '/def fib/,/return approx/p' examples/phi1.py
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
|
|
|
|
Sortons cProfile :
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
2022-06-29 21:26:20 +00:00
|
|
|
|
$ python -m cProfile --sort cumulative phi1.py 10
|
2022-09-15 14:16:10 +00:00
|
|
|
|
...
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cache python -m cProfile --sort cumulative examples/phi1.py 10 | sed -n '/fib\|function calls/{s/ \+/ /g;s/^ *//;p}'
|
2022-06-29 21:26:20 +00:00
|
|
|
|
...
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
C'est donc `fib` la coupable :
|
|
|
|
|
- C'est ~100% du temps (`cumtime`).
|
|
|
|
|
- C'est ~100% des appels de fonctions.
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
Cachons les résultats de `fib` :
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '/import cache/,/return fib/p' examples/phi2.py
|
2022-06-29 21:26:20 +00:00
|
|
|
|
```
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
Et on repasse dans cProfile !
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
2022-06-29 21:26:20 +00:00
|
|
|
|
$ python -m cProfile --sort cumulative phi2.py 10
|
2023-09-22 13:33:14 +00:00
|
|
|
|
...
|
|
|
|
|
#!cache python -m cProfile --sort cumulative examples/phi2.py 10 | sed -n '/fib\|function calls/{s/ \+/ /g;s/^ *//;p}'
|
|
|
|
|
...
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
C'est mieux !
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
On essaye d'aller plus loin ?
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
|
|
|
|
#!cache python -m cProfile --sort cumulative examples/phi2.py 2000 | head -n 3 | sed 's/^ *//g;s/seconds/s/g'
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
Ça tient, mais peut-on faire mieux ?
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
Divisons par 10 le nombre d'appels, on réduira mécaniquement par 10 le
|
|
|
|
|
temps d'exécution ?
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '/def approx_phi_up_to/,/return step1/p' examples/phi3.py
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
|
|
|
|
#!cache python -m cProfile --sort cumulative examples/phi3.py 2000 | head -n 3 | sed 's/^ *//g;s/seconds/s/g'
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
En cachant `approx_phi` ?
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '10,/return step1/p' examples/phi4.py
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
Notez l'astuce pour que le `step2` d'un
|
|
|
|
|
tour soit le `step1` du suivant...
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
## cProfile, exemple
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
|
|
|
|
$ python -m cProfile --sort cumulative examples/phi4.py 2000
|
2022-09-15 14:16:10 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
`RecursionError` !? En effet, en avançant par si grands pas, le cache
|
|
|
|
|
de `fib` n'est pas chaud, et il peut vite devoir descendre
|
|
|
|
|
profondément en récursion...
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
|
|
|
|
Il est temps de sortir une implémentation de `fib` plus robuste, basée
|
|
|
|
|
sur l'algorithme « matrix exponentiation » :
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!sed -n '/def fib/,/return fib/p' examples/phi5.py
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## cProfile, exemple
|
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
```text
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cache python -m cProfile --sort cumulative examples/phi5.py 2000 | head -n 3 | sed 's/^ *//g;s/seconds/s/g'
|
2022-06-23 14:10:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
notes:
|
2022-06-29 21:26:20 +00:00
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
Mieux.
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
## Snakeviz
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
```shell
|
|
|
|
|
$ python -m pip install snakeviz
|
|
|
|
|
$ python -m cProfile -o phi5.prof phi5.py 2000
|
|
|
|
|
$ python -m snakeviz phi5.prof
|
2022-06-29 21:26:20 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!if [ ! -f .cache/phi5.prof ]; then python -m cProfile -o .cache/phi5.prof examples/phi5.py 2000 >/dev/null 2>&1; fi
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!if [ ! -f output/phi5-snakeviz.png ]; then python -m snakeviz -s .cache/phi5.prof & TOKILL=$!; sleep 1; cutycapt --min-width=1024 --delay=500 --url=file://$(pwd)/.cache/phi5.prof --out=output/phi5-snakeviz.png ; kill $TOKILL; fi
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2022-06-29 21:26:20 +00:00
|
|
|
|
## Snakeviz
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
2022-09-15 14:16:10 +00:00
|
|
|
|
![](phi5-snakeviz.png)
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2022-09-15 14:16:10 +00:00
|
|
|
|
## Scalene
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
```shell
|
2022-09-15 14:16:10 +00:00
|
|
|
|
$ python -m pip install scalene
|
|
|
|
|
$ scalene phi5.py 100000
|
|
|
|
|
```
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!if [ ! -f output/phi5.html ]; then ( cd examples; scalene phi5.py 100000 --html --outfile ../output/phi5.html --cli >&2 ); fi
|
|
|
|
|
#!if [ ! -f output/phi5-scalene.png ]; then cutycapt --min-width=1024 --delay=100 --url=file://$(pwd)/output/phi5.html --out=output/phi5-scalene.png; fi
|
|
|
|
|
|
|
|
|
|
|
2022-09-15 14:16:10 +00:00
|
|
|
|
## Scalene
|
|
|
|
|
|
|
|
|
|
![](phi5-scalene.png)
|
|
|
|
|
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## line_profiler
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
$ python -m pip install line_profiler
|
|
|
|
|
#!cache python -m kernprof --view --prof-mod examples/phi5.py --line-by-line examples/phi5.py 100000
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## Aussi
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
- https://github.com/gaogaotiantian/viztracer
|
|
|
|
|
- https://github.com/joerick/pyinstrument
|
|
|
|
|
- https://github.com/benfred/py-spy
|
|
|
|
|
- https://github.com/sumerc/yappi
|
|
|
|
|
- https://github.com/vmprof/vmprof-python
|
|
|
|
|
- https://github.com/bloomberg/memray
|
2023-10-09 12:09:02 +00:00
|
|
|
|
- https://github.com/pythonprofilers/memory_profiler
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## Profilage — À vous !
|
2022-06-29 21:26:20 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
Profilez votre implémentation et tentez quelques améliorations.
|
2022-09-15 14:16:10 +00:00
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
|
|
|
|
|
# Cython
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
Cython est un dialecte de Python transpilable en C.
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
## Cython démo
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Sans modifier le code :
|
|
|
|
|
|
2023-06-22 09:50:58 +00:00
|
|
|
|
```python
|
2023-10-09 12:09:02 +00:00
|
|
|
|
$ pip install cython
|
|
|
|
|
$ cythonize --inplace examples/phi5cython.py
|
|
|
|
|
#!cythonize --inplace examples/phi5cython.py
|
2023-06-22 09:50:58 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Cython démo
|
|
|
|
|
|
|
|
|
|
```
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.phi5 import approx_phi_up_to' 'approx_phi_up_to(100_000)'
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.phi5cython import approx_phi_up_to' 'approx_phi_up_to(100_000)'
|
2023-06-22 09:50:58 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## Cython démo
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
En annotant le fichier on permet à cython d'utiliser des types natifs.
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
Et ainsi réduire les aller-retour coûteux entre le C et Python.
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## Cython annotate
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache cython --annotate examples/phi5cython.py
|
|
|
|
|
#!if ! [ -f output/phi5cython.png ] ; then cutycapt --min-width=1024 --delay=500 --url=file://$(pwd)/examples/phi5cython.html --out=output/phi5cython.png; fi
|
2023-06-22 09:50:58 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
![](phi5cython.png)
|
2023-06-22 09:50:58 +00:00
|
|
|
|
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## Cython — À vous !
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
# Numba
|
|
|
|
|
|
2023-06-22 09:57:41 +00:00
|
|
|
|
Numba est un `JIT` : « Just In Time compiler ».
|
|
|
|
|
|
|
|
|
|
```python
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cat examples/collatz_length_numba.py
|
2023-06-22 09:57:41 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Numba démo
|
|
|
|
|
|
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length_numba import collatz_length' 'collatz_length(837799)'
|
2023-06-22 09:57:41 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## numba — À vous !
|
|
|
|
|
|
|
|
|
|
|
2023-10-09 21:11:27 +00:00
|
|
|
|
# pypy
|
|
|
|
|
|
|
|
|
|
pypy est un interpréteur Python écrit en Python.
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
|
|
|
|
#!cache pypy3 -m pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
```
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
# mypyc
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
mypyc est un compilateur qui s'appuie sur les annotationes de type mypy :
|
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cat examples/collatz_length_mypy.py
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## mypyc demo
|
|
|
|
|
|
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
$ pip install mypy
|
|
|
|
|
#!cd examples; mypyc collatz_length_mypy.py
|
|
|
|
|
$ mypyc collatz_length_mypy.py
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
|
|
|
|
|
## mypyc demo
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length_mypy import collatz_length' 'collatz_length(837799)' 2>/dev/null
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## mypyc — À vous !
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
# Pythran
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
pythran est un compilateur pour du code scientifique :
|
|
|
|
|
|
|
|
|
|
```python
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cat examples/collatz_length_pythran.py
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Pythran demo
|
|
|
|
|
|
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
$ pip install pythran
|
2023-09-22 13:33:14 +00:00
|
|
|
|
$ pythran examples/collatz_length_pythran.py
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!if ! [ -f examples/collatz_length_pythran.*.so ]; then cd examples; pythran collatz_length_pythran.py; fi
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
|
|
|
|
|
## Pythran demo
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length_pythran import collatz_length' 'collatz_length(837799)'
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
## pythran — À vous !
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
|
2022-09-23 13:05:20 +00:00
|
|
|
|
# Nuitka
|
|
|
|
|
|
2023-06-22 10:37:49 +00:00
|
|
|
|
Aussi un compilateur, aussi utilisable pour distribuer une application.
|
|
|
|
|
|
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
$ pip install nuitka
|
2023-06-22 10:37:49 +00:00
|
|
|
|
$ python -m nuitka --module collatz_length_nuitka.py
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!if ! [ -f examples/collatz_length_nuitka.*.so ]; then (cd examples/; python -m nuitka --module collatz_length_nuitka.py >/dev/null); fi
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
2023-10-09 21:11:27 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length_nuitka import collatz_length' 'collatz_length(837799)'
|
2023-06-22 10:37:49 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
2022-06-23 14:10:37 +00:00
|
|
|
|
# Hand crafted C
|
2023-06-23 08:54:12 +00:00
|
|
|
|
|
|
|
|
|
```c
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!sed -n '/int collatz_length/,$p' examples/my_collatz_length.c
|
2023-06-23 08:54:12 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Mais comment l'utiliser ?
|
|
|
|
|
|
2023-09-22 13:33:14 +00:00
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## Avec Cython
|
2023-06-23 08:54:12 +00:00
|
|
|
|
|
|
|
|
|
```cpython
|
2023-09-22 13:33:14 +00:00
|
|
|
|
#!cat examples/collatz_length_cython_to_c.pyx
|
2023-06-23 08:54:12 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```shell
|
2023-09-22 13:33:14 +00:00
|
|
|
|
$ cythonize -i examples/collatz_length_cython_to_c.pyx
|
|
|
|
|
#!if ! [ -f examples/collatz_length_cython_to_c.*.so ] ; then cythonize -i examples/collatz_length_cython_to_c.pyx; fi
|
2023-06-23 08:54:12 +00:00
|
|
|
|
```
|
|
|
|
|
|
2023-10-09 12:09:02 +00:00
|
|
|
|
## Avec Cython
|
|
|
|
|
|
2023-06-23 08:54:12 +00:00
|
|
|
|
```shell
|
2023-10-09 12:09:02 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length_cython_to_c import collatz_length' 'collatz_length(837799)'
|
2023-06-23 08:54:12 +00:00
|
|
|
|
```
|
2023-10-09 12:09:02 +00:00
|
|
|
|
|
|
|
|
|
|
2023-10-09 14:00:49 +00:00
|
|
|
|
# Hand crafted rust
|
2023-10-09 12:09:02 +00:00
|
|
|
|
|
2023-10-09 14:00:49 +00:00
|
|
|
|
```rust
|
|
|
|
|
#!sed -n '/pyfunction/,$p' examples/collatz_length_rs.rs
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## with rustimport
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
$ pip install rustimport
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## with rustimport
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
#!cache pyperf timeit --setup 'from examples.collatz_length import collatz_length' 'collatz_length(837799)'
|
|
|
|
|
|
2023-10-09 21:11:27 +00:00
|
|
|
|
#!cache pyperf timeit --setup 'import rustimport.import_hook; import rustimport.settings; rustimport.settings.compile_release_binaries = True; from examples.collatz_length_rs import collatz_length' 'collatz_length(837799)'
|
2023-10-09 14:00:49 +00:00
|
|
|
|
```
|