arthur.bebou

Le site arthur.bebou.netlib.re - retour accueil

git clone git://bebou.netlib.re/arthur.bebou
Log | Files | Refs |

index.sh (15183B)


      1 #! page
      2 
      3 title: Benchmark de Francium
      4 author: Arthur Pons
      5 publication: 2023-03-11
      6 description: Quelques statistiques sur le site de Katzele
      7 sectionmd: main
      8 
      9 # Benchmark et critique des performances de Francium
     10 
     11 ## Le benchmark
     12 
     13 J'ai eu l'idée d'écrire cette note en entendant parler d'11ty, un générateur de
     14 site statique. Il est écrit sur leur site
     15 
     16 > Fast Builds and even Faster Web Sites
     17 
     18 Et on trouve une petite animation qui présente qu'11ty construit 4000
     19 fichiers markdown en 2s, plus rapide que qu'Astro en 20 secondes, Gatbsy en 30
     20 secondes etc. Le site omet qu'Hugo est plus rapide mais soit.
     21 
     22 Ces résultats proviennent de [ce
     23 benchmark](https://github.com/zachleat/bench-framework-markdown).
     24 
     25 Et Francium ? Testons d'abord les performances de cmark et lowdown, les deux
     26 parseur de markdown qui nous utilisons. En prenant les 4000 fichiers markdown
     27 du benchmark et en lançant les commandes :
     28 
     29 	time find -name '*.md' | xargs -n1 -P0 sh -c 'lowdown "$1" > "$1".html' --
     30 	xargs -n1 -P0 sh -c 'lowdown "$1" > "$1".html' --  4,84s user 1,05s system 307% cpu **2,291** total
     31 
     32 et
     33 
     34 	time find -name '*.md' | xargs -n1 -P0 sh -c 'cmark "$1" > "$1".html' --
     35 	xargs -n1 -P0 sh -c 'lowdown "$1" > "$1".html' --  4,84s user 1,05s system 307% cpu **1,914** total
     36 
     37 On tombe sur des temps d'environ deux secondes. Je trouvais surprenant que ces
     38 deux logiciels, écrits en C et dont le seul but est de convertir du md en html
     39 ne soient pas plus rapides qu'Hugo. Marc m'a rappelé que cette commande fait un
     40 fork par fichier et les forks c'est "couteux".
     41 
     42 > Un fork c'est la création d'un nouveau processus par un autre. Nos commandes
     43 > seront un processus qui, pour chaque fichier en créera un nouveau pour faire
     44 > sa traduction. Créer un nouveau processus a un coût fixe. Il serait donc plus
     45 > performant de créer un minimum de processus qui gèrent un maximum de fichiers
     46 > chacun.
     47 
     48 En l'occurence cmark peut prendre plusieurs fichiers en argument, on peut donc
     49 écrire
     50 
     51 	time cmark *.md
     52 	cmark *.md  0,08s user 0,07s system 29% cpu 0,528 total
     53 
     54 ou pour lowdown tout concaténer
     55 
     56 	time cat *.md | lowdown
     57 	lowdown  0,15s user 0,07s system 32% cpu 0,689 total
     58 
     59 Dans les deux cas on s'économise le fait de devoir créer 4000 fichiers mais pas
     60 celui d'écrire les données pour les voir dans la console. D'ailleurs avec :
     61 
     62 	time cmark *.md /dev/null
     63 	cmark *.md > /dev/null 0,08s user 0,07s system 29% cpu 0,093 total
     64 
     65 on voit que la majorité du temps est passé à écrire le résultat.
     66 
     67 J'identifie avec le code suivant
     68 
     69 	for i in $(seq 1 4000)
     70 	do
     71 	echo $i > $i.txt
     72 	done
     73 	./test  0,03s user 0,17s system 99% cpu 0,199 total
     74 
     75 que cela prend un peu moins de 0,2 secondes de créer 4000 fichiers presque
     76 vides[^1] ce qui voudrait dire que l'on a la découpe approximative suivante :
     77 
     78 | opération | temps (s) |
     79 |---|---|
     80 |traiter les données|0,1|
     81 |créer les fichiers|0,2|
     82 |écrire les données|0,22|
     83 
     84 En réalité j'en sais rien, je connais pas assez bien linux pour savoir si je
     85 mesure les choses comme il faut. Prenez tout ça avec des pincettes.
     86 
     87 Quoi qu'il en soit nous apprenons de ce test que Francium ne pourra pas aller
     88 plus vite qu'environ une demie seconde pour 4000 fichiers. Pour en faire un
     89 benchmark assez équivalent j'ai retiré tous les alias de page, sauf %S et
     90 modifié les pages md du dépôt de benchmark pour qu'elles n'aient plus le 
     91 
     92 	---
     93 	title: blablabla
     94 	---
     95 
     96 et leur ajouter le shebang
     97 
     98 	#! page
     99 
    100 et les rendre exécutables.
    101 
    102 > J'ai fait ça avec
    103 > 
    104 > 		find -name '*.md' | xargs -n1 -P0 sed -i 's/^/#! page\n/;2,4d'
    105 > 		chmod 755 ./*
    106 
    107 J'ai vérifié au préalable, le titre n'est pas pris en compte dans le benchmark.
    108 Du moins l'HTML généré par Hugo et 11ty a une balise `<title>` vide.
    109 Une fois que tout est prêt on construit le site comme on le fait habituellement
    110 avec Francium[^2] (version qui utilise lowdown) :
    111 
    112 	time make -B -j
    113 	make -B -j  30,29s user 8,31s system 302% cpu **12,741** total
    114 
    115 On est donc sur du six fois plus lent que la simple conversion en HTML depuis
    116 lowdown. Tentons de comprendre pourquoi en bidouillant, faute de savoir comment
    117 correctement diagnostiquer ce genre de choses.
    118 
    119 Retirer les shebang et modifier le makefile pour faire
    120 
    121 	./page machin.md
    122 
    123 ne change rien en terme de performance.
    124 
    125 Supprimer l'appel à `install` en faisant directement une redirection semble
    126 économiser environ une seconde.
    127 
    128 Supprimer l'appel à page en demandant à makefile de directement utiliser
    129 lowdown et en supprimant les heredoc `%S` (en gros ce qu'on a fait au début
    130 mais avec l'overhead de make) fait tomber le temps d'exécution à 3,7 secondes.
    131 C'est donc quelque part dans page que l'on perd de la performance.
    132 
    133 J'ai ensuite repris depuis le début en supprimant la gestion des sections. Cela
    134 revient à s'économiser la création d'un dossier temporaire et d'un fichier
    135 temporaire[^3] par article. Ne plus créer le fichier temporaire qu'il faut
    136 ensuite relire pour insérer son contenu dans le layout fait gagner environ 2
    137 secondes, make ne prend plus qu'environ 9,5 secondes. Ne plus créer le dossier
    138 temporaire fait gagner 3 secondes supplémentaires pour descendre à 6,5 secondes
    139 environ.
    140 
    141 Il semblerait donc que notre façon de gérer le layout soit responsable de 3
    142 secondes d'overhead sur 4000 fichiers. Pour que la comparaison tienne à peu
    143 près la route j'ai modifié le template pour qu'il soit identique à celui généré
    144 par Hugo. Je m'arrête là dans l'exploration des performances de Francium.
    145 
    146 On en retient qu'à la louche et avec mes outils de diagnostiques très
    147 approximatifs, ce qui coûte est :
    148 
    149 | Modification | Temps (s)  |
    150 |---|---|
    151 | overhead make  | 1,7 |
    152 | la création du dossier temporaire  | 2  |
    153 | la création puis la lecture du fichier temporaire par section | 3 |
    154 | l'appel à install | 1 |
    155 | le template | 3 |
    156 
    157 Ce qui ajoutés bout à bout explique la différence entre les deux secondes de
    158 lowdown et les 12/13 de Francium.
    159 
    160 Résultats finaux :
    161 
    162 | Générateur | Temps (s) |
    163 |---|---|
    164 | Hugo | 1,6 |
    165 | 11ty | 2 |
    166 | Francium (sans sections) | 6 |
    167 | Francium | 12 |
    168 | Le reste | 20+ |
    169 
    170 ## Et alors ?
    171 
    172 Francium tel qu'il existe pour le site de Katzele est 6 fois plus lent que les
    173 deux générateurs de sites statiques les plus rapides et plus rapide que tous les
    174 autres. Dans une version allégée, pour un site avec une seule section que l'on
    175 souhaite alimenter de contenu il n'est "que" trois fois plus lent.
    176 
    177 C'est significatif mais à mettre au regard du temps d'ingénieurie investit. Il
    178 est probable que le temps passé à construire Francium dans son ensemble est un
    179 ou deux ou trois ordres de grandeur inférieur au temps passé à rendre Hugo et
    180 11ty performants.
    181 
    182 De plus la comparaison de performances de logiciels est compliquée et
    183 hasardeuse. Déjà parce que cela dépend du matériel sur lequel les logiciels
    184 sont testés. Ensuite parce que les couvertures fonctionnelles ne sont pas les
    185 mêmes. Nous avons vu que l'intégration de fonctionnalités supplémentaires dans
    186 Francium pouvait avoir un fort impact sur sa performance. Qu'en est-il des
    187 autres outils ? Hugo et 11ty font *beaucoup* plus de choses que Francium mais
    188 le benchmark leur fait générer un site aussi simple que gros. Au vu de leurs
    189 performances, ils ne semblent pas ralentir quand leurs très nombreuses
    190 fonctionnalités ne sont pas effectivement utilisées. Comment Hugo et 11ty
    191 réagiraient-ils si l'on construisait des sites plus complexes ? Et Francium ?
    192 En l'absence de réponse à ces questions les benchmarks ne veulent pas dire
    193 grand chose.
    194 
    195 Cela dit, pourquoi est-ce que ces logiciels font la promotion de leurs
    196 performances sur leurs pages d'accueil ? Au-delà d'une éventuelle volonté de
    197 savoir qui a ~~la plus gro~~ le plus rapide, possibilité à ne pas sous-estimer,
    198 on pourrait aller regarder du côté des générateurs historiques. On me racontait
    199 que fut une époque nombre de générateurs de sites étaient particulièrement
    200 "lents". Il fallait attendre possiblement plusieurs dizaines de secondes pour
    201 faire la revu de ses modifications ce qui rendait l'itération lente et le
    202 travail fastidieux. Pour résoudre ce souci il semblerait que les communautés
    203 autour de ces outils aient opté pour de l'ingénierie logicielle supplémentaire
    204 faisant appel à nos matériels informatiques modernes très puissants. "Cela
    205 prend 30 secondes de reconstruire tout le site pour vérifier le rendu de
    206 notre nouvelle page ? Optimisons le code pour que les opérations aillent plus
    207 vite et fassent usage de toute la puissance des processeurs pour le faire
    208 descendre à deux secondes".
    209 
    210 Ce qui est intéressant c'est qu'en puisant dans une autre culture informatique,
    211 comme la notre par exemple, ce n'est pas une autre solution qui aurait été
    212 choisie mais le problème qui n'aurait tout simplement existé - ou suffisamment
    213 rarement pour que ça n'en soit pas un.
    214 
    215 Illustrons cette idée en trois points :
    216 
    217 1. Dans le monde Unix le système de "build"[^4] traditionnel permet de ne
    218    reconstruire que le nécessaire.
    219 
    220 Le système utilisé pour compiler de nombreux programmes dans le monde Unix (et
    221 sur lequel Francium se base), make, utilise un graph de dépendance pour savoir
    222 ce qui doit être reconstruit et ce qui est encore à jour. Ainsi, si l'on
    223 modifie 10 fichiers markdown sur les 4000 il n'est nécessaire de reconstruire
    224 que 10 fichiers HTML. A moins d'avoir vraiment besoin de tout reconstruire,
    225 pour une raison technique ou parce que l'on a touché à quelque de chose de
    226 commun à tout le site (un template par exemple), la question du temps de
    227 génération de la totalité d'un si gros site est caduque. La variable
    228 qui influe sur la vitesse de construction est dorénavant la quantité de
    229 fichiers modifiés et non plus la quantité de fichiers au total.
    230 
    231 A noter que cet avantage n'est pas gratuit, les moteurs de production sont
    232 souvent des logiciels assez complexes. L'alternative à priori plus légère et
    233 maintenable à cmake et make serait
    234 [mk](https://doc.cat-v.org/plan_9/4th_edition/papers/mk).
    235 
    236 Si les personnes impliquées dans les communautés des générateurs de site
    237 statique avaient identifié des moteurs tels que make comme judicieux pour leurs
    238 besoins alors le problème ne ce serait probablement jamais posé.
    239 
    240 Dans la pratique une configuration parmi d'autres qui permettrait d'itérer
    241 rapidement serait d'avoir une fenêtre vim d'ouverte sur le fichier qui nous
    242 intéresse et depuis le dossier dans lequel le makefile se trouve, et une autre
    243 fenêtre avec l'aperçu du fichier html. Dans vim on met la configuration
    244 "autowrite" (aw de son petit nom) à vraie en faisant `set aw` et lorsque l'on
    245 veut vérifier nos modifs faire `:make!`. Suffit ensuite de rafraichir la page
    246 dans le navigateur.
    247 
    248 > autowrite permet d'indiquer à vim que vous voulez qu'il enregistre les
    249 > modifications apportées au lancement de tout un tas de commandes dont make.
    250 > Voir `:help autowrite` pour plus d'infos.
    251 
    252 Un petit map pour n'avoir à appuyer sur qu'un seul bouton dans vim :
    253 
    254 	map <F3>:set aw<CR>:make!<CR><CR>
    255 
    256 2. L'utilisation d'éditeurs de texte s'interfaçant bien avec le système permet
    257    de tester des bouts de markdown.
    258 
    259 Toujours en partant du principe que le besoin principal est d'obtenir un
    260 feedback rapide sur ce que l'on a écrit, un éditeur tel que vim permet d'y
    261 répondre sans jamais toucher à la génération du site.
    262 
    263 Exemple, on a un doute sur la syntaxe des liens (personnellement j'inverse
    264 souvent les () et les []), on écrit :
    265 
    266 	(un lien)[http://katzele.netlib.re]
    267 
    268 On teste si ça fonctionne en se mettant sur la ligne et en le filtrant avec
    269 lowdown - ou markdown ou pandoc ou... - en lançant `:.!lowdown` :
    270 
    271 	<p>(un lien)[<a href="http://katzele.netlib.re">http:&#47;&#47;katzele.netlib.re</a>]</p>
    272 
    273 Ah oui non c'est pas ça
    274 
    275 	[un lien](http://katzele.netlib.re)
    276 	<p><a href="http://katzele.netlib.re">un lien</a></p>
    277 
    278 mieux !
    279 
    280 Si l'on veut tester plusieurs lignes on peut faire une sélection visuelle sur
    281 plusieurs lignes ou remplacer `.` de la commande `:.!lowdown` par un autre range[^5].
    282 
    283 On peut aussi écrire un heredoc et le filtrer avec sh. En faisant `vip` puis `:!sh`
    284 (ce qui va écrire `:'<,'>!sh` dans la ligne de commande, les `'<>` étant les ranges
    285 du début jusqu'à la fin de la sélection visuelle) :
    286 
    287 	<<. lowdown
    288 	| Générateur | Temps (s) |
    289 	|---|
    290 	| Hugo | 1,6 |
    291 	| 11ty | 2 |
    292 	| Francium (sans sections) | 6 |
    293 	| Francium | 12 |
    294 	| Le reste | 20+ |
    295 	.
    296 
    297 et ça va donner
    298 
    299 	<p>| Générateur | Temps (s) |
    300 	|&#8212;|
    301 	| Hugo | 1,6 |
    302 	| 11ty | 2 |
    303 	| Francium (sans sections) | 6 |
    304 	| Francium | 12 |
    305 	| Le reste | 20+ |</p>
    306 
    307 Ce n'est pas un tableau, réessayons en ajoutant un colonne ligne 2 :
    308 
    309 	<<. lowdown
    310 	| Générateur | Temps (s) |
    311 	|---|---|
    312 	| Hugo | 1,6 |
    313 	| 11ty | 2 |
    314 	| Francium (sans sections) | 6 |
    315 	| Francium | 12 |
    316 	| Le reste | 20+ |
    317 	.
    318 
    319 et ça donne :
    320 
    321 	<table>
    322 	<thead>
    323 	<tr>
    324 	<th>Générateur</th>
    325 	<th>Temps (s)</th>
    326 	</tr>
    327 	</thead>
    328 	
    329 	<tbody>
    330 	<tr>
    331 	<td>Hugo</td>
    332 	<td>1,6</td>
    333 	</tr>
    334 	<tr>
    335 	<td>11ty</td>
    336 	<td>2</td>
    337 	</tr>
    338 	<tr>
    339 	<td>Francium (sans sections)</td>
    340 	<td>6</td>
    341 	</tr>
    342 	<tr>
    343 	<td>Francium</td>
    344 	<td>12</td>
    345 	</tr>
    346 	<tr>
    347 	<td>Le reste</td>
    348 	<td>20+</td>
    349 	</tr>
    350 	</tbody>
    351 	</table>
    352 
    353 Sauf que c'est difficile de dire à l'oeil nu si c'est juste. On peut le piper
    354 dans lynx et lui demander de dump le résultat dans vim pour voir ce que ça
    355 donne :
    356 
    357 	<<. lowdown | lynx -stdin --dump
    358 	| Générateur | Temps (s) |
    359 	|---|---|
    360 	| Hugo | 1,6 |
    361 	| 11ty | 2 |
    362 	| Francium (sans sections) | 6 |
    363 	| Francium | 12 |
    364 	| Le reste | 20+ |
    365 	.
    366 	
    367 			  Générateur        Temps (s)
    368 	   Hugo                     1,6
    369 	   11ty                     2
    370 	   Francium (sans sections) 6
    371 	   Francium                 12
    372 	   Le reste                 20+
    373 
    374 Nickel.
    375 
    376 J'imagine qu'il y a pleins d'autres façons d'obtenir du feedback, que ce soit
    377 avec vim ou d'autres outils. Vous pouvez écrire au collectif si vous voulez
    378 les partager. Ou mieux encore, écrire sur la liste linux du lug.
    379 
    380 ## Mot de la fin
    381 
    382 Le but de l'article est de mettre en lumière que pour une situation donnée des
    383 cultures informatiques différentes peuvent mener à des lectures radicalement
    384 différentes. Ce qui est un problème pour un groupe n'en est pas un pour un
    385 autre. Ce qui doit donc être produit pour y remédier par le premier n'a pas à
    386 l'être pour l'autre. Ce n'est pas sans conséquence.
    387 
    388 Problème ou pas, une autre façon de le voir serait de prendre le problème à
    389 l'envers. Plutôt que d'estimer qu'un temps de construction "long" pour un gros
    390 site est un problème d'optimisation logiciel, on pourrait estimer que lorsque
    391 le temps de construction du site est perçu comme "long" c'est que le site est
    392 trop gros.
    393 
    394 [^1]: Peut-être que ça a un gros impact qu'ils ne le soient pas d'ailleurs, je ne sais pas
    395 [^2]: Nous utiliserons lowdown à partir d'ici
    396 [^3]: Un seul puisque les fichiers markdown du benchmark n'ont pas de "section". Tout va donc au même endroit dans le layout et un seul fichier de section a besoin d'être créé
    397 [^4]: moteur de production en bon français semble-t-il
    398 [^5]: `.` est le range qui veut dire "la ligne sous le curseur". Voir `:help range` pour plus d'infos