Avec la plupart des compilateurs C/C++, il existe un indicateur passable pour le compilateur, -march=native
, qui indique au compilateur de régler le code généré pour la micro-architecture et les extensions ISA de la CPU hôte. Même si elle ne porte pas le même nom, il existe généralement une option équivalente pour les compilateurs basés sur LLVM, comme rustc
ou swiftc
.
D'après ma propre expérience, cet indicateur peut fournir des accélérations massives pour le code à forte intensité numérique, et il sons comme s'il serait exempt de compromis pour le code que vous compilez juste pour votre propre machine. Cela dit, je ne pense pas avoir vu de système de construction ou de compilateur statique qui le permette par défaut:
Évidemment, tout exécutable du compilateur en ligne de commande qui vous oblige à le passer ne l'utilise pas par défaut.
Je ne peux penser à aucun IDE qui permet cela par défaut.
Je ne peux penser à aucun système de construction commun avec lequel j'ai travaillé (cmake
, automake
, cargo
, spm
, etc.) qui le permet par défaut, même pour les versions optimisées.
Je peux penser à quelques raisons à cela, mais aucune n'est vraiment satisfaisante:
En utilisant -march=native
est inapproprié pour les binaires qui seront distribués sur d'autres machines. Cela dit, je me retrouve à compiler des sources pour ma propre machine beaucoup plus souvent que pour d'autres, et cela n'explique pas son manque d'utilisation dans les versions de débogage, où il n'y a aucune intention de distribution.
Au moins sur les processeurs Intel x86, je crois comprendre que l'utilisation peu fréquente des instructions AVX pourrait dégrader les performances ou l'efficacité énergétique, car l'unité AVX est mise hors tension lorsqu'elle n'est pas utilisée, ce qui nécessite qu'elle soit mise sous tension pour être utilisée, et de nombreux processeurs Intel downclock pour exécuter les instructions AVX. Pourtant, cela explique seulement pourquoi AVX ne serait pas activé, pas pourquoi le code ne serait pas réglé pour la gestion des instructions régulières par la micro-architecture particulière.
Étant donné que la plupart des processeurs x86 utilisent des pipelines superscalaires sophistiqués et hors service avec un changement de nom de registre, le réglage du code pour une micro-architecture particulière n'est probablement pas particulièrement important. Pourtant, si cela pourrait aider, pourquoi ne pas l'utiliser?
Si vous regardez de plus près les paramètres par défaut de gcc, le plus ancien compilateur de votre liste, vous vous rendrez compte qu'ils sont très conservateurs:
-Wall
et -Wextra
n'a pas changé depuis des années; il y a de nouveaux avertissements utiles, ils NE sont PAS ajoutés à -Wall
ou -Wextra
.Pourquoi? Parce que ça casserait les choses!
Il existe des chaînes de développement entières qui s'appuient sur ces valeurs par défaut de commodité, et toute modification entraîne le risque de les casser ou de produire des fichiers binaires qui ne fonctionneront pas sur les cibles.
Plus il y a d'utilisateurs, plus la menace est grande, donc les développeurs de gcc sont très, très conservateurs pour éviter les ruptures mondiales. Et les développeurs du prochain lot de compilateurs suivent les traces de leurs aînés: il a fait ses preuves.
Remarque: rustc
utilisera par défaut la liaison statique et se vante que vous pouvez simplement copier le binaire et le déposer sur une autre machine; évidemment -march=native
y serait un obstacle.
Et en vérité, cela n'a probablement pas d'importance. Vous l'avez reconnu vous-même:
D'après ma propre expérience, cet indicateur peut fournir des accélérations massives pour le code à forte intensité numérique
La plupart du code est plein d'appels virtuels et de branches (généralement OO) et pas du tout numériquement intensif. Ainsi, pour la majorité du code, SSE 2 est souvent suffisant.
Les quelques bases de code pour lesquelles les performances sont vraiment importantes nécessiteront de toute façon un temps considérable pour l'optimisation des performances, à la fois au niveau du code et du compilateur. Et si la vectorisation est importante, elle ne sera pas laissée à la discrétion du compilateur: les développeurs utiliseront les intrinsèques intégrés et rédigeront eux-mêmes le code vectorisé, car c'est moins cher que de mettre en place un outil de surveillance pour s'assurer que l'auto-vectorisation a bien eu lieu .
De plus, même pour un code à forte intensité numérique, la machine hôte et la machine cible peuvent différer légèrement. La compilation bénéficie d'un grand nombre de cœurs, même à une fréquence plus faible, tandis que l'exécution bénéficie d'une fréquence élevée et éventuellement de moins de cœurs, à moins que le travail ne soit facilement parallélisable.
Ne pas activer -march=native
par défaut facilite le démarrage des utilisateurs; puisque même les chercheurs de performances ne s'en soucient pas beaucoup, cela signifie qu'il y a plus à perdre qu'à gagner.
Dans une autre histoire où la valeur par défaut avait été -march=native
Depuis le début; les utilisateurs seraient utilisés pour spécifier l'architecture cible, et nous n'aurions pas cette discussion.
-march=native
Est un drapeau destructeur. Cela rend le binaire possible non compatible sur beaucoup de matériel (essentiellement n'importe quel CPU qui n'est pas un descendant direct de celui utilisé pour la compilation). Il est tout simplement trop dangereux de l'activer par défaut.
Une autre chose importante à considérer est que l'utilisation finale de -march=native
Est l'optimisation. L'indicateur d'optimisation par défaut est -O0
(Pas d'optimisation), il ne serait donc pas logique dans cette perspective de l'activer par défaut.
Vous pensez du point de vue des utilisateurs avancés, mais le public principal d'une chaîne d'outils de compilation n'est pas les utilisateurs avancés, mais plutôt les développeurs.
La plupart des développeurs ont une machine de développement et des systèmes de production cibles distincts. Dans le cas d'applications grand public, ce système cible est la machine d'autrui avec tous les écarts. Construire pour le dénominateur le plus courant est un défaut sûr car il réduit le risque de bogues qui ne se produisent qu'en dehors des machines du développeur.
Bien sûr, il y a des cas où les développeurs savent qu'ils vont développer une application pour une machine cible unique avec une architecture connue. Mais même dans ce cas, la plupart des applications ne sont pas sensibles aux performances, donc l'option sûre par défaut fonctionne toujours assez bien, tandis que les développeurs qui travaillent sur des applications sensibles aux performances sont généralement plus disposés à consacrer du temps à peaufiner leurs configurations de génération.