2009-02-11 11 views
4

J'ai un morceau de C++ hautement optimisé et faire de petits changements dans des endroits éloignés des points chauds peut atteindre 20% de performance. Après une enquête plus approfondie, il s'est avéré être (probablement) des registres légèrement différents utilisés dans les points chauds. Je peux contrôler en ligne avec l'attribut always_inline, mais puis-je contrôler l'allocation de registre?Puis-je contrôler l'allocation de registre en g ++?

+0

Seriez-vous contraint en 32 bits x86? Parce que x86 64 bits a plus de registres (environ 16 je pense?) Et ne devrait pas avoir de problèmes comme ça ... – Calyth

+0

J'ai essayé 64, mais il s'est avéré que c'est plus lent. Je ne pouvais pas trouver la raison pour cela. –

Répondre

6

Si vous voulez vraiment jouer avec l'allocation de registre, vous pouvez forcer GCC à allouer des variables locales et globales dans certains registres.

vous faites cela avec une déclaration variable spéciale comme ceci:

register int test_integer asm ("EBX"); 

Works pour d'autres architectures aussi bien, il suffit de remplacer EBX avec un nom de registre cible spécifique.

Pour plus d'informations sur cela, je vous suggère de jeter un oeil à la documentation gcc:

http://gcc.gnu.org/onlinedocs/gcc-4.3.3/gcc/Local-Reg-Vars.html

Ma suggestion est cependant de ne pas jouer avec l'allocation de registre à moins que vous avez de très bonnes raisons pour elle . Si vous allouez vous-même des registres, l'allocateur a moins de registres à utiliser et vous risquez de vous retrouver avec un code pire que le code avec lequel vous avez commencé.

Si votre performance est essentielle pour obtenir 20% de différences de performances entre les compilations, il peut être judicieux d'écrire cette chose dans inline-assembler.


EDIT: Comme strager a souligné le compilateur n'est pas obligé d'utiliser le registre pour la variable. Il est seulement obligé d'utiliser le registre si la variable est utilisée du tout. Par exemple. Si la variable ne survit pas à une passe d'optimisation, elle ne sera pas utilisée. Le registre peut également être utilisé pour d'autres variables.

+0

En fait, la syntaxe dit "utiliser ce registre pour jouer avec test_integer". Cela ne force pas EBX à être test_integer. Au contraire, il force test_integer à être EBX. (Au moins d'après ce que je comprends des docs.) Je pense que vous devriez préciser cela dans votre réponse. – strager

+0

bon lien. inline asm n'est pas une option. le point chaud est beaucoup trop grand. –

+0

Lukasz, si vous ne voulez pas utiliser l'assembleur en ligne, vous pouvez également prendre un code objet compilé qui fonctionne bien, le désassembler et utiliser le code asm généré. –

-1

Cela dépend du processeur que vous utilisez. Ou devrais-je dire, oui vous pouvez avec le mot-clé de registre, mais cela est désapprouvé, sauf si vous utilisez un processeur simple sans doublure et un seul noyau. Ces jours-ci, GCC peut faire un meilleur travail que vous pouvez avec l'allocation des registres. Faites-en confiance.

+1

Ses résultats montrent qu'il n'est pas digne de confiance dans ce cas. Il obtient 20% de changements de performance dans différentes versions! – Novelocrat

3

En général, le mot-clé register est simplement ignoré par tous les compilateurs modernes. La seule exception est l'ajout (relativement) récent d'une erreur si vous tentez de prendre l'adresse d'une variable que vous avez marquée avec le mot clé register. J'ai aussi éprouvé ce genre de douleur, et j'ai finalement trouvé que le seul moyen de contourner le problème était de regarder l'assemblage de sortie pour essayer de déterminer ce qui fait que gcc disparait du dépendant. Il y a d'autres choses que vous pouvez faire, mais cela dépend exactement de ce que votre code essaie de faire. Je travaillais dans une très très grande fonction avec une grande quantité de chaos dans lesquels des changements mineurs (apparemment inoffensifs) pouvaient causer des dégâts catastrophiques. Si vous faites des choses similaires, il y a quelques choses que vous pouvez faire pour essayer d'atténuer le problème, mais les détails sont quelque peu bizarres, donc je renoncerai à en discuter ici, à moins que ce soit pertinent.

+0

afaik goto va sérieusement visser avec la capacité d'un compilateur à optimiser, ce qui conduit probablement à la sortie amusante. – Calyth

+0

Oui, mais goto calculé est extraordinairement utile pour les interprètes où vous écrivez de toute façon une série de goto (un interpréteur standard est while (1) switch (...) {pile de code}, ou statementNode-> execute (..) (où execute est une fonction virtuelle) – olliej

+0

@Calyth: Les gotos réguliers ne nuisent pas à l'optimisation - le compilateur doit faire essentiellement la même chose pour les instructions break/continue et return dans les fonctions qui sont inline. –

Questions connexes