tag:blogger.com,1999:blog-9497065884978318522024-03-14T11:09:19.773+01:00L'Aube des HérosM87http://www.blogger.com/profile/01230411662211999500noreply@blogger.comBlogger685125tag:blogger.com,1999:blog-949706588497831852.post-43955371555031897232024-03-09T10:32:00.000+01:002024-03-09T10:32:07.747+01:00C++ : Chercher un fichier dans un répertoire - Partie 2<p>Et on continue à creuser ! Malheureusement, même avec une recherche récursive écrite en libc, cela prend encore trop de temps sur le système cible. En effet, il s'agit d'un système de fichiers un peu particulier, qui est censé monter en charge très fort mais dont les accès aux métadonnées sont individuellement plutôt lents. Et je ne peux pas échapper au besoin de devoir indexer un système de répertoires contenant environ 100 000 fichiers.</p>
<p>Le système de fichiers veut un accès concurrent ? On va lui en donner un. Malheureusement, ce n'est pas si simple ! En effet, il faut créer un algorithme à la fois récursif et parallèle, ce qui est un nid à problèmes. Pour l'instant, j'entrevois une solution qui consisterait à construire une liste des répertoires non visités, les visiter de manière parallèle pour aller chercher à chaque fois le prochain niveau, et continuer tant qu'on trouve. Le fait de gérer les tâches à partir du thread principal simpilife beaucoup de choses, mais empêche un très bon parallelisme.</p>
<p>Quelle tuile.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-64350525856827305592024-02-21T00:11:00.001+01:002024-02-21T00:11:36.138+01:00C++ : Chercher un fichier dans un répertoire<p>Petite séance d'optimisation aujourd'hui, où nous tentions d'améliorer une routine qui cherche des fichiers dans un répertoire.</p>
<p>En bon dev C++, nous sommes allés chercher ce bon vieux <code>std::filesystem::path</code> et ce non moins bon vieux <code>std::filesystem::recursive_directory_iterator</code>. Sauf que ça prend des plombes. Mais vraiment. Sur un système de fichiers distant (NFS) et un répertoire de 5000 fichiers pas accédé depuis quelques temps, cela peut monter à des dizaines de secondes. Mais que se passe-t-il ?</p>
<p>Avant de se lancer dans de complexes manipulations avec <code>vtune</code> ou encore <code>gprof</code>, <code>pstack</code> nous indique que l'on passe beaucoup de temps dans l'appel à <code>stat</code>. En effet, <code>std::filesystem::recursive_directory_iterator</code> nous donne un <code>std::filesystem::directory_entry</code> qui contient tout un tas d'infos tout à fait intéressantes, mais qui sont chères à récupérer...</p>
<p>Alors que peut-on faire ?</p>
<p>Eh bien, revenir aux bases, et à cette bonne vieille libc, qui contient l'appel <code>readdir</code>, lequel justement ne récupère pas d'informations sur le fichier autre que son type (ce qui est pratique pour explorer récursivement un répertoire). Et n'oublions pas non plus <code>glob</code>, lequel est justement conçu pour aller chercher un fichier efficacement à partir d'un motif.</p>
<p>Testons, alors. Et sur notre répertoire de 5000 fichiers, cela donne maintenant:</p>
<pre>
filesystem 40s
readdir 30ms
glob 3ms
</pre>
<p>Glob est donc plus de 10000 fois plus rapide qu'une recherche manuelle !</p>
<p>Conclusion : méfiance, donc ! Malgré ses qualités, <code>std::filesystem::path</code> peut coûter très cher, et revenir à des appels plus bas niveau est parfois salutaire.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-83755319430137307622024-02-09T00:44:00.004+01:002024-02-09T00:44:44.995+01:00Unity3D<p>Je m'initie aux joies d'Unity3D, et je trouve l'outil particulièrement bien fichu. Le fait qu'il soit aisé de trouver tout un tas de docs et de tutoriels vidéos aide aussi, bien sûr. Histoire de tenter de comprendre le bousin, j'ai modélisé une voiture, puis je l'ai importée et utilisé le moteur physique pour la faire se déplacer. Grâce au modèle de roue très complet comprenant les amortisseurs et la puissance, il suffit d'un petit peu de plomberie pour faire quelque chose de plutôt impressionnant.</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJZhaYglSSRj1kmdCepo3bUQSPPWYLzp56zQlyyXTYAttzy9qOoJAcA6kMsHB2Z1D_O054nil0bFIlSv18ON7fmeHcE-cBHCago9oMPBL7I9rhpG5-46fIlkWhfQQqCnLYX5rJd1waFupKVbNXjB2PJlF3zy5RN48vCoOE5aJnVRtaNQEGf1TKw7O6_FI/s1850/unity3d.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1053" data-original-width="1850" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJZhaYglSSRj1kmdCepo3bUQSPPWYLzp56zQlyyXTYAttzy9qOoJAcA6kMsHB2Z1D_O054nil0bFIlSv18ON7fmeHcE-cBHCago9oMPBL7I9rhpG5-46fIlkWhfQQqCnLYX5rJd1waFupKVbNXjB2PJlF3zy5RN48vCoOE5aJnVRtaNQEGf1TKw7O6_FI/s320/unity3d.png"/></a></div>
<p>Voici donc une sorte de jeep, ainsi qu'une boule que j'ai utilisée pour m'entraîner à importer des matériaux complexes depuis Blender. Et que ça marche bien ! Prochaine étape : ajouter obstacles et plans inclinés pour faire bondir la bagnole.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-65634108586764535482024-01-23T23:20:00.001+01:002024-01-23T23:20:31.017+01:00X-Plane en stream sur la télé<p>Eh bien ça marche ! Je ne sais pas trop ce qui a fait la différence, mais avec un Raspberry Pi réinstallé de neuf, et une reconfiguration complète des options dans Steam Remote, j'ai un X-Plane stable (une fois le chargement complété, j'ai quand même eu 2 déconnexions avant). Les commandes au pad sont moins chiadées qu'avec le hotas, mais sur grand écran, c'est très, très agréable. Je m'en suis mis plein les yeux.</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAhIg8PyDZpWx9WpTQLvLiWvDRAEO41GzmAHu_BSLwZEusy5HDL5JezHipAWHw3HqUpJqQ0lFCpalPNrWseBhCB3pd_xx1s4KNHoR9wUc-mRaVFeZl1Bp0413LwNNIYxYOm58GoFAjmcI5eExARrMQDjrSl0FxypE-DaBBz2uWTws1GWr22hEKFZ5QUp8/s4032/xplane_steam_remote.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="3024" data-original-width="4032" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAhIg8PyDZpWx9WpTQLvLiWvDRAEO41GzmAHu_BSLwZEusy5HDL5JezHipAWHw3HqUpJqQ0lFCpalPNrWseBhCB3pd_xx1s4KNHoR9wUc-mRaVFeZl1Bp0413LwNNIYxYOm58GoFAjmcI5eExARrMQDjrSl0FxypE-DaBBz2uWTws1GWr22hEKFZ5QUp8/s320/xplane_steam_remote.jpg"/></a></div>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-52585429712747939672024-01-21T23:36:00.003+01:002024-01-21T23:36:32.197+01:00Steam remote et Raspberry Pi<p>Ayant découvert la fonctionnalité "Remote Play" de Steam, je tente de bidouiller pour le faire fonctionner depuis ma tour jusqu'à ma télé avec un Raspberry Pi. Et le résultat est, heu, particulier.</p>
<p>Tout d'abord, c'est déjà hyper impressionnant que ça fonctionne tout court, et sans trop se casser le bol : la partie serveur de Steam Remote fonctionne toute seule, et le steamplay sur Raspberry Pi s'installe très facilement. Une fois qu'on a compris qu'il fallait faire un Ctrl-Alt-F1 pour aller dans le framebuffer et démarrer le client depuis là, c'est plutôt tranquille. Ensuite, le serveur est détecté, les périphériques aussi, bref, magie.</p>
<p>Cependentant, j'ai encore 1 souci : autant sur le même switch, la connection est tout à fait stable, en passant par le deuxième switch près de la télé, j'ai des coupures toutes les 3 minutes : le client quitte brutalement la session, et je dois me reconnecter.</p>
<p>Alors, que se passe-t-il ? La seule idée que j'ai, c'est que le switch de la télé est en 1Gb/s, alors que le switch près de la tour est en 100Mb/s. Est-ce que ça cause des pertes sur certains types de paquet ? Peut-être de l'UDP ?</p>
<p>Au vu du prix des switchs de nos jours, j'ai bien envie de simplement mettre à jour mon antiquité (25 ans d'âge tout de même !) et voir ce que ça donne.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-81296067854512469042024-01-21T15:48:00.003+01:002024-01-21T15:48:28.734+01:00Bonne année ! <p>Permettez moi de souhaiter à mes nombreux lecteurs une excellente année 2024 !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-21354538979181541432023-12-17T15:45:00.001+01:002023-12-17T15:45:21.532+01:00Pentiment<p>Que voici une belle claque vidéoludique. J'avais vu passer Pentiment sur <a href="https://www.canardpc.com/jeu-video/test-jeu-video/pentiment-3/">CanardPC</a>, et je l'avais gardé dans un coin de ma mémoire, jusqu'à ce que je voie qu'il était disponible sur le XBox GamePass. Ni une, ni deux, je l'installe, je l'essaie, et je suis scotché.</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhnqqQ3lOB5vfISsibEEbwwJiTqJL5bBO65HIzARAUeQn2Toe4-PFkpDTL8-ZueKY1KSj_zKMiJ4YKP0-33WceZCap5Oe6wtqx9YzSQv4w4dJQNL-XDN9Tdvw0r4JTKEGa_RLED5xFpN6tjml12Wn1w2GGtDl6oQB3QzA1smrKBvgbUH5_SDRgmHl3q8g/s1229/pentiment.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="691" data-original-width="1229" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhnqqQ3lOB5vfISsibEEbwwJiTqJL5bBO65HIzARAUeQn2Toe4-PFkpDTL8-ZueKY1KSj_zKMiJ4YKP0-33WceZCap5Oe6wtqx9YzSQv4w4dJQNL-XDN9Tdvw0r4JTKEGa_RLED5xFpN6tjml12Wn1w2GGtDl6oQB3QzA1smrKBvgbUH5_SDRgmHl3q8g/s320/pentiment.jpg"/></a></div>
<p>Pentiment est un jeu d'enquête qui se passe dans un village de Bavière au XVIème siècle, dans lequel on incarne l'artiste Andreas, qui se retrouve malgré lui au milieu d'une affaire criminelle qu'il devra tenter de résoudre.</p>
<p>Tout d'abord, c'est graphiquement que c'est magnifique. Un jeu entier dans le style des enluminures du Moyen-Âge, avec exploration d'une abbaye, d'un village, de ruines romaines, le tout entrecoupé de séquences oniriques plutôt émouvantes, ça fait quelque chose. Ensuite, l'histoire est prenante : il y a le mystère, la vie difficile des différents protagonistes, et et l'impression constante que l'on est en train de faire des erreurs et de condamner des innocents. Cet impact constant sur l'histoire est ce qui fait le charme du jeu : l'on doit en permanence faire des choix qui vont changer, pour le meilleur et pour le pire, le destin des habitants du lieu. C'est aussi assez frustrant lorsque l'on a l'impression de rater étape après étape, mais cela fait partie du jeu : il n'est pas possible de reprendre à un point précédent de l'histoire, et nous sommes donc condamnés à vivre avec les conséquences de nos décisions.</p>
<p>Il y a probablement un potentiel de rejouabilité, pour découvrir tous les chemins possibles, tenter de sauver un personnage et d'en condamner un autre, ou explorer certaines scènes que l'on a raté. En effet, limité par le temps, il n'est juste pas possible de tout voir en une seule partie. Cependant, il y aura nécessairement des redondances, et pour ma part, une seule session sera suffisante !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-71788866075566255282023-12-17T15:24:00.002+01:002023-12-17T15:24:57.593+01:00Et Novembre ?<p>Rien publié en Novembre ! Ça alors. Qu'ais-je donc fait ? J'ai joué à <a href="https://fr.wikipedia.org/wiki/Pentiment">Pentiment</a>, dont il faudra que je vous en dise plus. J'ai fait un peu plus de X-Plane 12, en particulier sur le sympathique <a href="https://aerobask.com/phenom300.php">Phenom 300</a> d'Aerobask. Du côté du C++, je m'attelle à une grosse conversion vers GCC 13, qui va me permettre d'utiliser std::format et std::date à la place de fmt::format et date. En attendant, préparons Noël !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-91905035744566514312023-10-29T11:16:00.001+01:002023-10-29T11:16:04.887+01:00Lego nous gâte<p>Quand on pensait qu'ils ne pouvaient pas faire mieux, Lego continue de faire plaisir aux space geeks. On connaissait la Saturn V et la navette spatiale américaine, voici maintenant le rover martien Perseverance que j'ai découvert dans une vitrine récemment, avec son drone. Belle bête !</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu5v4enBanlS6L4TkNh55xAdur_HeHKUBc30MM0VupZti0iBNkOzGiSZZncXnmoifNBe3SXr31d3lQIC6SsYCtEGPj1vDKjim4yntdGHB96GYZaNLLmmeENDJ-P581-HXN7_3xVWL0AYqapYVAqpbgbttz4Nze1bIK4rKuLfQlxr_ERr6yeCFQLISk_Ao/s4032/perseverance_lego.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="3024" data-original-width="4032" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhu5v4enBanlS6L4TkNh55xAdur_HeHKUBc30MM0VupZti0iBNkOzGiSZZncXnmoifNBe3SXr31d3lQIC6SsYCtEGPj1vDKjim4yntdGHB96GYZaNLLmmeENDJ-P581-HXN7_3xVWL0AYqapYVAqpbgbttz4Nze1bIK4rKuLfQlxr_ERr6yeCFQLISk_Ao/s320/perseverance_lego.jpg"/></a></div>M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-25269377399220284892023-09-19T23:44:00.003+02:002023-09-19T23:44:26.361+02:00Palonnier MFG Crosswind<p>C'était ma petite folie de la rentrée : je me suis offert un palonnier <a href="https://mfg-sim.com/en/4-rudders">MFG Crosswind</a>, fabriqué par une toute petite boite en Croatie, mais qui envoie du pâté. Du solide, tout en métal, à part les pédales qui sont en impression 3D d'excellente qualité, avec un amortisseur optionnel (et donc essentiel). C'est un plaisir de l'utiliser, c'est d'une précision redoutable, et en plus c'est plutôt esthétique.</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQfK2qGVjxFSe72tp9kSjnvby-Ooy1kM0gveWe8QhUuVsms64TPtCbaDd_s03qnwgGWrmEplrvWAC5NDpVhx4uCvjJkDCCnMbyWs0fjAQfcdm9YqroWkJwq3-0WtKEwkUiHc6h5CRrKv_AijbNT2xfB7d_1XH2OAt8StvKuKzctJSZiC09ZNTX9WcrMcM/s2016/palonnier_1.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1512" data-original-width="2016" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQfK2qGVjxFSe72tp9kSjnvby-Ooy1kM0gveWe8QhUuVsms64TPtCbaDd_s03qnwgGWrmEplrvWAC5NDpVhx4uCvjJkDCCnMbyWs0fjAQfcdm9YqroWkJwq3-0WtKEwkUiHc6h5CRrKv_AijbNT2xfB7d_1XH2OAt8StvKuKzctJSZiC09ZNTX9WcrMcM/s320/palonnier_1.jpg"/></a></div><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHqQrHRDhBa0PvLaZUWHG_xVeCFTKwUkkOb-i6FdEo7hzgf0NFctwG362aAddcywm-pKFgUmAI6qYNVegNhDUCr7LEclXcPJXc0WyGGV0a4zjjnPJ91rITOWRuQSyGue5jFYej4LTZP8V-w-SF0kdoczAEpBrTgBNjcxQkErZDcQBCWBgPcVLc68PPki8/s2016/palonnier_2.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1512" data-original-width="2016" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHqQrHRDhBa0PvLaZUWHG_xVeCFTKwUkkOb-i6FdEo7hzgf0NFctwG362aAddcywm-pKFgUmAI6qYNVegNhDUCr7LEclXcPJXc0WyGGV0a4zjjnPJ91rITOWRuQSyGue5jFYej4LTZP8V-w-SF0kdoczAEpBrTgBNjcxQkErZDcQBCWBgPcVLc68PPki8/s320/palonnier_2.jpg"/></a></div>
<p>J'ai choisi les pédales Airbus et les pédales "chasse". Joli, non ?</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGfKy_3mybLW7fRMNkzyk7ypAJ72qx0_XC0mSOM0nFNgOJ8g4y66fVmYisnvsStEaw8kk9t1LbfqItaNZsn9kulLrOeZ6A_oIgzHFdYIYDTrbc7UKNJ_WzcpjG82YjMSalAhsHuCQhAZg_-fxfPlGmtzSevsumYm6P1nsj5Ps8zd3I4VTCztgj3l0b65M/s2016/palonnier_3.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="1512" data-original-width="2016" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGfKy_3mybLW7fRMNkzyk7ypAJ72qx0_XC0mSOM0nFNgOJ8g4y66fVmYisnvsStEaw8kk9t1LbfqItaNZsn9kulLrOeZ6A_oIgzHFdYIYDTrbc7UKNJ_WzcpjG82YjMSalAhsHuCQhAZg_-fxfPlGmtzSevsumYm6P1nsj5Ps8zd3I4VTCztgj3l0b65M/s320/palonnier_3.jpg"/></a></div>
<p>Seul petit souci, le palonnier se met facilement à glisser sur la moquette, et donc je ne dois pas trop serrer l'amortisseur, sinon c'est tout qui bouge !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-84944285819806357032023-09-16T10:52:00.002+02:002023-09-16T10:52:33.471+02:00Accolades et std::optional<p>La nouvelle manière unifiée d'initialiser les valeurs en C++, c'est super. Bim, on met deux accolades, et on a gagné. Vraiment ?</p>
<p>Sur le papier, c'est bath, on peut pas se tromper:</p>
<pre>
int a = {};
std::string b = {};
std::optional<int> c = {};
MonObjectQuIlEstBeau d = {};
</pre>
<p>Sauf qu'il a danger ! C'est que lorsque l'on fait un changement de type quelque part, mettons un paramètre de fonction, et que l'on s'attend à ce que le compilo nous indique gentiment tous les endroits à changer, eh bien il est possible en fait que le compilo accepte le changement sans broncher, mais en changeant la sémantique. Et boum ! C'est ce qui m'est arrivé la semaine dernière, heureusement rapidement détecté. Voyez plutôt cet innocent programme, l'on a une fonction f qui prend un optionel, et on l'appelle en initialisant notre optionel sur vide.</p>
<pre>
#include <optional>
void f(std::optional<int> a);
int main()
{
f({});
return 0;
}
</pre>
<p>Un peu plus tard, l'on change la signature de f:</p>
<pre>
void f(int a);
</pre>
<p>Et boum, l'on initialise maintenant a avec la valeur 0, ce qui pourrait bien être complètement faux.</p>
<p>Que faire alors ? Eh bien, utilisons std::nullopt ! Ainsi, notre appel f(std::nullopt) fonctionnera correctement dans le premier cas, et causera une erreur de compilation dans le deuxième.</p>
<p>Conclusion : mangez du {}, mais avec les optionels, préférez std::nullopt !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-79553764844834934692023-08-06T13:30:00.002+02:002023-08-06T13:30:20.695+02:00Noexcept - Ce n'est pas gratuit !<p>Je parle régulièrement de <a href="https://fr.wikipedia.org/wiki/Culte_du_cargo">culte du cargo</a> dans le domaine informatique, où l'on a souvent ses petites marottes que l'on applique sans comprendre. Et j'ai un chef dont la marotte c'est d'exiger l'ajout du mot-clé "noexcept" un peu partout, avec l'espoir d'augmenter les performances.</p>
<p>Et c'est le cas, parfois. Par exemple, une réallocation d'un std::vector après un dépassement de capacité lors de l'ajout d'un élément sera bien plus efficace si le type de l'élément a un move constructor designé comme noexcept, car dans ce cas, l'algorithme de réallocation du vecteur peut utiliser le move. Il faut donc bien se rendre compte qu'au sein du code de std::vector, il y a une condition qui vérifie à la compilation si le type a son move constructor designé ainsi, et décide d'utiliser l'algo efficace ou non. Ce n'est donc pas une optimisation du compilateur, mais bien un choix de code au sein de la bibliothèque standard, et c'est complètement indépendant du niveau d'optimisation, de l'inlining...</p>
<p>Et surtout, noexcept n'est pas gratuit ! Si le compilo ne peut déterminer si effectivement la fonction marquée noexcept ne lance pas d'exception (disons, elle appelle simplement une autre fonction pas inlinée qui n'est pas déclarée noexcept), il lui faut rajouter du code pour pouvoir attraper cette exception et terminer le programme à la place. Voyons ce que dit notre ami Godbolt sur ce tout petit programme:</p>
<pre>
void f();
void g()
{
f();
}
</pre>
<p>L'assembleur généré est celui-là, c'est à dire un bête jump et puis c'est tout !</p>
<pre>
g():
jmp f()
</pre>
<p>En revanche, si l'on dit maintenant que g() est noexcept:</p>
<pre>
void f();
void g() noexcept
{
f();
}
</pre>
<p>Alors l'assembleur généré nous montre bien que l'on fait un peu plus de travail, en poussant la frame sur la pile, afin que si une exception était lancée dans f(), il soit possible de l'arrêter dans g().</p>
<pre>
g():
subq $8, %rsp
call f()
addq $8, %rsp
ret
</pre>
<p>Conclusion que ne renieraient pas Plic et Ploc : réfléchir avant d'agir !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-58679154285201335042023-07-31T00:34:00.001+02:002023-07-31T00:34:25.103+02:00Fontes pour programmer<p>C'est en lisant un article de <a href="https://developers.slashdot.org/story/23/06/10/030224/intel-open-sources-new-one-mono-font-for-programmers">Slashdot</a> sur une nouvelle fonte mono particulièrement lisible que je me suis mis à reconsidérer mes choix. Jusqu'à présent, j'étais plutôt satisfait des fontes par défaut pour coder dans Emacs, mais de plus en plus, j'étais frustré par la ressemblance du 1 et du l ainsi que du 0 et du O. C'était donc l'occasion d'en changer.</p>
<p>J'ai découvert qu'il existait 2 fontes souvent citée dans ce domaine, <a href="https://en.wikipedia.org/wiki/Consolas">Consolas</a> sous Windows et <a href="https://en.wikipedia.org/wiki/Inconsolata">Inconsolata</a> sous Linux. Après quelques tentatives, je confirme que l'essayer, c'est l'adopter.</p>
<p>Regardez-donc Inconsolata: c'est beau, non ?</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTOiD2UyoEm6lWWkttPfHuFYHKuL1FB53IgjpvRwWmMDA_MmG0Yv_T4zkdFu1YlvjAJB63CBm0WuGRXEJYkPuMpW2hFQOJ54IAR5MouYPs6Ib7O4rvqQYpMjGj3ew6EgfOHYPeY2pEqc8NDYIdf3laI5MdnK_jS4s8uaFPWWt-FjQeXnpC3AOcaka0rmA/s610/Inconsolata.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="481" data-original-width="610" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTOiD2UyoEm6lWWkttPfHuFYHKuL1FB53IgjpvRwWmMDA_MmG0Yv_T4zkdFu1YlvjAJB63CBm0WuGRXEJYkPuMpW2hFQOJ54IAR5MouYPs6Ib7O4rvqQYpMjGj3ew6EgfOHYPeY2pEqc8NDYIdf3laI5MdnK_jS4s8uaFPWWt-FjQeXnpC3AOcaka0rmA/s320/Inconsolata.png"/></a></div>M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-75642283157226350092023-07-10T23:31:00.000+02:002023-07-10T23:31:13.641+02:00Architecture CPU et optimisation du compilo<p>Et on continue de jouer avec <a href="https://godbolt.org/">Godbolt</a>, en particulier la capacité de gcc d'optimiser du code numérique. Prenons par exemple une version simplifiée de la résolution d'une équation quadratique :</p>
<pre>
#include <cmath>
double calc(double a, double b, double c)
{
double delta = b * b - 4 * a * c;
return (-b + sqrt(delta)) / (2 * a);
}
</pre>
<p>Je vous laisserai aller voir sur Godbolt, mais en gros, ça nous fait une 30aine d'instructions assembleur.</p>
<p>La première grosse optimisation, c'est la combinaison de -O3 et de -ffast-math. On passe à 18 lignes (dont 12 seulement font quelque chose d'intéressant), et le compilo utilise l'instruction assembleur sqrtsd plutôt que d'appeler le sqrt de la libc. Mais l'on peut faire encore mieux ! Avec un -march=skylake, on perd 2 instructions, et la machine passe alors sur des instructions vectorisées. Plus rapide ? Moins rapide ? Je suppose que ça va dépendre ! On retrouve un code équivalent en passant chez AMD et -march=znver3.</p>
<p>Maintenant, le souci, c'est que je si, comme dans mon cas, je dois compiler du code qui tournera à la fois sur des machines récentes de chez Intel et AMD, eh bien je suis obligé de garder une architecture générique et de perdre l'avantage de toutes ces instructions magiques... Quand bien même elles sont peut-être en commun ?</p>
<p>Frustrant, donc. Mais probablement pas catastrophique, car le code que j'optimise n'est de toutes façons pas très numérique, et se vectorise probablement mal. Tant pis !</p>M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-44482609072897248492023-06-08T00:19:00.005+02:002023-06-08T00:19:41.785+02:00Gitversion prend ses aises, partie 2<p>Juste un rebond sur mon fil précédent : je suis allé voir ce qu'il en était de git lui même. Et bien, je n'ai pas été déçu : avec grosso modo une dépendance sur la libc, sur zlib, et sur les regex perl, git tient dans à peine plus que 3 megs. Il fait donc à peu près 100 fois plus que gitversion, en 20 fois moins de place. Yay !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-79584822698418623872023-06-06T19:17:00.003+02:002023-06-06T19:17:59.494+02:00Gitversion prend ses aises<p><a href="https://gitversion.net/">Gitversion</a> est un outil ma foi plutôt malin qui regarde un dépôt git et décide du prochain numéro de version, en se basant sur une série de règles, typiquement le tag précédent et certains mots-clé dans les messages de commit. Comme l'outil, ou du moins sa version en ligne de commande (parce qu'il est également disponible en intégration continue par exemple) est plutôt simple, je me suis demandé quelle était la techno derrière.</p>
<p>Un petit ldd plus tard, premier bon point : en fait de dépendances, c'est minimal, en gros libstdc++. Je regarde donc le binaire en lui même, c'est du bon vieux elf, mais les chaines présentes dedans contiennent beaucoup de références à Microsoft. Mhh... Allons donc voir le source.</p>
<p>Et en effet, c'est du C#. Beaucoup de C#, d'ailleurs. Pris d'un doute, je regarde donc la taille du binaire... 66 megs !</p>
<p>Les types ont donc embarqué un interpreteur mono plus tout une palanquée de bibliothèques .NET pour lire quelques lignes de log et générer 3 malheureux nombres qui se battent en duel...</p>
<p>Portabilité, que de disques on a rempli en ton nom !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-84063861641110076462023-05-14T21:01:00.002+02:002023-05-14T21:01:29.405+02:00Question C++ toute bête<p>Qu'est ce qui est le plus rapide ?</p>
<pre>
bool a = ...
if (a)
{
a = false;
}
</pre>
<p>
ou
</p>
<pre>
bool a = ...
a = false;
</pre>
<p>En gros: est-ce que la lecture est significativement moins chère que l'écriture, et que cela vaut donc le coup de vérifier avant d'écrire la valeur ? Pour l'instant, je l'ignore. M'en vais faire tourner quelques benchmarks pour tenter d'élucider cette question...</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-91293833831747238132023-05-01T19:53:00.002+02:002023-05-01T19:53:12.386+02:00Godbolt<p>Je vous ai déjà dit à quel point <a href="https://godbolt.org/">ce site</a> était une tuerie ? L'idée de base est géniale : fournir une interface web permettant de tester un programme sur une grande variété de compilateurs, d'en voir l'assembleur généré, et le résultat. Avec une grande quantité de languages (C++, D, Java, Objective-C, Ocaml...) et une grande quantité de compilos (Pour le c++, nous avons pratiquement chaque version de gcc, de llvm, et du compilo de Microsoft, plus tout un tas de variations). </p>
<p>C'est vraiment très, très sympa pour bidouiller, tester une fonctionnalité à venir, vérifier un bug, faire de la micro-optimisation, ou juste partager une idée de code avec quelqu'un d'autre, parce qu'en plus chaque programme est enregistré via un lien unique. Très, très pratique.</p>M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-8389297521418754452023-04-15T16:03:00.002+02:002023-04-15T16:03:11.671+02:00125 GB !<p>J'avais 15 minutes à tuer l'autre soir, et en traînant dans le Gold Pass de la XBox, je me suis dit que c'était l'occasion de tester un jeu de bagnoles. Je vois Forza, je lance l'installation, et je vois que le jeu fait 125 GB. Alors, voyez vous, ça m'a sérieusement refroidi. Parce que bon, même avec une bonne connection, ça fait quand même un bon moment à passer à télércharger toutes ces cochonneries. Serieusement, il y a quoi, là dedans ? Il y a carrément la texture 4K de chaque brin d'herbe et de chaque caillou ?</p>
<p>Alors j'ai laissé tomber, et j'ai plutôt installé un jeu de rallye et un jeu de F1, qui se contentaient de quelques dizaines de GB.</p>
<p>Et puis j'ai découvert qu'en fait je n'aime pas les jeux de voiture.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-21110465670094176002023-03-26T20:58:00.002+02:002023-03-26T20:58:40.893+02:00Addiction à Civilization 6<p>C'est terrible... À peine sorti de ma 3ème partie de 20 heures, je pense déjà à la prochaine ! Il va falloir que je trouve un moyen de me calmer. Je trouve ce jeu de plus en plus sympa, et en particulier sa variété : un petit peu de city builder, un petit peu de wargame, un petit peu d'exploration... Parfait pour un dilettante comme moi. Venant de remporter une victoire militaire avec les Romains, je tente pour la prochaine la victoire culturelle avec la France sur une carte avec plein d'îles !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-15579373999933587882023-02-23T23:29:00.000+01:002023-02-23T23:29:47.641+01:00C++20 - std::source_location<p>J'ai eu l'occasion d'expérimenter avec la structure <a href="https://en.cppreference.com/w/cpp/utility/source_location">std::source_location</a>, qui est très bien fichue puisqu'elle s'initialise avec les informations courantes de fonction, de fichier source, et de ligne et de colonne dans le source.</p>
<p>Là où c'est très sympa, c'est qu'il est possible en utilisant un paramètre par défaut d'obtenir dans une fonction les informations de l'appelant ! C'est particulièrement pratique, par exemple, pour implémenter une fonction de log qui ne soit pas une immonde macro.</p>
<pre>
#include <source_location>
#include <iostream>
#include <string>
void log(std::source_location location =
std::source_location::current())
{
std::cout << location.function_name() << std::endl;
}
void f()
{
log();
}
template<typename T>
void g()
{
log();
}
int main()
{
f();
g<std::string>();
g<int>();
return 0;
}
</pre>
<p>Et voilà le résultat :</p>
<pre>
void f()
void g() [with T = std::__cxx11::basic_string<char>]
void g() [with T = int]
</pre>
<p>Là où ça devient intéressant, c'est quand on veut le combiner avec une fonction de log variadique, de type std::format. Puisque l'on ne peut pas mettre le paramètre par défaut à la fin, car c'est ambigu, il faut ruser, et transformer le premier paramètre, typiquement la chaîne de formattage, en un objet spécial qui prend en premier paramètre la chaîne de formattage et en deuxième le paramètre std::source_location par défaut. Puis combiner tout cela avec du consteval et l'empaqueter dans un std::identity_type_t afin qu'il ne participe pas à la résolution des types variadiques, sinon ça ne marche pas !</p>
<p>Je posterai à l'occasion un exemple un peu plus complet. D'ici là, compilez bien.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-88711396170663098442023-01-14T16:42:00.003+01:002023-01-14T16:42:25.273+01:00Un Arduino dans le tiroir<p>C'est mon côté polarisé qui reprend le dessus - Je viens de ranger les divers composants électroniques de mon Arduino dans des petits casiers, et cela me remplit de joie.</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjztZd9r4ZXxYFzy9JfjkM8sdxI003mnP-qntptH7FowKIAh231BD01lOBpKyxxTupDs24MmGlmyOsqO1nrESUra2uXQx6p-0KPCQeoYVlg47ZNZbpuem0POP5Qs7UrWpgS3oYwROF8HKJv-25L7hwGI73vdFFosruz1PHzzO11YZQy1Fjb_hUFK27x/s3264/23-01-14%2015-21-20%206760.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="2448" data-original-width="3264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjztZd9r4ZXxYFzy9JfjkM8sdxI003mnP-qntptH7FowKIAh231BD01lOBpKyxxTupDs24MmGlmyOsqO1nrESUra2uXQx6p-0KPCQeoYVlg47ZNZbpuem0POP5Qs7UrWpgS3oYwROF8HKJv-25L7hwGI73vdFFosruz1PHzzO11YZQy1Fjb_hUFK27x/s320/23-01-14%2015-21-20%206760.jpg"/></a></div><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ63Y9XHBJgmFSrH6tsr16mQ2k8XE_jXWQRdniO6hMJazkjDqtn9VGExatuaLQj1L7ZyQNDqMkKpfTCwy4omRMZpHt8XQlhSBW028cSfbmaORh8ubAK9ThBq0Ijmkc3t0JCfl5eMemlJAqWcpQTurA4E_xx6M5szLz0p1XgpKTxyp2fYEbjXb0tCaG/s3264/23-01-14%2015-21-37%206761.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="2448" data-original-width="3264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJ63Y9XHBJgmFSrH6tsr16mQ2k8XE_jXWQRdniO6hMJazkjDqtn9VGExatuaLQj1L7ZyQNDqMkKpfTCwy4omRMZpHt8XQlhSBW028cSfbmaORh8ubAK9ThBq0Ijmkc3t0JCfl5eMemlJAqWcpQTurA4E_xx6M5szLz0p1XgpKTxyp2fYEbjXb0tCaG/s320/23-01-14%2015-21-37%206761.jpg"/></a></div>
<p>En particulier, je galère moins quand je cherche la bonne résistance. Les anneaux de couleur, c'est sympa, mais à moins de sortir la loupe, je trouve ça tout de même plutôt ardu à déchiffrer.</p>
<p>J'en suis maintenant au montage numéro 6, tout en faisant mes recherches sur la meilleure manière de multiplexer un grand nombre de boutons et d'encodeurs rotatifs. Le hardware, c'est pas facile !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-71426128795271068672023-01-04T18:49:00.002+01:002023-01-04T18:49:20.936+01:00Arduino<p>Et voilà, j'ai commené à jouer avec mon Arduino ! Les projets sont sympa, et permettent de comprendre pas à pas comment interfacer des composants electroniques standard (diodes, interrupteurs, capteurs de température, de position...) avec l'Arduino, et d'écrire le code qui va bien. Je continue à apprendre, avant de me lancer dans mon projet principal de panneau de contrôle pour la simu aérienne. Il faudra que j'aille faire mon marché pour acheter boutons et encodeurs rotatifs. Je me tâte même à tenter d'intégrer un afficheur 7 segments pour l'altitude, le cap, la vitesse ascensionelle... Mais c'est plus compliqué à intégrer ensuite depuis l'ordinateur, donc on verra !</p>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1OwmQb9RRp-mVnrhglhqnqQUuSH8EYqux2hCInErCDDX2KyQVfycdOGKITNxmocdan_JL7m8jUJyiVcwgzsGwmcTD2B3mxE5KohOMdSfoxWrk2fgR8pGxqANsWy2CigxdfNkBRRsn2QzsldcwIgnfsYC6L7Cn2IZXSfMDAu6fAg13IUATA3R_gvAS/s3264/22-12-29%2022-28-36%206701.jpg" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="2448" data-original-width="3264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1OwmQb9RRp-mVnrhglhqnqQUuSH8EYqux2hCInErCDDX2KyQVfycdOGKITNxmocdan_JL7m8jUJyiVcwgzsGwmcTD2B3mxE5KohOMdSfoxWrk2fgR8pGxqANsWy2CigxdfNkBRRsn2QzsldcwIgnfsYC6L7Cn2IZXSfMDAu6fAg13IUATA3R_gvAS/s320/22-12-29%2022-28-36%206701.jpg"/></a></div>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-37785600380553779962022-12-14T22:55:00.000+01:002022-12-14T22:55:40.169+01:00Méthodes monadiques sur std::optional<p>Voilà que C++ se prend pour Haskell ! Maintenant, nous avons une belle interface monadique pour <a href="https://en.cppreference.com/w/cpp/utility/optional">std::optional</a>, les méthodes and_then, transform, or_else, qui permettent de chainer des appels sur un optionel. Je me suis demandé si le compilo pouvait optimiser entre les appels, et j'ai donc demandé au fidèle <a href="https://godbolt.org/">godbolt</a> ce quí il en pensait. Le résultat est impressionnant. Voici deux fonctions qui font la même chose, l'une utilisant l'approche monadique (g++ 12.2, options -O3 -std=c++23):</p>
<pre>
#include <optional>
int f(const std::optional<int>& opt)
{
return opt
.transform([](auto&& val) { return val + 3;})
.transform([](auto&& val) { return val - 11;})
.value_or(7);
}
int g(const std::optional<int>& opt)
{
if (opt)
{
return *opt + 3 - 11;
}
else
{
return 7;
}
}
</pre>
<p>G++, sans broncher, nous sort, dans les deux cas, le même code optimisé aux petits oignons: </p>
<pre>
cmpb $0, 4(%rdi)
movl $7, %eax
je .L1
movl (%rdi), %eax
subl $8, %eax
.L1:
ret
</pre>
<p>À noter que clang, encore mieux, nous débarasse carrément du saut conditionnel !</p>
<pre>
movl (%rdi), %ecx
addl $-8, %ecx
cmpb $0, 4(%rdi)
movl $7, %eax
cmovnel %ecx, %eax
retq
</pre>
<p>Ils sont forts, ces concepteurs de compilos. La conclusion, c'est donc que oui, le compilo peut optimiser à travers les appels monadiques. Mangez-en donc !</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0tag:blogger.com,1999:blog-949706588497831852.post-30434558685916674352022-12-07T21:42:00.003+01:002022-12-07T21:42:57.671+01:00VulkanSceneGraph version 1.0<p>Je ne me souvenais pourtant pas de m'être abonné aux sorties de <a href="https://github.com/vsg-dev/VulkanSceneGraph">VulkanSceneGraph</a>, mais j'avais la hype quand j'ai reçu un e-mail annonçant la version 1.0 de la nouvelle mouture du <a href="https://www.openscenegraph.com/">graphe de scène</a>, mais basé sur Vulkan.</p>
<p>J'étais tellement enthousiaste que j'ai pondu une petite trilogie d'articles sur <a href="https://linuxfr.org/">linuxfr.org</a> : tout d'abord, une petite retrospective des <a href="https://linuxfr.org/news/le-rendu-3d-retrospective">techniques de rendu</a>, moment nostalgie avec tous ces vieux jeux, puis un petit aperçu sur les <a href="https://linuxfr.org/news/les-graphes-de-scene">graphes de scène</a>, et enfin la <a href="https://linuxfr.org/news/vulkanscenegraph-un-graphe-de-scene-en-c">présentation de VulkanSceneGraph</a>.</p>
<p>Avec un support gltf aux petits oignons, je n'ai plus qu'à espérer un rapide développement des fonctionnalités d'animation, et je n'aurai plus d'excuses pour ne pas faire un truc avec tout ça.</p>
M87http://www.blogger.com/profile/01230411662211999500noreply@blogger.com0