À l'aide du Langage assembleur en C/C++
Je me souviens avoir lu quelque part que pour vraiment optimiser & vitesse jusqu'à une certaine section du code, les programmeurs d'écrire cet article dans le langage d'Assemblage. Mes questions sont -
- Cette pratique est encore fait? et Comment fait-on cela?
- N'est pas écrit en Langage d'Assemblage un peu trop lourd & archaïque?
- Lorsque nous compiler du code C (avec ou sans l'option-O3 drapeau), le compilateur effectue une optimisation de code & les liens de toutes les bibliothèques & convertit le code binaire de l'objet fichier. Alors, quand on lance le programme, il est déjà dans sa forme la plus basique, c'est à dire binaire. Alors, comment induire de l'Assemblée de la Langue " de l'aide?
Je suis en train d'essayer de comprendre ce concept & de l'aide ou des liens est très apprécié.
Mise à JOUR: de Reformuler le point 3, comme demandé par dbemerlin - Parce que vous pourriez être en mesure d'écrire plus efficace assemblée de code que le compilateur génère, mais sauf si vous êtes un assembleur expert, votre code sera probablement plus lent parce que, souvent, le compilateur optimise le code mieux que la plupart des humains peuvent.
- Belle question, correctement rédigé. +1
- C'est probablement l'une des cinq questions sur ALORS, où à l'aide de "C/C++" a du sens.
Vous devez vous connecter pour publier un commentaire.
Le seul moment où il est utile de revenir à l'assemblée de la langue, c'est quand
des instructions du PROCESSEUR n'ont pas d'équivalents fonctionnels en C++ (par exemple, les instructions de plusieurs instructions données, BCD ou des opérations arithmétiques décimales)
<cstdlib>
adiv
/ldiv
et al pour obtenir le quotient et reste efficace)OU
pour des raisons inexplicables - l'optimiseur est de ne pas utiliser les meilleures instructions du PROCESSEUR
...ET...
Simplement en utilisant assembly en ligne pour faire une opération qui peut facilement être exprimé en C++, comme l'ajout de deux valeurs ou à la recherche dans une chaîne est activement contre-productif, parce que:
gcc -S
) ou désassembler le code machine#ifdef
-ed pour vos plates-formes deUn point de vue que je pense est bon de garder à l'esprit est que lorsque C a été introduit, il a dû gagner beaucoup de hardcore langage d'assemblage programmeurs qui s'agitait sur le code machine généré. Machines a moins de puissance CPU et de la RAM à l'époque, et vous pouvez parier que les gens se sont agités sur la plus petite des choses. Optimisateurs est devenu très sophistiqué et ont continué à s'améliorer, alors que l'assemblée langues de processeurs comme le x86 sont devenus de plus en plus compliqué, comme d'autres de leur exécution, les pipelines, les caches et d'autres facteurs impliqués dans leur performance. Vous ne pouvez pas ajouter des valeurs à partir d'une table de cycles par instruction plus. Les rédacteurs du compilateur prendre le temps d'examiner toutes ces subtiles facteurs (en particulier ceux qui travaillent pour les fabricants de processeurs, mais qui augmente la pression sur d'autres compilateurs trop). Il est maintenant impossible pour les programmeurs en assembleur en moyenne - plus de toutes les non-trivial de l'application de manière significative une meilleure efficacité de code que celle générée par une bonne optimisation du compilateur, et ils sont extrêmement probable à faire pire. Ainsi, l'utilisation de l'assemblage doit être limitée à la fois, il fait vraiment un mesurables et utiles différence, ça vaut le couplage et les coûts de maintenance.
Tout d'abord, vous devez établir le profil de votre programme. Ensuite, vous optimisez les plus utilisées, les chemins de code C ou C++. À moins que les avantages sont clairs, vous n'avez pas de réécriture en assembleur. À l'aide d'assembler rend votre code plus difficile à maintenir et beaucoup moins portable, c'est pas la peine, sauf dans de très rares situations.
strlen()
dans une boucle tandis que la longueur de la chaîne ne change pas de réécriture qui en assembleur est un gaspillage de temps - il suffit d'utiliser une variable temporaire pour stocker la longueur et (magique!) vous programme susceptible s'exécute beaucoup plus rapidement.(1) Oui, la façon la plus simple d'essayer ce sort est à utiliser inline assemblée, c'est le compilateur, mais dépend ressemble généralement à ceci:
(2) C'est très subjectif
(3) Parce que vous pourriez être en mesure d'écrire plus efficace assemblée de code que le compilateur génère.
Because you might be able to write more effective assembly code than the compiler generates
mais sauf si vous êtes un assembleur expert, votre code sera probablement plus lent parce que, souvent, le compilateur optimise le code mieux que la plupart des humains peuvent.Vous devriez lire le livre classique
Zen of Code Optimization
et le suiviZen of Graphics Programming
par Michael Abrash.Sommairement dans le premier livre, il explique comment utiliser l'assemblage de programmation poussés à la limite. Dans le cadre du suivi, il a expliqué que les programmeurs doivent plutôt utiliser certains langage de plus haut niveau comme le C et seulement essayer d'optimiser très spécifique les taches à l'aide de l'assemblée, si nécessaire.
Une motivation de ce changement d'esprit était qu'il ne voyait que très optimisé les programmes de génération de processeur pourrait devenir (un peu) la lenteur dans la prochaine génération de la même famille de processeur par rapport à code compilé à partir d'un langage de haut niveau (peut-être compilateur à l'aide de nouvelles instructions, par exemple, ou la performance et le comportement de celles existantes de la modification d'un processeur de la génération à l'autre).
Une autre raison est que les compilateurs sont très bons et d'optimiser de manière agressive aujourd'hui, il y a généralement beaucoup plus de performance à acquérir en travaillant sur des algorithmes de conversion de code C à l'assemblée. Même pour les GPU (Cartes Graphiques processeurs) de la programmation vous pouvez le faire en C à l'aide de cuda ou OpenCL.
Il y a encore quelques (rares) cas où vous devriez/devez utiliser de l'assemblée, habituellement pour obtenir un réglage très fin sur le matériel. Mais même dans les OS code du noyau, il est généralement de très petites pièces et pas beaucoup de code.
loop
vsdec/jnz
,sub
/mov
vspush
) énormément changé entre 8086 et 686. Et 586 dans l'ordre superscalar pentium est une valeur aberrante où il pourrait pipeline des instructions simples, faisant d'elle la peine d'utiliser plus simples instructions vs moins d'instructions complexes. Plus tard, les Processeurs peuvent décoder complexes à plusieurs uop, mais 586 ne pouvait pas et qu'il suffit de caler le pipeline.Il y a très peu de raisons d'utiliser la langue assemblage de ces jours, même à faible niveau de constructions comme de l'ESS et de l'âge de MMX ont intégré intrinsèques à la fois cgc et MSVC (cpi trop je parie, mais je n'ai jamais utilisé).
Honnêtement, les optimiseurs de ces jours sont si incroyablement agressif que la plupart des gens ne pouvaient pas égale à la moitié de leur performance à l'écriture de code en assembleur. Vous pouvez changer la façon dont les données sont commandés en mémoire (localité) ou de dire au compilateur plus au sujet de votre code (par
#pragma
), mais en fait, l'écriture de code assembleur... de doute, vous obtiendrez quelque chose de cela.@VJo, notez que l'utilisation de intrinsèques de haut niveau en code C vous laisser faire les mêmes optimisations, sans l'aide d'une seule instruction de montage.
Et pour ce que ça vaut, il y a eu des discussions au sujet de la prochaine compilateur C++ de Microsoft, et comment ils tomberont assembly en ligne à partir d'elle. Qui parle des volumes au sujet de la nécessité pour elle.
Il dépend. Il est (encore) fait, dans certaines situations, mais pour la plupart, c'est pas la peine. Les Processeurs modernes sont incroyablement complexes, et il est tout aussi complexes à écrire un montage efficace de code pour eux. Ainsi, la plupart du temps, l'assemblée vous écrivez à la main de finir plus lente que ce que le compilateur peut générer pour vous.
En supposant un compilateur décent publié dans le dernier couple de d'années, vous pouvez généralement modifier votre code C/C++ pour obtenir le même avantage en matière de performances, comme vous le feriez à l'aide de l'assemblée.
Beaucoup de gens dans les commentaires et de réponses ici, parlons de la "N fois speedup" ils ont gagné la réécriture quelque chose dans l'assemblée, mais que par lui-même ne veut pas dire trop. J'ai eu un 13 fois l'accélération de la réécriture d'une fonction C de l'évaluation de la dynamique des fluides, les équations de en C, par l'application d'un grand nombre des mêmes optimisations que vous le feriez si vous étiez à écrire dans l'assemblée, par la connaissance du matériel, et par profilage. À la fin, il obtenu assez proche de la théorique des performances de pointe du PROCESSEUR qu'il y aurait pas de point dans la réécriture dans l'assemblée. Généralement, ce n'est pas la langue qui est le facteur limitant, mais le code que vous avez écrit. Tant que vous n'êtes pas à l'aide de "spécial" des instructions pour que le compilateur a de la difficulté, il est difficile de battre le bien-écrit le code C++.
De l'assemblée n'est pas comme par magie plus rapide. Il faut juste le compilateur en dehors de la boucle. C'est souvent une mauvaise chose, à moins que vous vraiment savez ce que vous faites, car le compilateur effectue beaucoup d'optimisations qui sont vraiment vraiment pénible à faire à la main. Mais dans de rares cas, le compilateur n'a tout simplement pas de comprendre votre code, et ne peut pas générer un montage efficace, et puis, il pourrait être utile d'écrire un peu de montage vous-même. Autres que pilote de développement ou similaires (où vous avez besoin de manipuler le matériel directement), le seul endroit où je peux penser à l'endroit où la rédaction de l'assemblée peut être intéressant de il est si vous êtes coincé avec un compilateur qui ne peuvent pas générer efficace de l'ESS code de intrinsèques (comme MSVC). Même là, je serais encore commencer à l'aide de intrinsèques en C++, et de profil, et d'essayer de l'adapter autant que possible, mais parce que le compilateur n'est tout simplement pas très bon à cela, il pourrait éventuellement être la peine de réécrire ce code dans l'assemblée.
Je ne pense pas que vous avez spécifié le processeur. Des réponses différentes en fonction du processeur et de l'environnement. Manière générale, la réponse est oui, il est encore fait, il n'est pas archaïque certainement. La raison générale est que les compilateurs, parfois ils font un bon travail à l'optimisation en général, mais pas vraiment bien pour des objectifs spécifiques. Certains sont très bons dans une cible et pas bon du tout à d'autres. La plupart du temps il est assez bon, la plupart du temps vous voulez le portable de code C et pas non portable assembleur. Mais vous trouvez toujours que C des bibliothèques seront toujours de la main d'optimiser memcpy et d'autres routines que le compilateur ne peut tout simplement pas comprendre qu'il y a un moyen très rapide à mettre en œuvre. En partie parce que des cas de coin n'est pas la peine de passer du temps à faire le compilateur d'optimiser, de la même manière de le résoudre dans l'assembleur et le système de construction a beaucoup de si cette cible, puis utilisez C si la cible utilise C si la cible utilisation de l'asm, si la cible utilisation de l'asm. De sorte qu'il se produit encore, et je soutiens doivent continuer éternellement dans certains domaines.
X86 est propre bête avec beaucoup d'histoire, nous sommes à un point où vous ne pouvez vraiment pas pratique d'écrire une goutte d'assembleur qui est toujours plus rapide, vous pouvez certainement optimiser les routines d'un processeur spécifique sur une machine spécifique sur un jour précis, et à effectuer le compilateur. Autres que pour certains cas spécifiques, il est généralement inutile. D'enseignement mais dans l'ensemble ne vaut pas le temps. Notez également que le processeur n'est plus le goulot d'étranglement, donc un mauvais générique compilateur C est assez bon, de trouver de la performance d'ailleurs.
D'autres plates-formes qui signifie souvent incorporé, arm, mips, avr, msp430, pic, etc. Vous peut ou peut ne pas être en cours d'exécution d'un système d'exploitation, vous peut ou peut ne pas être en cours d'exécution avec un cache ou d'autres choses telles que votre desktop. Donc les faiblesses de le compilateur va le montrer. Notez également que les langages de programmation continuer à évoluer loin de processeurs au lieu de les atteindre. Même dans le cas de C est considéré comme peut-être d'être un langage de bas niveau, il n'ya pas de match le jeu d'instructions. Il y aura toujours des moments où vous pouvez produire des segments de l'assembleur qui dépassent le compilateur. Pas nécessairement le segment qui est le goulot d'étranglement mais à l'échelle de l'ensemble du programme, vous pouvez souvent faire des améliorations ici et là. Vous devez toujours vérifier la valeur de le faire. Dans un environnement embarqué, il peut faire la différence entre le succès et l'échec d'un produit. Si votre produit est de 25 $par unité investi dans plus de puissance de la faim, conseil immobilier, plus de la vitesse des processeurs de sorte que vous n'avez pas à utiliser de l'assembleur, mais votre concurrent passe de 10 $ou moins par unité et est prêt à mélanger asm C à utiliser de plus petits souvenirs, d'utiliser moins d'énergie, moins cher, pièces, etc. Bien tant que la loi NRE est récupéré puis le mélange avec l'asm solution à long terme.
Vrai embedded est un marché spécialisé avec des ingénieurs spécialisés. Un autre incorporées marché, votre linux embarqué roku, tivo, etc. Intégré téléphones, etc tous besoin d'avoir portable systèmes d'exploitation pour survivre, parce que vous avez besoin de développeurs tiers. De sorte que la plate-forme doit être plus comme un ordinateur de bureau que sur un système embarqué. Enterré dans la bibliothèque C, mentionnées ou le système d'exploitation il peut y avoir certains assembleur optimisations, mais comme avec le bureau que vous souhaitez pour tenter de jeter matériel de sorte que le logiciel peut être portable au lieu de la main optimisée. Et votre ligne de produit ou de système d'exploitation embarqué sera un échec si l'assembleur est requis pour la troisième partie réussite.
La plus grande préoccupation que j'ai, c'est que cette connaissance est en train de disparaître à un rythme alarmant. Parce que personne ne inspecte l'assembleur, parce que personne n'écrit en assembleur, etc. Personne n'est à remarquer que les compilateurs n'ont pas été l'amélioration quand il s'agit du code produit. Les développeurs pensent souvent qu'ils ont à acheter plus de matériel au lieu de réaliser que par connaître le compilateur, ou comment le programme de mieux, ils peuvent améliorer leurs performances en 5 à plusieurs centaines de pour cent avec le même compilateur, parfois avec le même code source. De 5 à 10% en général avec le même code source et le compilateur. gcc 4 ne produisent pas toujours mieux que le code de gcc 3, je garde les deux, parce que parfois gcc3 fait mieux. Cibler certains compilateurs peuvent (pas toujours) d'exécuter des cercles autour de gcc, vous pouvez voir quelques centaines de pour cent d'amélioration, parfois avec le même code source du compilateur différent. D'où tout cela vient-il? Les gens qui ont encore la peine de chercher et/ou de l'utilisation de l'assembleur. Certains de ces gens travaillent sur le compilateur backends. L'extrémité avant et milieu sont amusants et éducatifs, certes, mais le backend est où vous faire ou défaire la qualité et la performance du programme résultant. Même si vous n'avez jamais écrire en assembleur, mais seulement chercher à la sortie du compilateur de temps en temps (gcc-O2 -s myprog.c) il fera de vous un meilleur niveau élevé programmeur et conservent certaines de ces connaissances. Si personne n'est prêt à le connaître et à écrire en assembleur, puis par la définition que nous avons donnée dans l'écriture et le maintien de compilateurs de haut niveau pour les langues et du logiciel en général, cessera d'exister.
Comprendre qu'avec gcc par exemple la sortie du compilateur est l'assemblée qui est transmis à un assembleur qui le transforme en code objet. Le compilateur C ne produisent habituellement pas de binaires. Les objets lorsqu'ils sont combinés en finale binaire, se fait par l'éditeur de liens, encore un autre programme qui est appelé par le compilateur et ne fait pas partie du compilateur. Le compilateur transforme en C ou C++ ou ADA ou que ce soit en assembleur puis l'assembleur et l'éditeur de liens outils de prendre le reste de la voie. Dynamique recompilers, à l'instar de la stc par exemple, doit être en mesure de générer des exécutables à la volée, en quelque sorte, mais je vois que, comme l'exception, non la règle. LLVM a sa propre solution d'exécution ainsi que de toute évidence, montrant le niveau élevé de code interne, afin de cibler le code binaire chemin si vous l'utilisez comme un cross compilateur.
Donc, pour revenir à la question, oui c'est fait, plus souvent que vous ne le pensez. Surtout a à voir avec la langue ne compare pas directement le jeu d'instructions, et puis le compilateur ne pas toujours produire assez rapidement le code. Si vous pouvez obtenir dire des dizaines de fois sur l'amélioration de la très utilisés, comme les fonctions malloc ou memcpy. Ou si vous voulez avoir une vidéo HD player sur votre téléphone sans support matériel, balance les avantages et les inconvénients de l'assembleur. Véritablement intégrés marchés toujours utiliser de l'assembleur tout à fait un peu, parfois, c'est tout C mais parfois, le logiciel est entièrement codé en assembleur. Pour pc x86, le processeur n'est pas le goulot d'étranglement. Les processeurs sont microcoded. Même si vous faire de belles à la recherche d'assembleur, sur la surface il l'habitude de courir très vite sur toutes les familles de processeurs x86, bâclée, assez bon code est le plus susceptible de s'exécuter sur le même travers le conseil d'administration.
Je recommande fortement l'apprentissage de l'assembleur pour les non-x86 Isa comme le bras, pouce/thumb2, mips, msp430, avr. Les cibles qui ont des compilateurs, en particulier ceux avec gcc ou à la prise en charge du compilateur llvm. Apprendre l'assembleur, apprendre à comprendre la sortie du compilateur C, et de prouver que vous pouvez faire mieux fait de la modification de cette sortie et de le tester. Cette connaissance vous aidera à faire de votre bureau de haut niveau code de beaucoup mieux sans assembleur, plus rapide et plus fiable.
Prendre un coup d'oeil ici, où le gars d'améliorer les performances de 6 heures à l'aide de code assembleur. Donc, la réponse est : il est toujours en train de se faire, mais le compilateur est en train de faire du bon travail.
Sur mon travail, j'ai utilisé de l'assemblée sur cible embarquée (micro-contrôleur) pour l'accès de bas niveau.
Mais pour un logiciel PC, je ne pense pas que c'est très utile.
Duke Nukem Forever
effet. Vous n'avez pas encore fini de l'optimisation que la prochaine génération de matériel est là et vous devez redémarrer à partir de zéro parce que tout a changé et votre ancien code optimisé est maintenant de moins en moins efficace que le code compilé sur le nouveau matériel...J'ai un exemple de montage d'optimisation que j'ai fait, mais c'est encore sur une cible embarquée. Vous pouvez voir quelques exemples de montage de programmation pour les Pc trop, et il crée vraiment petit et rapide des programmes, mais ne vaut pas l'effort (Cherchez "assemblée pour windows", vous pouvez trouver quelques très petite et assez de programmes).
Mon exemple, j'avais écrit un contrôleur d'imprimante, et il y avait une fonction qui était censé être appelée à chaque 50 micro-secondes. Il y a à faire, remaniement de bits, plus ou moins. À l'aide de C, j'ai été en mesure de le faire en 35microseconds, et avec le montage je l'ai fait en environ 8 secondes. C'est une procédure bien spécifique, mais encore, quelque chose de réel et nécessaire.
Sur certains appareils embarqués (téléphones et Pda), c'est utile parce que les compilateurs ne sont pas très matures, et peut générer très lent et même un code incorrect. J'ai personnellement eu à contourner, ou d'écrire le code d'assemblée de fixer, le buggy de sortie de plusieurs compilateurs pour les BRAS embarqués à base de plates-formes.
"Cette pratique est encore fait?"
--> Il est fait en traitement d'image, traitement du signal, de l'IA (par exemple. efficace de multiplication de matrice), et d'autres. Je serais prêt à parier que le traitement de la geste de défilement sur mon macbook trackpad est également partiellement assemblée de code parce que c'est immédiat.
--> Il est encore fait dans des applications C# (voir https://blogs.msdn.microsoft.com/winsdk/2015/02/09/c-and-fastcall-how-to-make-them-work-together-without-ccli-shellcode/)
"N'est pas écrit en Langage d'Assemblage un peu trop lourd & archaïque?"
--> C'est un outil comme un marteau ou un tournevis et certaines tâches nécessitent un tournevis horloger.
--> j'aime ce que @jalf.com dit, que l'écriture de code C dans une manière que vous le feriez écrire assemblée déjà conduire à un code efficace. Toutefois, pour ce faire, vous devez penser à comment vous pouvez écrire le code en langage d'assemblage, afin par exemple. comprendre tous les endroits où les données sont copiées (et de ressentir de la douleur à chaque fois, c'est inutile).
Avec le langage d'assemblage, vous pouvez être sûr de laquelle les instructions sont générés. Même si votre code C est efficace, il n'y a aucune garantie que l'assemblée sera efficace avec chaque compilateur. (voir https://lucasmeijer.com/posts/cpp_unity/)
--> Avec le langage d'assemblage, au moment de distribuer un binaire, vous pouvez tester le cpu et faire différentes branches selon les fonctions du processeur optimisé pour pour AVX ou tout simplement pour l'ESS, mais vous avez seulement besoin de distribuer un binaire. Avec intrinsèques, c'est aussi possible en C++ ou .NET de Base 3. (voir https://devblogs.microsoft.com/dotnet/using-net-hardware-intrinsics-api-to-accelerate-machine-learning-scenarios/)