2010-09-23 4 views
0

Est-il plus rapide d'accéder à une variable globale ou objet?Différence de vitesse entre la variable globale et la variable objet

En C++, je fais référence à la différence entre

::foo 

et

this->foo 

En assembleur x86, cela se traduit essentiellement à

mov eax, offset foo 

vs

mov eax, dword ptr[edx+foo] 

Toutes les données dans les deux cas devraient être dans le cache.

(Je connais la différence s'il y en a une minuscule, et il faut généralement choisir celle qui simplifie le code, mais dans ce cas il n'y a littéralement aucune autre différence, et le code en question s'appellera peut-être un demi-milliard fois dans une limite de temps, donc je pourrais aussi bien aller avec celui qui est même un peu plus rapide.)

+2

Qu'en est-il du test et du timing des deux variantes? – sharptooth

+1

Si cela est important, cela vaut la peine d'être chronométré. Cela dit, la variable membre sera probablement plus souvent mise en cache avec vos autres données. – GManNickG

+0

"Sous une limite de temps"? Quelle est la limite de temps? Un demi-milliard d'accès par seconde pourrait signifier que cela a une incidence sur la performance, mais un demi-milliard par heure le rendrait complètement insignifiant. – jalf

Répondre

8

Vous devez tester et chronométrer les deux. Cependant, sachez que vous avez pris d'autres décisions dans votre application qui auront un plus grand impact sur les performances, de plusieurs ordres de grandeur que. Pour les yeux humains, le Global est plus rapide d'accès, mais ce que le compilateur décide de placer où, et comment le processeur décide de mettre en cache les choses va finalement décider lequel est le plus rapide.

Testez-le et chronométrez-le. Je serais étonné si vous avez des différences significatives dans une application non triviale sur des millions de courses.

+0

Et le downvote est parce que. . ? Si vous n'êtes pas d'accord avec ma réponse, pouvez-vous me dire pourquoi? J'aimerais savoir ce qui ne va pas, nous sommes tous là pour apprendre après tout :) –

1

Comme l'ont dit les commentateurs précédents, mesurez-le. Comparer les instructions de l'assembleur ne vous aidera pas. Prédire le comportement de vos ordinateurs cpu caching est presque impossible et dépend des autres données nécessaires. En outre, votre programme n'est pas nécessairement lié au processeur.

Vous pouvez utiliser en plaçant le nouveau pour vous assurer que l'objet contenant foo se trouve à un emplacement approprié dans le mémore pour éviter les erreurs de page.

4

Veuillez ne pas optimiser ceci pour la vitesse. Il existe une différence sémantique importante entre les deux, et la valeur qu'elle apporte à votre code, avec les données à l'endroit le plus logique, vous fera gagner plus de temps que de réduire les performances d'exécution.

Plusieurs milliards d'itérations ne sont pas vraiment si importantes. Le processeur de mon ordinateur tourne à 2.2 Ghz. Si c'est dans le cache, le déréférencement va coûter peut-être un cycle supplémentaire, et donc 100billion boucles est d'environ 30 secondes d'exécution. Je doute que ça va me manquer.

3

Avez-vous envisagé une troisième option?

void bar() 
{ 
    foo_t myFoo = ::foo; // or this->foo 
    for(;;) 
    { 
     // do something with myFoo 
    } 
    ::foo = myFoo; 
} 

Dans ce cas, le compilateur est susceptible de mettre foo dans un registre, qui est sûr d'être encore plus rapide qu'un accès au cache.

+3

Les compilateurs ne sont pas si mal à assigner des registres. En fait, je ne connais plus aucun compilateur qui respecte le mot clé 'register', car ils sont tous convaincus qu'ils n'ont pas du tout besoin de l'indice. – MSalters

+1

Les compilateurs sont plus enclins à utiliser des registres pour des variables locales que des variables qui doivent avoir une adresse, telle qu'une variable globale (qui existe dans l'image exécutable) ou des valeurs explicitement déréférencées (telles que 'this-> foo') – SingleNegationElimination

3

Comme toujours, optez pour ce qui simplifie le code.

Si vous utilisez un global, alors le lecteur du code doit se demander pourquoi, et où d'autre est accédé cette variable. De combien de threads est-il accessible? Comment les accès de différents threads sont-ils synchronisés?

Si vous créez une variable locale visible seulement là où elle est nécessaire, ces questions disparaissent. En ce qui concerne la vitesse, la seule chose qui pourrait faire la différence est la localisation de la mémoire cache. Si la variable est accédée souvent, elle sera mise en cache dans les deux cas, mais si elle se trouve à côté d'autres objets récemment utilisés, elle pourra partager la même ligne de cache, laissant plus de place libre dans le cache pour les autres données .

Mais si le code mérite d'être optimisé, il vaut également la peine de le mesurer. Éviter les globales est l'option simple et propre. Si la performance est un problème, et que vos mesures indiquent que l'utilisation d'un global est plus rapide, passez à un global. Mais n'oubliez pas que vous changez également la sémantique de votre programme. Si vous avez plusieurs threads appelant la fonction, vous obtiendrez une condition de concurrence si vous utilisez un global, où il était sûr avant

+0

+1 pour "Si le code vaut la peine d'être optimisé, alors cela vaut aussi la peine de mesurer". Notez que certains processeurs ("basse performance") peuvent voir une différence de vitesse. Plus important encore, une charge relative avec un faible décalage sera probablement plus petite (en code) qu'une charge absolue; Je préfère généralement la version qui prend moins de place dans votre I-cache. –