• [^] # Re: Who's that guy ?

    Posté par (site web personnel, Mastodon) . En réponse au lien Software is Way Less Performant Today. Évalué à 8.

    La connaissance de l'assembleur est bien un pré-requis car il donne vraiment une idée suffisamment précise du comportement du CPU

    Pas vraiment. Les CPU modernes:

    • N'exécutent pas les instructions dans l'ordre,
    • Ont plus de registres en interne que ce qui est disponible dans le jeu d'instruction, et renomment/réassignent les registres à la volée,
    • Sont fabriqués par plusieurs fabricants implémentant le même jeu d'instruction, avec des nombre de cycles CPU par instruction pas forcément identiques,
    • Partagent les unités d'exécution entre plusieurs threads, donc on ne peut même pas savoir quelles ressources vont être disponibles,
    • De toutes façons, le problème est probablement la bande passante de la mémoire et rendre l'exécution du code sur le CPU plus rapide va juste faire que le CPU passe plus de temps à attendre au lieu d'exécuter du code.

    Au final, l'assembleur est un langage de programmation comme un autre, il n'est même plus "proche du matériel". Donc autant choisir un langage plus confortable.

    Bref on se mort la queue : si un CPU est si compliqué c'est aussi à force d'optimisations que les devs n'ont pas voulu faire parce que... "c'est trop compliqué un CPU".

    Faire du code optimisé pour un modèle de CPU, une taille de cache fixe, une mémoire avec une bande passante bien déterminée: facile.

    Faire du code optimisé dans tous les cas, y compris pour des CPU qui ne sont pas encore fabriqués: impossible.

    Ces optimisations dans les CPU sont ce qui permet d'avoir du matériel moderne qui continue d'exécuter le code existant avec de meilleures performances. Je trouve ça mieux que de dire "ah on a rajouté 1Mo de mémoire cache dans le nouveau CPU, mais tu dois réécrire tout ton code pour l'exploiter, parce que c'est à toi de dire explicitement quelles variables il faut stocker dans le cache".

    Le problème est simple: il vaut mieux optimiser le temps de travail des développeurs, plutôt que quelques cycles CPU. Et donc, ne pas avoir à réécrire tout le code à chaque nouvelle génération de CPU, c'est bien.

    le compilo applique des optimisations génériques car il n'a pas le moindre début d'idée de ce que le code fait.

    C'est faisable, on peut donner à gcc une trace d'exécution du code et recompiler une deuxième fois, et il va ajouter automatiquement les instructiosn de prédiction de branchement. Est-ce que des gens s'embêtent à le faire? Non, parce que même cette procédure entièrement automatisée n'a aucun intérêt économique dans la plupart des cas. Le temps passé par le développeur à mettre en place ça va coûter plus cher que les 0.1% de performance qu'on va pouvoir gagner. Sauf dans quelques cas particuliers où ces micro optimisations vont faire la différence entre "ça ne marche pas du tout" et "ça passe de justesse", ou là, le développeur peut être payé très cher pour passer du temps à ce genre de choses.

    Et de toutes façons le problème de l'optimisation n'est même pas là la plupart du temps. Il y a des problèmes beaucoup plus bêtes de mauvais choix de structures de données, ou de mauvaise utilisation de structures de données. Par exemple, faire plusieurs fois de suite une recherche d'un objet dans une map, au lieu de le trouver une fois et de garder une référence. Là on peut avoir des gains de plusieurs dizaines de % de performances, et ça peut être intéressant d'y passer du temps.

    Et pour faire ce genre de choses, c'est plus facile si on travaille avec un langage haut niveau ou au moins qui propose un bon choix de structures de données disponibles dans sa bibliothèque standard (C++ ou Python par exemple). Sinon, le coût de développer ne serait-ce qu'une hash map n'en vaut peut-être même pas la peine.